Part2 滑块验证码识别及请求截获

  • 滑块验证码识别
  • 滑块偏移量
  • 滑块验证码的拖动
  • selenium截获请求
  • Token获取
  • 后续


滑块验证码识别

新版网站登录使用滑块验证码做登录认证。验证通过的首要条件为将滑块向右滑动到图片缺失口位置。简单点的滑块验证码只需通过这个条件就可以完成认证。

滑块偏移量

举个简单的例子,某网站滑块验证码右键保存图片如下图:

lua 滑块验证代码 滑块验证码检验_lua 滑块验证代码


上图左侧黄线框是滑块的初始位置,右侧深色框是缺失口位置,通过webdriver完成认证,首先需要计算缺失口位置偏移量(即横向像素点坐标)

通常,别的滑块验证码缺失口和滑块具备相同的颜色特征(就是缺失口暗了些)直接用OpenCV函数去找原图片和滑块图片的相似位置

im = cv2.cvtColor(cv2.imread(imgName), cv2.COLOR_BGR2GRAY)
tp = cv2.imread(tmpName, 0)
return cv2.minMaxLoc(cv2.matchTemplate(im, tp, cv2.TM_CCOEFF_NORMED))

im是滑块验证码图片(大图);tp是小滑块图片;返回一个四元组(包含最小概率、最小概率坐标、最大概率和最大概率坐标)

本例子中滑块和验证码图片是没有相似的,有个投机取巧的办法,将验证码缺失口PS抠出来如下:

lua 滑块验证代码 滑块验证码检验_python_02

所以我们直接用抠出的黑块做代码中tp就直接计算出向右偏移量~

滑块验证码的拖动

验证码拖动,我这里使用最简单的(因为网站并没有验证滑块拖动轨迹)

from selenium.webdriver import ActionChains
……
action = ActionChains(browser)
action.click_and_hold(slel)
action.move_by_offset(offval, 0)
action.release()
action.perform()
……

其中slel是用find_element_by_xpath或别的定位到的元素。

selenium截获请求

基于OAUTH认证的网站每次HTTP请求都需要在头部携带accessToken、secretKey等。
我们用了selenium来搞定滑块验证码,就没法直接requests请求解析JS获取secretKey和applyID,也不能直接login请求得到其返回accessToken。
所以截获请求是必要的。基于每次请求都需要携带头部,基本思路是首先触发一个例如获取当日数据请求的页面操作,截获请求日志,分析请求日志中携带的头部信息。

Token获取

以某网站为例,accessToken等HTTP头部的获取如下:

from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
caps = {'loggingPrefs': {'performance': 'ALL',
                         'server': 'ALL', 'browser': 'ALL', 'client': 'ALL'}}

options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_experimental_option('w3c', False)
options.add_experimental_option(
    'perfLoggingPrefs', {'enableNetwork': True})
browser = webdriver.Chrome(
    executable_path='./chromedriver', chrome_options=options, desired_capabilities=caps)

……
browser.get(url)
……
performaceLogs = browser.get_log('performance')
for item in performaceLogs:
    if 'https://XXXXXX' in item['message']:
        params = json.loads(item['message'])
        pprint(params)
        try:
            applyid = params['message']['params']['request']['headers']['applyID']
            secretk = params['message']['params']['request']['headers']['secretKey']
            actoken = params['message']['params']['request']['headers']['accessToken']
            break
        except:
            print('do nothing')

……
# 拿到key token后就可以退出了
browser.quit()

webdriver和Chrome版本比较高的话,

options.add_experimental_option('w3c', False)
options.add_experimental_option(
    'perfLoggingPrefs', {'enableNetwork': True})

一定要的!

https://stackoverflow.com/questions/55126252/python-selenium-perfloggingprefs-filtering

后续

后续就没有后续了,拿到token后就requests.get或requests.post吧~