Python使用selenium和百度AI開放平臺識別驗證碼自動登錄

本文內容

本文將介紹如何使用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,調用太快容易被盯上。

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章