寫了個腳本,用於從www.so.com 上查詢電話號碼的標記狀況,記錄下號碼所屬公司、標記類型、標記人數(若是存在)。以下圖紅框中的信息。主要使用python的beautifulsoup和selenium,還用到了雲打碼平臺(固定ip頻繁查詢後會被360要求輸入驗證碼,須要收費,1分錢1個碼)和百度OCR(360的查詢結果中,所屬公司是圖片形式,所以須要文字識別,天天50000張如下免費)。約4-8秒處理一個號碼,只能單進程(多進程啥的無心義,畢竟固定ip只有一個)。咱們用來處理9000個號碼,0點開始,大約10點結束。(python3.7.2)
雲打碼平臺:http://www.yundama.com/apidoc/YDM_SDK.html#demo
百度OCR:https://ai.baidu.com/sdk#ocrhtml
#-*- coding: UTF-8 -*- import sys import time import os import re import random import base64 #百度ocr模塊 from aip import AipOcr import datetime from ctypes import * from selenium import webdriver from pyquery import PyQuery as pq from bs4 import BeautifulSoup from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.action_chains import ActionChains default_encoding = 'utf-8' if sys.getdefaultencoding() != default_encoding: reload(sys) sys.setdefaultencoding(default_encoding)
# 調用雲打碼api,須要提供帳號id、api key、用戶名、密碼、識別類型、超時時間 # 注意指定雲打碼的dll文件路徑 YDMApi = windll.LoadLibrary('C:\\phone\\yundamaAPI-x64.dll') appId = 帳號id appKey = b'api key' username = b'用戶名' password = b'密碼' # 1004表示識別類型是4個字母或數字 codetype = 1004 timeout = 60 # 使用selenium chrome_options = webdriver.ChromeOptions() # 使用最高權限模式,並使用無圖形化界面模式 chrome_options.add_argument("--no-sandbox") chrome_options.add_argument('--headless') browser=webdriver.Chrome(chrome_options=chrome_options) # 窗口最大化,無圖形化模式下不用 browser.maximize_window() # 先打開360的查詢頁面 url='https://www.so.com/s?q=021' browser.get(url)
phone=號碼 # 中間有些sleep是爲了保證運行不出錯,能夠適當再調快 try: # 定位搜索框控件 sousuokuang=browser.find_element_by_id("keyword") time.sleep(0.5) # 搜索框清空 sousuokuang.clear() time.sleep(0.5) # 輸入號碼 sousuokuang.send_keys(phone) time.sleep(0.5) # 點擊搜索按鈕 browser.find_element_by_id("su").submit() time.sleep(random.uniform(0.5,1.3)) # 試圖定位驗證碼控件,若是定位失敗,進入except,若是定位成功(說明有驗證碼),則進入else yanzhengma=browser.find_element_by_id("img") except: # 沒有驗證碼,查詢成功,進入結果頁面 pass
else: # 若是有驗證碼,先點擊驗證碼圖片(圖片要先點擊一次纔會顯示驗證碼) time.sleep(0.3) ActionChains(browser).click(yanzhengma).perform() time.sleep(0.3) # 將驗證碼圖片保存到本地(號碼.png) yanzhengma.screenshot("c:\\phone\\%s.png" % phone) # 進行雲打碼(參考雲打碼文檔) result = c_char_p(b" ") filename = b'C:\\phone\\%s.png' % phone.encode('gbk') captchaId = YDMApi.YDM_EasyDecodeByPath(username, password, appId, appKey, filename, codetype, timeout, result) # 驗證碼數據解碼獲取 shuruma=(result.value).decode('gbk') # 定位驗證碼輸入框 shurukuang=browser.find_element_by_name("rcode") time.sleep(0.3) # 輸入驗證碼並點擊按鈕 shurukuang.send_keys(shuruma) time.sleep(0.3) browser.find_element_by_class_name("btn").submit() # 刪除驗證碼圖片 os.remove('c:\\phone\\%s.png' % phone) finally: # 讀取網頁內容並初始化 html=browser.page_source data=str(pq(html))
# 讀取須要ocr識別的圖片 def get_file_content(filePath): with open(filePath, 'rb') as fp: return fp.read() # 百度ocr須要有appid、apikey、祕鑰,調用函數 APP_ID = 'appid' API_KEY = 'API key' SECRET_KEY = '祕鑰' client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
# 頁面信息分析 soup = BeautifulSoup(data,"lxml") # 查找class名爲mohe-tips的div標籤 soup_div=soup.find('div',{'class':"mohe-tips"}) # 若是有mohe-tips if soup_div!=None: # 進一層查找span標籤 soup_spans=soup_div.findAll('span') # 若是有2個span標籤(有標記的號碼,正常狀況都是2個span) if len(soup_spans)==2: # 第1個span是號碼標記(騷擾電話、中介等,用state變量) state=soup_spans[0].getText().replace('\t','').replace('\n','').replace(' ','') # 第2個span是標記數,有的號碼可能沒有,就標爲0(用num變量) try: num=soup_spans[1].find('b').getText() except: num=0 else: pass # 若是進一層查找結果span標籤有1個(第一種特殊狀況) else: # 從新查找class名爲mohe-tips mh-ws-hy的div標籤 soup_div=soup.find('div',{'class':"mohe-tips mh-ws-hy"}) # 若是查找結果不爲空 if soup_div!=None: # 再進一層查找span標籤 soup_spans=soup_div.findAll('span') # 第1個span是號碼標記 state=soup_spans[0].getText().replace('\t','').replace('\n','').replace(' ','') # 第2個span是標記數,有的號碼可能沒有,就標爲0 try: num=soup_spans[1].find('b').getText() except: num=0 else: pass # 若是進一層查找結果爲空,則表示該號碼無標記 else: num=u'0' state=u'無' # 若是沒有mohe-tips標籤,第二種特殊狀況 else: # 直接查找class名爲mohe-tips mh-ws-hy的div標籤 soup_div=soup.find('div',{'class':"mohe-tips mh-ws-hy"}) # 若是查找結果不爲空 if soup_div!=None: # 進一層查找span標籤 soup_spans=soup_div.findAll('span') # 第1個span是號碼標記 state=soup_spans[0].getText().replace('\t','').replace('\n','').replace(' ','') # 第2個span是標記數,有的號碼可能沒有,就標爲0 try: num=soup_spans[1].find('b').getText() except: num=0 else: pass #若是進一層查找結果爲空,則表示該號碼無標記 else: num=u'0' state=u'無'
# 查找有無class名爲mh-hy-img的img控件 soup_img=soup.find('img',{'class':"mh-hy-img"}) try: # 嘗試把img控件的前綴'data:image/png;base64,'給刪除 img_src=soup_img.get("src").replace('data:image/png;base64,','') except: # 若是刪除失敗,就表示沒有所屬公司標記,就標記爲無(用company變量) company=u'無' else: # 若是有img控件,就把圖片保存到本地 f = open('c:\\phone\\%s.png' % phone,'wb') f.write(base64.b64decode(img_src)) f.close() # 讀取本地圖片,經過百度ocr識別,並把圖片刪除 image = get_file_content('c:\\phone\\%s.png' % phone) company=client.basicGeneral(image)['words_result'][0]['words'] os.remove('c:\\phone\\%s.png' % phone) # 在沒有mh-hy-img的img控件狀況下,有一種特殊狀況 if soup_img==None: # 查找有無class名爲mohe-tips mh-hy的strong控件 soup_strong=soup.find('strong',{'class':"mohe-tips mh-hy"}) try: # 進一步查找有無img控件 soup_img=soup_strong.find('img') img_src=soup_img.get("src").replace('data:image/png;base64,','') except: # 若是沒有img控件,公司標記爲無 company=u'無' else: # 有img控件,就把圖片識別處理並刪除 f = open('c:\\phone\\%s.png' % phone,'wb') f.write(base64.b64decode(img_src)) f.close() image = get_file_content('c:\\phone\\%s.png' % phone) company=client.basicGeneral(image)['words_result'][0]['words'] os.remove('c:\\phone\\%s.png' % phone)
print phone,state,num,company