如今网站的的普滑动验证码一已经逐渐替代普通的验证码
这无疑加大了爬虫的工作量
滑动验证码可以显著优化用户体验,这在互联网时代是非常重要的。

通过这次实践我也学到了很多
今天我们以bilibili为例讲解破解滑动验证码的过程

关于selenium的介绍及安装请看我另一篇博客:

python用selenium爬取百度搜索结果

需要用到的库

from PIL import ImageChops, Image
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import pyautogui
from time import sleep
import os

首先利用selenium自动填充用户名,密码并点击登录

driver = webdriver.Chrome()
ac = ActionChains(driver)
driver.implicitly_wait(3)
driver.get('https://passport.bilibili.com/login')
driver.maximize_window()
# 输入账号和密码
input1 = driver.find_element_by_xpath('//div//input[@id="login-username"]').send_keys('18888888888')
input2 = driver.find_element_by_xpath('//div//input[@id="login-passwd"]').send_keys('xxxxxxxx')
driver.find_element_by_xpath('//div/a[@class="btn btn-login"]').click()  # 点击登录按钮
sleep(1)

获取滑动验证码的背景图和带缺口的背景图

# 获取带缺口的图片
js = 'document.getElementsByClassName("geetest_canvas_slice")[0].className="geetest_canvas_slice geetest_absolute1"'
driver.execute_script(js)
img = driver.find_element_by_xpath('//*[@class="geetest_canvas_slice geetest_absolute1"]')
ac.context_click(img).perform()
pyautogui.typewrite(['enter', 'enter', 'enter'])

利用js修改class类命达到隐藏滑块就可以很轻松得到带缺口的背景图
在这里插入图片描述

# 获取完整的背景图片
js = 'document.getElementsByClassName("geetest_canvas_fullbg geetest_fade geetest_absolute")[0].style=""'
driver.execute_script(js)
img = driver.find_element_by_xpath('//*[@class="geetest_canvas_slice geetest_absolute1"]')
ac.context_click(img).perform()
pyautogui.typewrite(['enter', 'enter', 'enter'])

再通过删除style获取完整的背景图

在这里插入图片描述

# 恢复出带缺口的图片便于滑动时是观察(可选)
js = 'document.getElementsByClassName("geetest_canvas_slice")[0].className="geetest_canvas_slice geetest_absolute"'
driver.execute_script(js)

前面两部会删除滑块,不利于观察,加上这两句可以使原来的滑块恢复,即把类名改回原来的

对比两张图片找到缺口位置计算滑动多少像素

table = []
for i in range(256):
    if i < 50:
        table.append(0)
    else:
        table.append(1)


def compute_gap(img1, img2):
    """计算缺口偏移 这种方式成功率很高"""
    # 将图片修改为RGB模式
    img1 = img1.convert("RGB")
    img2 = img2.convert("RGB")

    # 计算差值
    diff = ImageChops.difference(img1, img2)

    # 灰度图
    diff = diff.convert("L")

    # 二值化
    diff = diff.point(table, '1')

    left = 42
    for w in range(left, diff.size[0]):
        lis = []
        for h in range(diff.size[1]):
            if diff.load()[w, h] == 1:
                lis.append(w)
            if len(lis) > 5:
                return w
# 从下载中获取两张图片
def get_images():
    bg = Image.open('C:/Users/yuaneuro/Downloads/下载.png')
    fullgb = Image.open('C:/Users/yuaneuro/Downloads/下载 (1).png')
    return bg, fullgb

最后编写主函数

def main():
    bg_img, fullbg_img = get_images()
    gap = compute_gap(fullbg_img, bg_img)
    print(gap)
    # 寻找滑块的元素
    slide = driver.find_element_by_xpath('//*[@class="geetest_slider_button"]')
    ac = ActionChains(driver)
    # 滑动操作(等待大佬更新滑动算法)
    ac.click_and_hold(slide).perform()
    ac.move_by_offset(gap - 10, 0.1).perform()  # 平行移动鼠标
    slide.click()
    ac.reset_actions()


if __name__ == '__main__':
    main()
    os.remove('C:/Users/yuaneuro/Downloads/下载.png')
    os.remove('C:/Users/yuaneuro/Downloads/下载 (1).png')

这里滑动验证码已经更新,暂未找到合适有效的滑动轨迹的方法,暂时用最原始的替代,后续找到可以用的滑动轨迹会跟新!

完整代码

此处内容需要评论回复后(审核通过)方可阅读。

最后修改:2022 年 01 月 27 日
如果觉得我的文章对你有用,请随意赞赏