文章目錄
本文內容
本文將介紹如何使用selenium的webdriver來自動輸入賬戶、密碼,以及通過 百度通用文字識別 來識別驗證碼信息,輸入並識別結果並點擊登錄。
工具準備
本文使用的是 Python 3.6 語言
Python Packages
需要安裝的包有:
- selenium
- urllib
- json
- base64
# 安裝方式, e.g.
pip install selenium
瀏覽器驅動
本文使用 chrome driver, 點擊該鏈接下載一個最新的版本即可。如果想要更深入了結selenium webdriver, 推薦閱讀這篇文章 傳送門
準備登錄
第一步 用Chrome瀏覽器打開目標網站
- 首先將鼠標移到登錄框,如下圖所示,右鍵點擊檢查
- 這個時候會自動跳轉到 “用戶名” 這個網頁元素的位置,可以從標籤中找到該元素的標識符 id
第二步 調用selenium輸入賬戶密碼
- 接下來我們就可以用python打開一個Chrome Webdriver。注意要先將下載的driver放到一個指定的路徑,下面會用到該路徑。
from selenium import webdriver, common
import urllib
import json
import base64
import time
import ssl
ssl._create_default_https_context = ssl._create_unverified_context # 全局取消證書驗證
# 連接百度雲圖像識別接口
from urllib.request import urlopen
from urllib.request import Request
from urllib.error import URLError
from urllib.parse import urlencode
options = webdriver.ChromeOptions()
# 需要指定driver path,前往 http://npm.taobao.org/mirrors/chromedriver/ 下載對應版本號的chrome driver,加壓放到指定文件夾
# 版本查看方法請自行百度, 打開瀏覽器--右上角(自定義及控制)-- 幫助 -- 關於Chrome 點開即可看到
browser = webdriver.Chrome(executable_path=r'D:\Projects\Repo 3\chromedriver.exe', chrome_options=options)
- 運行上述代碼,會打開一個空白的瀏覽器,接下來我們可以調用get方法打開網站
URL = 'https://jg.sac.net.cn/login.action' # 登錄網站(證券業協會網站)
USERNAME = 'jiajia' # 賬戶
PASSWORD = '0419' # 密碼
browser.get(URL)
browser.find_element_by_id('j_username').send_keys(USERNAME) # 輸入賬戶
browser.find_element_by_id('j_password').send_keys(PASSWORD) # 輸入密碼
打開網址後,調用webdriver的一個非常方便的函數,find_element_by_id,這個函數可以根據元素的id找到網頁上對應的位置,同時模擬鼠標的動作,將該輸入框激活。上一步我們已經找到了用戶名的 id,同樣的方法可以找到密碼的id。然後再繼續調用 send_keys 函數,輸入賬戶、密碼。
第三步 獲取圖片驗證碼信息
- 首先我們要找到驗證碼圖片的所在位置,同樣的右鍵驗證碼位置,選擇檢查,自動跳轉到該元素的標籤。找到元素的 id = ‘validateImage’,獲取element對象。
# 獲取驗證碼圖片
img_obj = browser.find_element_by_id('validateImage') # 獲取圖片對象
img_url = img_obj.get_attribute('src') # 獲取驗證碼圖片下載地址
try:
data = urllib.request.urlopen(img_url).read() # 讀取圖片信息
except urllib.error.HTTPError as err:
print(err)
獲得對象後,調用該對象的 get_attribute函數,獲得驗證碼圖片的連接,再通過urllib打開連接讀取圖片二進制信息。
第四步 調用百度文字識別API
- 百度文字識別 參考該連接註冊百度賬戶,創建文字識別應用,最後獲取該應用的API_KEY, SECRET_KEY
- 百度提供了不同的識別模式,有通用識別、高精度識別、網絡圖片識別等,可以根據圖片的種類選擇不同模式測試,最後挑一個識別正確率高的就行。
- 下面是我參考了百度提供的一個demo,寫了三個函數分別用來獲取token,調用API,接收識別結果並返回
API_KEY = 'L6LytQamc5dZdjW8Qfd' # 參考
SECRET_KEY = 'cUDqjaxnTo1HoNS0NeCBLumvf'
ACCURATE_OCR = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic" # 高精度文字識別
GENERAL_OCR = r"https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic" # 通用文字識別
WEBIMAGE_OCR = r'https://aip.baidubce.com/rest/2.0/ocr/v1/webimage' # 網絡圖片文字識別,每天可免費調用500次
TOKEN_URL = 'https://aip.baidubce.com/oauth/2.0/token'
def fetch_token():
'''
獲取請求token
'''
params = {'grant_type': 'client_credentials',
'client_id': API_KEY,
'client_secret': SECRET_KEY}
post_data = urlencode(params).encode('utf-8')
req = Request(TOKEN_URL, post_data)
try:
f = urlopen(req, timeout=5)
result_str = f.read()
result_str = result_str.decode()
result = json.loads(result_str)
return result['access_token']
except URLError as err:
print(err)
return None
def post_request(url, data):
"""
調用遠程服務
"""
req = Request(url, data.encode('utf-8'))
try:
f = urlopen(req)
result_str = f.read()
result_str = result_str.decode()
result = json.loads(result_str)
return result
except URLError as err:
print(err)
return None
def guess_text(data):
'''
輸入圖片信息,返回識別結果
'''
# 獲取access token
token = fetch_token()
# 網絡圖片識別url
image_url = WEBIMAGE_OCR + "?access_token=" + token
# 調用文字識別服務
result = post_request(image_url, urlencode({'image': base64.b64encode(data)}))
text = result['words_result'][0]['words']
print(result)
return text
- 最後接着第三步的驗證碼信息讀取,調用 guess_text 函數來識別驗證碼信息。
text = guess_text(data) # 調用百度通用圖片識別
第五步 輸入驗證碼並點擊登錄
browser.find_element_by_id('textfield').send_keys(text) # 驗證碼輸入框
- 在輸入完驗證碼之後,需要點擊 登錄 按鈕,參照前面的方法,我們找到了該元素的標籤,- 但遺憾的是我們沒有找到該元素的id,這個時候我們可以通過另一個方法來獲取按鈕的位置 find_element_by_xpath,首先我們先在網頁上右鍵點擊元素標籤,複製 XPath
- 然後將複製的XPath作爲參數送入函數,再調用 click 方法模擬鼠標點擊的動作
# 通過目標元素查找,Chrome可以右鍵目標元素,然後copy xpath
browser.find_element_by_xpath(
'//*[@id="loginForm"]/table/tbody/tr/td/table/tbody/tr/td[2]/table/tbody/tr[3]/td/input[1]').click()
time.sleep(5)
try:
info = browser.find_element_by_id('alertInfo').text # 獲取報錯提示
if info == '驗證碼輸入有誤':
# 換一個驗證碼
browser.find_element_by_xpath(
'//*[@id="loginForm"]/table/tbody/tr/td/table/tbody/tr/td[2]/table/tbody/tr[2]/td/table/tbody/tr[5]/td[2]/a').click()
# 清除輸入框
browser.find_element_by_id('textfield').clear()
# 重試,刷新驗證碼
except common.exceptions.NoSuchElementException as err:
# 找不到說明驗證通過!!
time.sleep(1) # 休息一會繼續搞
- 上述代碼裏還有另一個功能,當驗證碼識別錯誤,我們點擊登錄之後,頁面會有報錯提示,後半部分代碼就是用來捕捉這一提示,然後用 clear 方法清除輸入框,重複之前的操作即可。
- 最好將登陸的動作封裝到一個函數裏,方便多次重複調用。
- 在測試的過程中發現百度的API如果調用的頻率太高的話,可能會報錯,所以我在幾個地方都加了 sleep,調用太快容易被盯上。