专栏首页Python中文社区高阶爬虫实战:破解极验滑动验证码

高阶爬虫实战:破解极验滑动验证码

今天给大家带来的是极验验证码的selenium破解之法,是不是有点小激动呢,小伙伴们等不及了,让我们赶紧直入主题吧。

虎X网注册

这次我们是拿虎X开刀,注册账号的时候需要滑动图片到缺口位置,这种验证码我们现在也经常遇到,这个就不用详细介绍了吧

针对这种验证码我们首先确定了使用selenium模拟滑动破解方式,selenium鼠标移动点击拖动都比较简单,那么问题就在于拖动多少距离,眼睛看起来很直观,但是程序怎么获取呢?利用图像识别......,额,这个只能想想了吧。不如看看网页源码或者请求信息,看看有没有有效的信息。

查看网页信息

鼠标右键点击到图片上,查看元素

这一瞬间的图片,还好我二十几年的麒麟臂没白练,我们看看元素查看到的都是什么东西

这看起来有点奇怪哦,有个图片链接,还有位置信息,而且还那么多,先把图片链接拷贝到浏览器里访问下看看

WTF,这是什么鬼?注意到那个像猪尾巴一样的6了吗?还有那个小箭头,跟上面完整图片对比一下,发现把箭头挪动到小6旁边,猪尾巴就成功了。当然你仔细观察的话,还有其他的比如文字也是类似。那么我们可以确认这张图片应该是被打乱的,如果我们可以把它拼起来,是不是就离计算缺口位置比较近了。现在我们应该要注意到元素查看里后面的位置信息了,那么多,看起来应该跟这个打乱顺序有点关系吧。我们来确认一下。我的想法是这样子的,既然这个位置和拼图有关,而且再看我们上面麒麟臂截的图,我再标记一下

我们点击查看元素的时候,浏览器会帮我们突出显示一下,本来我是在图片上点击查看的,按照我的想法,它不是应该整张图片突出显示一下吗?看起来好像不是这么回事,只有那么一小部分,而且上面还有元素信息,宽高类名,再回去看看图3,位置坐标里,前面应该是x轴,后面是y轴,y轴只有58和0,再根据图2一看,图片分为上下两部分,再数一下div的数量,26块,每一块宽10x高58。按照这个来算的话,那么整个图片的宽就是260,高116,用截图工具去拉一下图片的宽高,基本吻合

接下来就是确定怎么拼了。这里很抱歉的告诉大家,猪没了,等我写到这里再去查看网页的时候,图片已经刷新了。所以接下来的截图可能不一样,在这里提前跟大家说明一下。反正就是找特征点嘛,每个图片应该都有的。先随便找一个特征点,查看元素,看它定位到那个div元素那里,然后再看看后面的位置。基本就是这样,所以我们找图片既然和位置有关,那么我们最好选一些位置明显的地方,比如中间,或者两边。

这个差不多算中间位置了吧,查那么一点点无所谓了

我去,这......跟我想的不太一样呀,再找两张看看,代表性及其强烈的

为了防止有人说我水字数,另外两个角就不截图了。到这一步可能有人纳闷了,为啥?你刚才说图片宽度260,为什么坐标里出现了289这样的坐标,这不就是超标了吗?一开始我也有这样的疑惑,可能我们看到图片比实际的小,也许人家在图片外面还留了边框呢,我一开始是这么想的。但是这个坐标是前面url里面的图片坐标,然后我就去看了一下图4

这个图片尽然比较大,坐标问题有答案了,但是这个跟260有什么关系呢?打乱的图片比较大,拼好的小,那它是怎么拼的呢?幸好我们看到了一个比较有用信息

看到这个-1px了吗?它成功引起了我的注意,因为按照我的想法,如果是从拼图里拿出一部分拼成一个完成图片的话,那么最左边拿出来的图片,应该是从(0,0),(0,58),但是我们看到的是(1,0),(1,58),y值还是比较符合我们的预期的,第一部分从0开始,高58,第二部分从58开始。但是x值有点问题,按照1作为起点,那第二个应该是11,因为宽度是10,这是确定的,我们找找看

是13,难道每一小块前面都多余了1个像素?按照这种的话也应该是12呀,按照这种方式我们继续找一找剩下的,通过分析我们发现每个小块+12作为下一个小块的起点。这样的话左右各去掉一个像素,宽度不就是10了吗?而且每个小块是12,26个是312,跟我们看到的拼图大小差不多,说明我们分析的是正确的。按照元素里提供的坐标,取宽度为10的大小即可。接下来分析一下这些坐标的意义。

坐标分析

分析一下我们图9到图12的截图,首先说图9,我本来觉得它x、y应该是0,就算不是0,也应该是各位数字吧,结果的y是58,这个算到下半截图片区域了,x是157,跑中场去了。图11呢,你的x应该在300左右,y应该100以上吧,结果y是0,到上半段,x是205,在中场偏后,离守门员还远呢。这是怎么肥事?不过我们发现了,图9在元素里是第一个,图11在元素里是最后一个,再结合坐标前面的y值全是58,后面的y值全是0,符合我们上半段下半段颠倒的想法了,然后你再分别查看图9右边/图11左边的元素就会发现,和元素里面div的顺序一样。到这里就差不多了。

总结一下:最终的图片就是把拼图,即图4,按照x=157、y=58、w=10、h=58截取出来,放在上半部分第一个位置,x=145、y=58、w=10、h=58截取出来放在上半部分第二个位置,紧挨着第一个,以此类推,拼成一张整图。

这个就是我拼出来的,恩,很好,很不错嘛小伙子。不过好像哪里不对,缺口嘞。仔细看看网页元素

原来一个是fullbg,一个是cutbg,这个名字就很有寓意嘛,那就好了,再把cutbg拼一下看看

这回就对上了。现在的问题就变成怎么计算缺口位置了

缺口位置

我觉得可能会有计算两张图片不同位置的方式吧,度娘来一发,然后获取了python实战===用python对比两张图片的不同,然后发现了ImageChops.difference这个接口,结果你们知道的,不准确,为啥捏?仔细看拼好的两张图,除了缺口还有其他地方不一样呀。看到图16缺口后面那个阴影没,让我的心里蒙上了一层阴影,再观察其他的图片,基本都有类似的,这可怎么办?这在后面还好说,如果是在前面呢,那不就计算到阴影里去了嘛。如果这个对比有一个容差就好了,我以前用按键精灵的时候好像就有这种嘛,这个好不智能呀。既然它是对比像素,我直接取像素对比一下不就得了,而且我还不给它用==,给它一个范围,如果色差在这个范围内就算一样了,这样不就有容差了吗?这个缺口一般都非常明显,而阴影跟背景又很模糊,应该是可行的。思路就是获取图片的宽高,然后一个像素一个像素的遍历对比。

色差

这个色差怎么确定?一种方式就是调试,这种是比较麻烦的,还有一种方式就是获取多张图片,全图和缺陷图,然后使用取色工具,取对应位置的颜色值,确定一个大概范围。距离确定了,下面就是移动了

selenium模拟移动

selenium的模拟操作网上介绍很多,这里我们只要确认需要哪些接口就行了。 ActionChains方法:

  • movetoelement(to_element) - 鼠标移动到某个元素
  • clickandhold(on_element =None) - 点击鼠标左键,不松开
  • movebyoffset(xoffset,yoffset) - 鼠标从当前位置移动到某个坐标
  • release(on_element = None) - 在某个元素位置松开鼠标左键
  • perform() - 执行操作,记住这个很重要,调用上面的方法后,一定要执行perform才能真正执行

selenium的操作我就不详细描述了,这里用到的都是比较简单的用法。

原理分析就完了,这一次必须要贴代码了,否则可能很多人完成不了,也有利于大家的理解。

由于篇幅有限,下面为部分代码,完整代码请关注公众号“编程狗”后回复“0419”获取

# -*- coding: utf-8 -*-
import random
import time, re
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from PIL import Image
import requests
from io import BytesIO

class HuXiu(object):
    def __init__(self):
        chrome_option = webdriver.ChromeOptions()
        # chrome_option.set_headless()

        self.driver = webdriver.Chrome(executable_path=r"/usr1/webdrivers/chromedriver", chrome_options=chrome_option)
        self.driver.set_window_size(1440, 900)

    def visit_index(self):
        self.driver.get("https://www.huxiu.com/")

        WebDriverWait(self.driver, 10, 0.5).until(EC.element_to_be_clickable((By.XPATH, '//*[@class="js-register"]')))
        reg_element = self.driver.find_element_by_xpath('//*[@class="js-register"]')
        reg_element.click()

        WebDriverWait(self.driver, 10, 0.5).until(EC.element_to_be_clickable((By.XPATH, '//div[@class="gt_slider_knob gt_show"]')))

        # 进入模拟拖动流程
        self.analog_drag()

    def analog_drag(self):
        #鼠标移动到拖动按钮,显示出拖动图片
        element = self.driver.find_element_by_xpath('//div[@class="gt_slider_knob gt_show"]')
        ActionChains(self.driver).move_to_element(element).perform()
        time.sleep(3)

        # 刷新一下极验图片
        element = self.driver.find_element_by_xpath('//a[@class="gt_refresh_button"]')
        element.click()
        time.sleep(1)

        # 获取图片地址和位置坐标列表
        cut_image_url, cut_location = self.get_image_url('//div[@class="gt_cut_bg_slice"]')
        full_image_url, full_location = self.get_image_url('//div[@class="gt_cut_fullbg_slice"]')

        # 根据坐标拼接图片
        cut_image = self.mosaic_image(cut_image_url, cut_location)
        full_image = self.mosaic_image(full_image_url, full_location)

        # 保存图片方便查看
        cut_image.save("cut.jpg")
        full_image.save("full.jpg")

        # 根据两个图片计算距离
        distance = self.get_offset_distance(cut_image, full_image)

        # 开始移动
        self.start_move(distance)

        # 如果出现error
        try:
            WebDriverWait(self.driver, 5, 0.5).until(EC.element_to_be_clickable((By.XPATH, '//div[@class="gt_ajax_tip gt_error"]')))
            print("验证失败")
            return
        except TimeoutException as e:
            pass

        # 判断是否验证成功
        try:
            WebDriverWait(self.driver, 10, 0.5).until(EC.element_to_be_clickable((By.XPATH, '//div[@class="gt_ajax_tip gt_success"]')))
        except TimeoutException:
            print("again times")
            time.sleep(5)
            # 失败后递归执行拖动
            self.analog_drag()
        else:
            # 成功后输入手机号,发送验证码
            self.register()

    # 获取图片和位置列表
    def get_image_url(self, xpath):
        link = re.compile('background-image: url\("(.*?)"\); background-position: (.*?)px (.*?)px;')
        elements = self.driver.find_elements_by_xpath(xpath)
        image_url = None
        location = list()
        for element in elements:
            style = element.get_attribute("style")
            groups = link.search(style)
            url = groups[1]
            x_pos = groups[2]
            y_pos = groups[3]
            location.append((int(x_pos), int(y_pos)))
            image_url = url
        return image_url, location

 (部分代码)

这个移动movebyoffset,我之前的y值也是随机的[-5,5],我觉得这个模拟会更真实一点,总会上下抖动的嘛,结果就是因为这个考虑的太人性了,识别率非常低,改了好多范围,更大的、更小的,结果最后不偏移,竟然识别率奇高。TMD考虑的太人性化了竟然识别不了,我也是醉了。最后再把执行效果发一下吧

作者:星星在线,一个从妹子图到爬虫爱好者的猿生历程

https://www.jianshu.com/u/680e0e38ddc9

文章分享自微信公众号:
Python中文社区

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 爬虫项目:破解极验滑动验证码

    一 介绍     一些网站会在正常的账号密码认证之外加一些验证码,以此来明确地区分人/机行为,从一定程度上达到反爬的效果,对于简单的校验码Tesserocr就可...

    用户1214487
  • Python 破解极验滑动验证码

    以上图片是最典型的要属于极验滑动认证了,极验官网:http://www.geetest.com/。

    测试开发社区
  • 爬虫进阶教程:极验(GEETEST)验证码破解教程

    原文链接及原作者:爬虫进阶教程:极验(GEETEST)验证码破解教程 | Jack Cui

    圆方圆PYTHON学院
  • 这个好玩!分享几个爬虫“逆向破解”的练手项目

    Hi,大家好。 四月过半,Python 爬虫兼职接单高潮期已经到来,最近圈子里喜报频传,很多朋友都接到了大单,甚至有人靠 Python 爬虫做副业半个月就赚了 ...

    崔庆才
  • 手把手教你轻松搞定爬虫 JS 逆向

    早在几年前,内卷一词就已家喻户晓,而近两年受到各种不可抗力的影响,则进一步加剧了“卷”的程度。为缓解压力摆脱内卷,有越来越多人在开辟副业兼职赚钱,毕竟,不能指望...

    崔庆才
  • 用 Python 把网络上的付费资源都爬了一遍!

    昨天在朋友圈里,看见有 Python 圈子里的朋友晒了张图,是其用 Python 技术兼职赚钱的接单记录,在了解详情后我大为震撼,竟然有人单靠 Python 爬...

    崔庆才
  • 爬虫模拟登录破解无原图滑动验证码

    大体思路:以前的滑动验证码多为有原图的验证码,可以通过Image模块截取两张不同的图,通过对比像素得出移动的距离,无原图验证码也是基于这个原理,只是多了一步找出...

    forxtz
  • 安全报告 | 2018上半年互联网恶意爬虫分析:从全景视角看爬虫与反爬虫

    云鼎实验室
  • 【报告】2018上半年互联网恶意爬虫分析

    导语:互联网最激烈的对抗战场,除了安全专家与黑客之间,大概就是爬虫与反爬虫领域了。据统计,爬虫流量早已超过了人类真实访问请求流量。互联网充斥着形形色色的爬虫,云...

    腾讯云基础安全
  • 从全景视角看爬虫与反爬虫

    导语:互联网最激烈的对抗战场,除了安全专家与黑客之间,大概就是爬虫与反爬虫领域了。据统计,爬虫流量早已超过了人类真实访问请求流量。互联网充斥着形形色色的爬虫,云...

    C4rpeDime
  • 为爬虫获取登录cookies:登录的恩恩怨怨

    讲到的新闻爬虫,是基本不受目标服务器限制的爬虫,技术上的挑战主要在抓取任务的管理、分配,并发的使用,提高效率等方面。而实际中,不同抓取目标的爬虫会遇到很多阻碍,...

    一墨编程学习
  • 想问问身价 300 亿的潘石屹,你到底为什么要学 Python?

    Python 可能是当下最火的编程语言了,就连房地产大佬都说自己要学 Python 。

    用户1564362
  • 如何突破反爬虫?看这篇就够了!

    之前给大家写了那么多的爬虫案例,今天来给大家讲讲大部分网站反爬虫的一些措施以及我们如何去突破他们得反爬虫!当然这次有点标题党,技术是日益进步的,反爬虫技术也是如...

    Python进击者
  • Python爬虫自学系列(六)

    这是一种比较简单粗暴的方式啊,首先如果没有验证码的需求的话,碧如我之前爬CSDN抓到自己的个人信息那次。这种方式就很好了。

    看、未来
  • python + selenium 爬虫模拟登录破解无原图滑动验证码

    爬虫模拟登录破解无原图滑动验证码: https://www.cnblogs.com/98WDJ/p/11050559.html

    forxtz
  • 干货|Python大佬手把手带你破解哔哩哔哩网滑动验证(上篇)

    有爬虫经验的各位小伙伴都知道,正常我们需要登录才能获取信息的网站,是比较难爬的。原因就是在于,现在各大网站为了反爬,与爬虫机制斗智斗勇,一般的都加入了图片验证...

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

      ♥各位如果想要交流的话,可以加下QQ交流群:974178910,里面有各种你想要的学习资料。♥

    不温卜火
  • 这可能是你见过的最全的网络爬虫干货总结!

    昨天的时候我参加了掘金组织的一场 Python 网络爬虫主题的分享活动,主要以直播的形式分享了我从事网络爬虫相关研究以来的一些经验总结,整个直播从昨天下午 1 ...

    崔庆才

扫码关注云+社区

领取腾讯云代金券