最帅爬虫_滑动验证码解决案例

一、案例

校验豆瓣网验证码逻辑

  1. 创建webdriver.Chrome对象,并请求登录的url (driver对象提升为全局变量到main方法当中)
  2. 页面加载等待(20)秒
  3. 输入账号与(错误的密码),多次登录,使其弹出验证码
  4. 判断验证码是否弹出

在这里插入图片描述
5. 如果弹出就解决
5.1 点住滑块,悬浮
5.2 找到滑块距离,找规律在这里插入图片描述
5.3 点住滑块,移动滑块距离
5.4 点住滑块,到指定位置后,松开滑块
6. 判断登录后标签的状态是否改变,改变就代表登录成功

豆瓣网代码

import time

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains


def get_tracks(distance):
    '''
    模仿先加速后减速的过程
    :param distance: 移动的距离
    :return: 列表
    '''
    #当前速度
    v = 0

    #定义时间间隔
    t = 0.3
    tracks = []

    #当前距离
    current = 0

    #加速和减速的分割线
    mid = distance*3/5

    while current < distance:
        #定义加速度
        if current < mid:
            a = 2
        else:
            a = -3
        #移动了
        #定义初速度
        v0 = v
        s = v0*t+0.5*a*t*t
        current += s
        #保持移动的时候有效果
        #0.1个像素。像素不能是小数
        tracks.append(round(s))
        #设置当前速度
        v = v0+a*t
    return tracks


def sliding_code(driver):
    '''
    处理滑动验证码
    :param driver: 出现验证码的driver对象
    :return: True-->解决了
    '''
    print('开始处理滑动验证码!')
    # 发现验证码的部分就是一个iframe标签,切入frame
    driver.switch_to.frame(0)
    # 1、先找到滑块,鼠标点他,悬浮           滑块在xpath路径是滑块最外层
    slider = driver.find_element_by_xpath('//*[@id="tcaptcha_drag_button"]')
    # print(slider)

    # 2、先找到滑动距离---任何一个问题解决思路--通过测量得到220
    

    # ActionChains(driver):创建一个鼠标动作链---绑定driver(参数)上的
    # click_and_hold:点击并保持(参数表示点谁)
    # perform:悬浮

    # 3、点住他,水平移动(移动一定的距离)---距离到底是多少
    while True:
        ActionChains(driver).click_and_hold(on_element=slider).perform()
        # 滑动:先闪现100
        ActionChains(driver).move_by_offset(xoffset=100, yoffset=0).perform()
        # 剩余的123模拟加速后减速的过程
        tracks = get_tracks(123)
        # print(tracks)
        for s in tracks:
            ActionChains(driver).move_by_offset(xoffset=s, yoffset=0).perform()
        # 4、放开鼠标即可
        ActionChains(driver).release().perform()
        if driver.title != '登录豆瓣':
            break
        time.sleep(1)
        # 点击刷新图片
        driver.find_element_by_xpath('//*[@id="reload"]').click()
        time.sleep(2)
    # 网络恍惚了一下:滑动的太快了
    # 滑动要符合人的滑动习惯:先加速,后减速


def login():
    # chrome也是可以设置请求头
    options = webdriver.ChromeOptions()
    # 设置中文
    options.add_argument('lang=zh_CN.UTF-8')
    # 更换头部
    ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36'
    options.add_argument('user-agent="%s"' % ua)

    # 创建driver
    driver = webdriver.Chrome(chrome_options=options)
    # https://www.douban.com/people/214807783/
    # driver.get('https://www.douban.com/')
    driver.get('https://accounts.douban.com/passport/login')
    # 等待
    driver.implicitly_wait(20)
    # 1、点击使用密码登录
    # iframe:框架标签。---他也是一个完整的html
    # 便于html代码的管理和开发
    # 如果遇到iframe标签记得要切入进去在获取
    # 0:切入到第一个
    # driver.switch_to.frame(0)

    #  在页面当中找到  密码登录,并复制他的xpath路径
    driver.find_element_by_xpath('//*[@id="account"]/div[2]/div[2]/div/div[1]/ul[1]/li[2]').click()
    # 2、输入用户名和密码
    driver.find_element_by_xpath('//*[@id="username"]').send_keys('输入豆瓣网注册账号')
    driver.find_element_by_xpath('//*[@id="password"]').send_keys('输入豆瓣网登陆密码')
    # 3、点击登录
    driver.find_element_by_xpath('//*[@id="account"]/div[2]/div[2]/div/div[2]/div[1]/div[4]/a').click()
    time.sleep(4)

    print(driver.title)
    # 4、判断(是否出现滑动验证码)
    if driver.title == '登录豆瓣':
        #出现了验证码
        if sliding_code(driver):
            print('登录成功!')
    else:
        print('登录成功!')


if __name__ == '__main__':
    login()

注意技术点:
当在处理滑块移动的时候,由于是机器移动,速度会非常的快,会出现网络恍惚的情况在这里插入图片描述
因此,我们要写一个get_tracks方法,使计算机去模仿人的行为去滑动验证码。

平时我们滑动验证码的时候都是先快速拉取,即将要到指定位置的时候,速度会慢下来,直到滑动验证码块重合。

校验博客园验证码逻辑

  1. 创建webdriver.Chrome对象,并请求登录的url (driver对象提升为全局变量到main方法当中)
  2. 页面加载等待(20)秒
  3. 输入账号与(错误的密码),多次登录,使其弹出验证码
  4. 判断验证码是否弹出
  5. 如果弹出就解决
    5.1 点住滑块,悬浮
    5.2 找到滑块距离,找规律
    在这里插入图片描述
    因此,我们需要另一种处理方式,抠图
    在这里插入图片描述
    5.3 点住滑块,移动滑块距离
    5.4 点住滑块,到指定位置后,松开滑块
  6. 判断登录后标签的状态是否改变,改变就代表登录成功

博客园代码

import time
from PIL import Image
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
def isSimilar(image1,image2,x,y):
    '''
    比较两种图片在(x,y)坐标点位置的像素值是否一样
    :param image1:
    :param image2:
    :param x:
    :param y:
    :return: True->一样
    '''
    #获取图片在x,y位置的像素值
    pixel1 = image1.getpixel((x,y))
    pixel2 = image2.getpixel((x,y))
    # print(pixel1,pixel2)
    #计算要考虑误差的影响
    if abs(pixel1[0]-pixel2[0]) >= 20 and abs(pixel1[1]-pixel2[1])>=20 and abs(pixel1[2]-pixel2[2])>=20:
        print(pixel1,pixel2)#(49, 81, 63, 255) (80, 120, 100, 255)
        return False
    return True

def get_distance(image1,image2):
    '''
    通过对比两张一样的图片,获取不一样点的坐标
    :param image1:
    :param image2:
    :return: (x,y)
    '''
    #比较是比较每个坐标点的像素值
    #这两种图片是一样大小的
    for i in range(198):#x轴
        for j in range(154):
            #(i,j)--->图片上的每个坐标点
            if isSimilar(image1,image2,i,j)==False:
                return (i,j)
    return -1


def get_tracks(distance):
    '''
    模仿先加速后减速的过程
    :param distance: 移动的距离
    :return: 列表
    '''
    #当前速度
    v = 0
    #定义时间间隔
    t = 0.3
    tracks = []
    #当前距离
    current = 0
    #加速和减速的分割线
    mid = distance*3/5
    while current < distance:
        #定义加速度
        if current < mid:
            a = 2
        else:
            a = -3
        #移动了
        #定义初速度
        v0 = v
        s = v0*t+0.5*a*t*t
        current += s
        #保持移动的时候有效果
        #0.1个像素。像素不能是小数
        tracks.append(round(s))
        #设置当前速度
        v = v0+a*t
    return tracks

def login_verify(driver):
    '''
    解决验证码
    :param driver: 出现验证码的浏览器对象
    :return: True--->解决了验证码
    '''
    print('出现滑动验证码,开始处理滑动验证码!')
    #1、获取滑块
    slider = driver.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div[1]/div[2]/div[2]')
    # 最大化浏览器
    driver.maximize_window()
    yz_element = driver.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div[1]/div[1]/div/a/div[1]')
    # print(yz_element.location)#位置(左上角的坐标(x,y))
    # print(yz_element.size)#元素的大小

    top = yz_element.location['y']
    left = yz_element.location['x']
    right = left + yz_element.size['width']
    bottom = top + yz_element.size['height']
    while True:
        #2、计算移动的距离
        # (1)得到有缺口的图tu1和无缺口的图tu2
        # 截图保存有缺口的图片完整图片
        driver.save_screenshot('quan_quekou.png')
        image_qk = Image.open('quan_quekou.png')
        image1 = image_qk.crop((left+60,top+5,right,bottom))
        # image2.show()
        image1.save('imaeg1.png')
        #该canvas画布的属性:让其出现无缺的原图
        driver.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].style="display: block"')
        #截图
        driver.save_screenshot('quan_wuque.png')
        image2 = Image.open('quan_wuque.png').crop((left+60,top+5,right,bottom))
        image2.save('image2.png')
        #(2)比较两张图片的内容,获取距离
        #不一样的坐标点(x,y)
        location= get_distance(image1,image2)
        print(location)

        # 3、使用鼠标动作链进行点击并悬浮
        ActionChains(driver).click_and_hold(on_element=slider).perform()
        # 先移动一半
        ActionChains(driver).move_by_offset(xoffset=(location[0] + 58) / 2, yoffset=0).perform()
        # 4、鼠标拖动并保持悬浮移动--->先加速后减速的过程
        # 剩下的一半:做先加速后减速的过程
        tracks = get_tracks((location[0] + 58) / 2)
        for s in tracks:
            ActionChains(driver).move_by_offset(xoffset=s, yoffset=0).perform()
        # 5、释放鼠标--保持悬浮
        ActionChains(driver).release().perform()
        time.sleep(3)
        if '用户登录' not in driver.title:
            break
        #点击刷新验证码
        driver.find_element_by_xpath('/html/body/div[2]/div[2]/div[6]/div/div[2]/div/a[2]').click()
        time.sleep(1)
    return True


if __name__ == '__main__':
    driver = webdriver.Chrome()
    driver.get('https://account.cnblogs.com/signin?returnUrl=https%3A%2F%2Fwww.cnblogs.com%2F')
    #隐式等待
    driver.implicitly_wait(20)
    #输入用户名和密码
    driver.find_element_by_xpath('//*[@id="LoginName"]').send_keys('输入博客园账号')
    driver.find_element_by_xpath('//*[@id="Password"]').send_keys('输入博客园密码')
    #点击登录按钮
    driver.find_element_by_xpath('//*[@id="submitBtn"]').click()
    time.sleep(2)
    #判断是否登录成功,不成功就解决验证码
    if '学途_w' in driver.page_source:
        print('登录成功')
    else:
        if login_verify(driver):
            print('登录成功!')

注意技术点:
由于每次弹出的滑动验证码距离不同,因此我们需要算出滑块需要移动的距离,所以我们要选择抠图解析的方式。

首先我们通过driver对象去截图有缺口的验证码图,并且筛选出来滑块的大小,进行再次的裁剪。图1
然后我们将截取后的图1还原成无缺的原图。
在这里插入图片描述
最后我们要移动的距离就是 滑块的宽度+ 有缺口图1与无缺口图2的像素值。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值