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,调用太快容易被盯上。

参考

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