Python进阶爬虫滑动验证码最新解决

今天给大家带来的是滑动验证码的selenium破解之法,参考网络资源最后总结而来,废话不多直入主题。

解析过程

  • 首先获取目标网站的验证码图片,没有缺口和有缺口的图片
  • 对比两张图片的所有RBG像素点,得到不一样像素点的x值,即要移动的距离distance
  • 模拟人的行为习惯(先匀加速拖动后匀减速拖动),把拖动的总距离分成一段一段小的轨迹
  • 按照轨迹拖动,完成验证

案例过程

这里我使用的是博客园验证码,不同的网站具体解析过程有差异,具体网站具体分析,代码里面也有分析过程
解析过程都大同小异

# -*- coding:utf-8 -*-
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from PIL import Image
import time


def get_image(driver):
	# 获取验证码图片
    img = driver.find_element_by_class_name('geetest_slicebg')
    #     img = driver.find_element_by_class_name('geetest_canvas_fullbg')
    time.sleep(2)
    location = img.location
    size = img.size

    left = location['x']
    top = location['y']
    right = left + size['width']
    bottom = top + size['height']

    driver.save_screenshot('full_snap.png')
    page_snap_obj = Image.open('full_snap.png')
    #     page_snap_obj=get_snap(driver)
    image_obj = page_snap_obj.crop((left, top, right, bottom))
    return image_obj

def get_distance(image1,image2):
    '''
    拿到滑动验证码需要移动的距离
    :param image1:没有缺口的图片对象
    :param image2:带缺口的图片对象
    :return:需要移动的距离
    '''
    threshold = 60
    left = 57
    print(image1.size)
    for i in range(left, image1.size[0]):
        for j in range(image1.size[1]):
            rgb1 = image1.load()[i, j]
            rgb2 = image2.load()[i, j]
            res1 = abs(rgb1[0] - rgb2[0])
            res2 = abs(rgb1[1] - rgb2[1])
            res3 = abs(rgb1[2] - rgb2[2])
            if (res1 > threshold and res2 > threshold and res3 > threshold):
                return i - 4  # 经过测试,误差为大概为4
                #         print(i,res1,res2,res3)
    return i

def get_tracks(distance):
    '''
    拿到移动轨迹,模仿人的滑动行为,先匀加速后匀减速
    匀变速运动基本公式:
    ①v=v0+at
    ②s=v0t+½at²
    ③v²-v0²=2as

    :param distance: 需要移动的距离
    :return: 存放每0.3秒移动的距离
    '''
    #初速度
    v=0
    #单位时间为0.2s来统计轨迹,轨迹即0.2内的位移
    t=0.3
    #位移/轨迹列表,列表内的一个元素代表0.2s的位移
    tracks=[]
    #当前的位移
    current=0
    #到达mid值开始减速
    mid=distance*3/5

    while current < distance:
        if current < mid:
            # 加速度越小,单位时间的位移越小,模拟的轨迹就越多越详细
            a= 2
        else:
            a=-3

        #初速度
        v0=v
        #0.2秒时间内的位移
        s=v0*t+0.5*a*(t**2)
        #当前的位置
        current+=s
        #添加到轨迹列表
        tracks.append(round(s))

        #速度已经达到v,该速度作为下次的初速度
        v=v0+a*t
    return tracks


def crack(driver): #破解滑动认证
    time.sleep(5)
    #  1执行js获取没有缺口的图片
    driver.execute_script('document.querySelectorAll("canvas")[2].style="display: block;"')
    image1 = get_image(driver)

    # 2还原js获取有缺口的图片
    driver.execute_script('document.querySelectorAll("canvas")[2].style="display: none;"')
    image2 = get_image(driver)

    # 3、对比两种图片的像素点,找出位移
    distance = get_distance(image1, image2)

    # 4、模拟人的行为习惯,根据总位移得到行为轨迹
    tracks = get_tracks(distance)
    tracks.append(distance - sum(tracks))
    print(tracks)
    print(distance, sum(tracks))

    # 5、按照行动轨迹先正向滑动,后反滑动
    button = driver.find_element_by_class_name('geetest_slider_button')
    ActionChains(driver).click_and_hold(button).perform()

    # 正常人类总是自信满满地开始正向滑动,自信地表现是疯狂加速
    for track in tracks:
        ActionChains(driver).move_by_offset(xoffset=track, yoffset=0).perform()

    # 结果傻逼了,正常的人类停顿了一下,回过神来发现,卧槽,滑过了,然后开始反向滑动
    time.sleep(0.5)

    # 小范围震荡一下,进一步迷惑极验后台,这一步可以极大地提高成功率
    ActionChains(driver).move_by_offset(xoffset=-3, yoffset=0).perform()
    ActionChains(driver).move_by_offset(xoffset=3, yoffset=0).perform()

    # 成功后,骚包人类总喜欢默默地欣赏一下自己拼图的成果,然后恋恋不舍地松开那只脏手
    time.sleep(0.5)
    ActionChains(driver).release().perform()

def login_cnblogs(username,password):
    driver = webdriver.Chrome()
    try:
        # 1、输入账号密码回车
        driver.implicitly_wait(3)
        driver.get('https://passport.cnblogs.com/user/signin')

        input_username = driver.find_element_by_id('LoginName')
        input_pwd = driver.find_element_by_id('Password')
        signin = driver.find_element_by_id('submitBtn')

        input_username.send_keys('12345')
        input_pwd.send_keys('12345')
        signin.click()

        # 2、破解滑动认证
        crack(driver)

        time.sleep(2)  # 睡时间,确定登录成功
    finally:
        driver.close()

if __name__ == '__main__':
    login_cnblogs(username='linhaifeng',password='xxxx')

你可能感兴趣的:(爬虫)