爬虫入门经典(十九) | 难度提升,破解极验验证码

不温卜火 等级 397 0 0

  大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己所犯的错误希望能够帮助到很多和自己一样处于起步阶段的萌新。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!暂时只在csdn这一个平台进行更新,博客主页:https://buwenbuhuo.blog.csdn.net/爬虫入门经典(十九) | 难度提升,破解极验验证码

PS:由于现在越来越多的人未经本人同意直接爬取博主本人文章,博主在此特别声明:未经本人允许,禁止转载!!!

目录


爬虫入门经典(十九) | 难度提升,破解极验验证码


推荐

爬虫入门经典(十九) | 难度提升,破解极验验证码
  ♥各位如果想要交流的话,可以加下QQ交流群:974178910,里面有各种你想要的学习资料。♥

  ♥欢迎大家关注公众号【不温卜火】,关注公众号即可以提前阅读又可以获取各种干货哦,同时公众号每满1024及1024倍数则会抽奖赠送机械键盘一份+IT书籍1份哟~♥
爬虫入门经典(十九) | 难度提升,破解极验验证码
上两篇文章中学长分别破解了文字验证码和简单的滑动验证码,接下来咱们升级破解,破解难度更大的滑动验证码,目前很多企业的用的第三方开发好的验证码,比如极验。
爬虫入门经典(十九) | 难度提升,破解极验验证码
在此,博主给出极验的滑动验证网站进行测试。网址如下:
https://captcha1.scrape.center/
爬虫入门经典(十九) | 难度提升,破解极验验证码
我们打开这个网址点击登录,可以发现验证码要比豆瓣的验证码复杂多了。
爬虫入门经典(十九) | 难度提升,破解极验验证码

一、验证码分析

爬虫入门经典(十九) | 难度提升,破解极验验证码
滑动验证码可以通过分析js,这个难度过大。我们这里还是使用selenium模拟滑动解决。

需要解决两个问题:
第1是滑动的距离。
第2是模拟滑动。

模拟滑动已经可以解决,现在就需要解决滑动距离。

首先,我们先来获取完整图片,先找到验证码的位置,然后取消选取display和opacity即可得到完整的图片
爬虫入门经典(十九) | 难度提升,破解极验验证码
或者这none改成block也可以显示完整图片
爬虫入门经典(十九) | 难度提升,破解极验验证码
下面我们来对不一下这两张图片
爬虫入门经典(十九) | 难度提升,破解极验验证码
爬虫入门经典(十九) | 难度提升,破解极验验证码
其实除了这种方案之外,往上是有其他方案的,比如通过opencv找到缺口位置。
爬虫入门经典(十九) | 难度提升,破解极验验证码

🆗既然这样,那么接下来思路就很清晰了

  • (1)访问网页,保存全屏为图片。
  • (2)截图验证码
  • (3)通过js修改css样式,显示完整图
  • (4)截图验证码
  • (5)对比找到缺口位置来判断出位移
  • (6)移动

注意:截图验证码的时候需要获取位置,这个时候需要本地屏幕设置100%和浏览器设置100%不缩放。
爬虫入门经典(十九) | 难度提升,破解极验验证码
爬虫入门经典(十九) | 难度提升,破解极验验证码

二、代码的逐步实现

实现的集体过程

  • (1)访问网页,保存全屏为图片。
  • (2)截图验证码
  • (3)通过js修改css样式,显示完整图
  • (4)截图验证码
  • (5)对比找到缺口位置来判断出位移
  • (6)移动

2.1 访问网页,使其能够出现验证码

爬虫入门经典(十九) | 难度提升,破解极验验证码

    1. 代码如下
from selenium import webdriver
from PIL import Image
import time

url = "https://captcha1.scrape.center/"
driver = webdriver.Chrome("./chromedriver/chromedriver.exe")
driver.maximize_window()
driver.get(url)

driver.find_elements_by_class_name("el-input__inner")[0].send_keys("老王")
driver.find_elements_by_class_name("el-input__inner")[1].send_keys("123456")
driver.find_element_by_class_name("el-button").click()

time.sleep(5)
driver.quit() 
    1. 效果如下

爬虫入门经典(十九) | 难度提升,破解极验验证码

2.2 截取验证码

1. 分析

爬虫入门经典(十九) | 难度提升,破解极验验证码

    1. 确定图片位置
      爬虫入门经典(十九) | 难度提升,破解极验验证码
    1. 截取验证码

我们的截图,其实就是确定左上和右下的位置

2. 代码实现

    1. 先截取整个屏幕
#保存屏幕
driver.save_screenshot("./screen1.png")
time.sleep(2) 
    1. 截取验证码
#获取验证码的定位
img = driver.find_element_by_class_name("geetest_canvas_img")
#print(img1.location,img1.size)#{'x': 590, 'y': 239} {'height': 160, 'width': 260}
#坐标(左上角,右下角)
rectangle = (img.location["x"],img.location["y"],img.location["x"]+img.size["width"],img.location["y"]+img.size["height"])
print(rectangle)
#打开图片
img_obj = Image.open("./screen1.png")
#截图
img_new = img_obj.crop(rectangle)
#保存
img_new.save("./img1.png")

driver.quit() 

3. 最终结果(截图)

爬虫入门经典(十九) | 难度提升,破解极验验证码

2.3 截取完整图片

1. 执行js,显示完整图片

代码如下

document.getElementsByClassName("geetest_canvas_fullbg")[0].style = "display:block" 

效果图如下
爬虫入门经典(十九) | 难度提升,破解极验验证码

2. 代码实现

#执行js,显示完整图片
driver.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].style = "display:block"')
time.sleep(2)

#保存屏幕
driver.save_screenshot("./screen2.png")
time.sleep(2)

#截图
img_obj = Image.open("./screen2.png")
img_new = img_obj.crop(rectangle)
img_new.save("./img2.png") 

爬虫入门经典(十九) | 难度提升,破解极验验证码

2.4 验证码缺口和完整截图

此部分,为上述源码的整合

from selenium import webdriver
from PIL import Image
import time

url = "https://captcha1.scrape.center/"
driver = webdriver.Chrome("./chromedriver/chromedriver.exe")
driver.maximize_window()
driver.get(url)

driver.find_elements_by_class_name("el-input__inner")[0].send_keys("老王")
driver.find_elements_by_class_name("el-input__inner")[1].send_keys("123456")
driver.find_element_by_class_name("el-button").click()

time.sleep(5)

#保存屏幕
driver.save_screenshot("./screen1.png")

#获取验证码的定位
img = driver.find_element_by_class_name("geetest_canvas_img")
#print(img1.location,img1.size)#{'x': 590, 'y': 239} {'height': 160, 'width': 260}
#坐标(左上角,右下角)
rectangle = (img.location["x"],img.location["y"],img.location["x"]+img.size["width"],img.location["y"]+img.size["height"])
print(rectangle)
#打开图片
img_obj = Image.open("./screen1.png")
#截图
img_new = img_obj.crop(rectangle)
#保存
img_new.save("./img1.png")

#执行js,显示完整图片
driver.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].style = "display:block"')
time.sleep(2)

#保存屏幕
driver.save_screenshot("./screen2.png")
time.sleep(2)

#截图
img_obj = Image.open("./screen2.png")
img_new = img_obj.crop(rectangle)
img_new.save("./img2.png")

driver.quit() 

2.5 对比缺口验证

爬虫入门经典(十九) | 难度提升,破解极验验证码
接下来,对比两张图的不同,从而找到缺口的位置,就是我们要移动的位置。爬虫入门经典(十九) | 难度提升,破解极验验证码
这里发现滑块的定位是固定的,距左面大概55左右。这两个图在截图的时候应该分别向右移动55像素,比对找到缺口后再加上原来的55就是要移动的位移。

分析完毕,下面我们只需修改下列一行代码

#坐标(左上角,右下角)
rectangle = (img.location["x"]+55,img.location["y"],img.location["x"]+img.size["width"],img.location["y"]+img.size["height"]) 

爬虫入门经典(十九) | 难度提升,破解极验验证码

接着要对比像素,找到二者不同的像素,这里需要注意,极验图上还加入了阴影,增加了对比难度。

爬虫入门经典(十九) | 难度提升,破解极验验证码
经过多张图的对比,发现差值临界点30左右可以既去掉灰色阴影的干扰块又能识别出缺口位置
通过代码,对比像素的不同

#对比像素的不同

from PIL import Image
img1 = Image.open("./img1.png")
img2 = Image.open("./img2.png")

for i in range(img1.width):
    for j in range(img1.height):
        if img1.getpixel((i,j))!=img2.getpixel((i,j)):
            print(i,j,img1.getpixel((i,j)),img2.getpixel((i,j))) 

爬虫入门经典(十九) | 难度提升,破解极验验证码

以上面的图为例,x就是31,加上原来的55,就是86,所以确定了滑块的位移就是86左右。

2.6 滑动滑块(此部分以后有时间会修复,在此只给出代码)

爬虫入门经典(十九) | 难度提升,破解极验验证码
此部分直接使用上一篇博文的匀加速匀减速代码

def get_tracks(distance, rate=0.5, t=0.2, v=0):
    """
    将distance分割成小段的距离
    :param distance: 总距离
    :param rate: 加速减速的临界比例
    :param a1: 加速度
    :param a2: 减速度
    :param t: 单位时间
    :param t: 初始速度
    :return: 小段的距离集合
    """
    tracks = []
    # 加速减速的临界值
    mid = rate * distance
    # 当前位移
    s = 0
    # 循环
    while s < distance:
        # 初始速度
        v0 = v
        if s < mid:
            a = 3
        else:
            a = -2
        # 计算当前t时间段走的距离
        s0 = v0 * t + 0.5 * a * t * t
        # 计算当前速度
        v = v0 + a * t
        # 四舍五入距离,因为像素没有小数
        tracks.append(round(s0))
        # 计算当前距离
        s += s0

    return tracks 

接下来就完成滑动,发现如下图所示,每次滑动都会超过大概5个像素左右,圆形的滑块与上面方形的滑块有像素偏差,需要在滑动距离上减去这个5个像素就可以解决。
爬虫入门经典(十九) | 难度提升,破解极验验证码
爬虫入门经典(十九) | 难度提升,破解极验验证码

三、完整代码

爬虫入门经典(十九) | 难度提升,破解极验验证码

# encoding: utf-8
'''
  @author 李华鑫
  @create 2020-10-11 16:03
  Mycsdn:https://buwenbuhuo.blog.csdn.net/
  @contact: 459804692@qq.com
  @software: Pycharm
  @file: 验证码升级2.py
  @Version:1.0

'''
"""
大概的思路就出来了:
(1)访问网页,保存全屏为图片。
(2)截图验证码
(3)通过js修改css样式,显示完整图
(4)截图验证码
(5)对比找到缺口位置来判断出位移
(6)移动
"""

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from PIL import Image
import time

#网址
url = "https://captcha1.scrape.center/"
#截屏的图片路径
screen1 = "./screen1.png"
screen2 = "./screen2.png"
#滑动验证的图片路径
img1 = "./img1.png"
img2 = "./img2.png"
#截图的偏移量
distance_offset = 55
distance_offset2 = 5
#位移
distance = 0

def get_tracks(distance, rate=0.5, t=0.2, v=0):
    """
    将distance分割成小段的距离
    :param distance: 总距离
    :param rate: 加速减速的临界比例
    :param a1: 加速度
    :param a2: 减速度
    :param t: 单位时间
    :param t: 初始速度
    :return: 小段的距离集合
    """
    tracks = []
    # 加速减速的临界值
    mid = rate * distance
    # 当前位移
    s = 0
    # 循环
    while s < distance:
        # 初始速度
        v0 = v
        if s < mid:
            a = 3
        else:
            a = -2
        # 计算当前t时间段走的距离
        s0 = v0 * t + 0.5 * a * t * t
        # 计算当前速度
        v = v0 + a * t
        # 四舍五入距离,因为像素没有小数
        tracks.append(round(s0))
        # 计算当前距离
        s += s0

    return tracks

def save_img(driver):
    """保存图片"""

    time.sleep(2)
    #保存屏幕
    driver.save_screenshot(screen1)
    #获取验证码的定位
    img = driver.find_element_by_class_name("geetest_canvas_img")
    #截图的区域
    rectangle = (img.location["x"]+distance_offset,img.location["y"],img.location["x"]+img.size["width"],img.location["y"]+img.size["height"])
    #打开图片
    img_obj = Image.open(screen1)
    #截图
    img_new = img_obj.crop(rectangle)
    #保存
    img_new.save(img1)

    #执行js,显示完整图片
    driver.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].style = "display:block"')
    time.sleep(2)
    #保存屏幕
    driver.save_screenshot(screen2)
    #执行js,隐藏完整图片
    driver.execute_script('document.getElementsByClassName("geetest_canvas_fullbg")[0].style = "display:none"')
    time.sleep(2)

    #截图
    img_obj = Image.open(screen2)
    img_new = img_obj.crop(rectangle)
    img_new.save(img2)

def discern_distance():
    """识别距离"""
    global distance

    #打开图像,得到图像对象
    img1_obj = Image.open(img1)
    img2_obj = Image.open(img2)
    #循环获取像素点
    for i in range(img1_obj.width):
        for j in range(img1_obj.height):
            #获取像素点
            p1 = img1_obj.getpixel((i, j))
            p2= img2_obj.getpixel((i, j))
            #比较
            if abs(p1[0]-p2[0])>30 and  abs(p1[1]-p2[1])>30 and abs(p1[2]-p2[2])>30:
                #计算位移
                distance = distance_offset+i-distance_offset2
                return

def slide(driver):
    """滑动"""
    # 找到滑块
    block = driver.find_element_by_class_name('geetest_slider_button')
    # 循环
    while True:
        print("distance:",distance)
        # 摁下滑块
        ActionChains(driver).click_and_hold(block).perform()
        # 移动
        ActionChains(driver).move_by_offset(distance*0.8, 0).perform()
        # 获取位移
        tracks = get_tracks(distance*0.2)
        # 循环
        for track in tracks:
            # 移动
            ActionChains(driver).move_by_offset(track, 0).perform()
        # 释放
        ActionChains(driver).release().perform()
        # 停一下
        time.sleep(5)
        # 判断
        if driver.current_url == url:
            print("失败...再来一次...")
            # 单击刷新按钮刷新
            driver.execute_script('document.getElementsByClassName("geetest_refresh_1")[0].click()')
            # 停一下
            time.sleep(2)
            #截图
            save_img(driver)
            #识别
            discern_distance()
        else:
            print("成功")
            break

def main():
    """主程序"""

    #开始访问网址
    driver = webdriver.Chrome("./chromedriver/chromedriver.exe")
    driver.maximize_window()
    driver.get(url)

    #找到用户名、密码、单击登录   弹出极验
    driver.find_elements_by_class_name("el-input__inner")[0].send_keys("admin")
    driver.find_elements_by_class_name("el-input__inner")[1].send_keys("admin")
    driver.find_element_by_class_name("el-button").click()

    time.sleep(5)

    #保存图片
    save_img(driver)
    #识别位移
    discern_distance()
    #滑动
    slide(driver)
    #退出
    driver.quit()

if __name__ == '__main__':
    main() 

四、最终运行结果

爬虫入门经典(十九) | 难度提升,破解极验验证码
爬虫入门经典(十九) | 难度提升,破解极验验证码

美好的日子总是短暂的,虽然还想继续与大家畅谈,但是本篇博文到此已经结束了,如果还嫌不够过瘾,不用担心,我们下篇见!


爬虫入门经典(十九) | 难度提升,破解极验验证码

  好书不厌读百回,熟读课思子自知。而我想要成为全场最靓的仔,就必须坚持通过学习来获取更多知识,用知识改变命运,用博客见证成长,用行动证明我在努力。
  如果我的博客对你有帮助、如果你喜欢我的博客内容,请“点赞” “评论”“收藏”一键三连哦!听说点赞的人运气不会太差,每一天都会元气满满呦!如果实在要白嫖的话,那祝你开心每一天,欢迎常来我博客看看。
  码字不易,大家的支持就是我坚持下去的动力。点赞后不要忘了关注我哦!

爬虫入门经典(十九) | 难度提升,破解极验验证码
爬虫入门经典(十九) | 难度提升,破解极验验证码

本文转自 https://buwenbuhuo.blog.csdn.net/article/details/109182895,如有侵权,请联系删除。

收藏
评论区

相关推荐

爬虫入门经典(十) | 一文带你快速爬取网易云音乐
大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己所犯的错误希望能够帮助到很多和自己一样处于起步阶段的萌新。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!暂时只在csdn这一个平台进行
爬虫入门经典(十四) | 使用selenium尝试爬取豆瓣图书
大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己所犯的错误希望能够帮助到很多和自己一样处于起步阶段的萌新。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!暂时只在csdn这一个平台进行
爬虫入门经典(十五) | 邪恶想法之爬取百度妹子图
大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己所犯的错误希望能够帮助到很多和自己一样处于起步阶段的萌新。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!暂时只在csdn这一个平台进行
爬虫入门经典(十七) | 图形验证码识别
大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己所犯的错误希望能够帮助到很多和自己一样处于起步阶段的萌新。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!暂时只在csdn这一个平台进行
爬虫入门经典(十八) | 滑动验证码识别
大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己所犯的错误希望能够帮助到很多和自己一样处于起步阶段的萌新。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!暂时只在csdn这一个平台进行
爬虫入门经典(十九) | 难度提升,破解极验验证码
大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己所犯的错误希望能够帮助到很多和自己一样处于起步阶段的萌新。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!暂时只在csdn这一个平台进行
爬虫入门经典(二十三) | fiddler抓包爬取QQ音乐
大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己所犯的错误希望能够帮助到很多和自己一样处于起步阶段的萌新。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!暂时只在csdn这一个平台进行
爬虫入门经典(二十四) | 爬取当当网图书信息并进行数据清洗
大家好,我是不温卜火,是一名计算机学院大数据专业大三的学生,昵称来源于成语—不温不火,本意是希望自己性情温和。作为一名互联网行业的小白,博主写博客一方面是为了记录自己的学习过程,另一方面是总结自己所犯的错误希望能够帮助到很多和自己一样处于起步阶段的萌新。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!暂时只在csdn这一个平台进行
用Python实现批量高效文件处理 解放你的双手
1.批量修改文件后缀名有时候会有大量修改文件名的需求,比如修改文件后缀、文件名加前缀等,如果手动修改,效率极低,这时候可以使用Python来批量修改:pythonimport osdef file_rename(): path input("请输入你需要修改的目录(格式如'F:\\test'):") old_suffix inp
分享一堆有用的软件工具
今天推荐一堆有用的软件工具,有实用 App ,在线网站,每一个都是特别好用,让你心动不已。所有 App 下载方法文章末尾提供。_1_ 一键测速一键测速是华为出品的网络测速软件,颜值极高;软件目前仅支持安卓版本。它完全免费,整个软件简约唯美,非常干净,颜值极高,让你拥有出色的视觉体验。它支持测试网速功能,也支持网络诊断功能;其中测试网
Django+Vue开发生鲜电商平台之7.用户登录和注册功能
@toc 聪明是智慧者的天敌,傻瓜用嘴讲话,聪明的人用脑袋讲话,智慧的人用心讲话。所以永远记住,不要把自己当成最聪明的,最聪明的人相信总有别人比自己更聪明。 ——马云Github和Gitee代码同步更新:;。 一、DRF的token基本使用 1.DRF的token登录原理基于DRF的前后端分离登录与单独使用Django登录的原理不同,
别再问我Python打包成exe了!(终极版)
大家好,我是小五🐶上次这篇文章中,评论区有好几条留言都是关心如何将python脚本打包成10多M的?那今天小五就给大家全面总结一下:Python如何打包成exe,以及如何打得足够小。标准打包目前比较常见的打包exe方法都是通过Pyinstaller来实现的,本文也将使用这种常规方法。如果对这块已经很熟悉的小伙伴,可以直接下滑到本文下半部分。 为什么要打包?众
人工智能数学基础5:单调有界定理
1\. 单调性对任一数列xn,如果从某一项xk开始,满足: 则称数列(从第k项开始)是单调递增的。特别地,如果上式全部取小于号,则称数列是严格单调递增的。 同样地,如果从某一项k开始,满足: 则称数列(从第k项开始)是单调递减的。特别地,如果上式全部取大于号,则称数列是严格单调递减的。 单调递增数列和单调递减数列统称单调数列。 2\. 有界性
人工智能数学基础7:极限、极限运算、ε-δ语言、ε-N语言、级数和函数连续性
一、极限的定义及四则运算1. 极限:某一个函数中的某一个变量,此变量在变大(或者变小)的永远变化的过程中,逐渐向某一个确定的数值A不断地逼近而“永远不能够重合到A”(“永远不能够等于A,但是取等于A‘已经足够取得高精度计算结果)的过程中,此变量的变化,被人为规定为“永远靠近而不停止”、其有一个“不断地极为靠近A点的趋势”。极限是一种“变化状态”的描述。此变
plotnine: Python版的ggplot2作图库
R语言的ggplot2绘图能力超强,python虽有matplotlib,但是语法臃肿,使用复杂,入门极难,seaborn的出现稍微改善了matplotlib代码量问题,但是定制化程度依然需要借助matplotlib,使用难度依然很大。 而且咱们经管专业学编程语言,一直有一个经久不衰的问题\“学数据分析,到底选择R还是Python”。通过plotnine这