问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

HCaptcha 的模拟点击破解教程来了!

发布网友 发布时间:2024-09-24 13:01

我来回答

1个回答

热心网友 时间:2024-09-24 22:02

前面的文章我们介绍过 ReCaptcha 的模拟点击破解教程,但除了 ReCaptcha,还有另外和 ReCapacha 验证流程很相似的验证码,叫做 HCaptcha。

ReCaptcha 是谷歌家的,因为某些原因,咱们国内是无法使用 ReCaptcha 的,所以有时候 HCaptcha 也成了一些国际性网站的比较好的选择。

那今天我们就来了解下 HCaptcha 和它的模拟点击破解流程。

HCaptcha

我们首先看看 HCaptcha 的验证交互流程,其 Demo 网站为 https://democaptcha.com/demo-form-eng/hcaptcha.html,打开之后,我们可以看到如下的验证码入口页面:

看起来入口和 ReCaptcha 很相似的对吧,其实验证流程也是很类似的。

当我们点击复选框时,验证码会先通过其风险分析引擎判断当前用户的风险,如果是低风险用户,便可以直接通过,反之,验证码会弹出对话框,让我们回答对话框中的问题,类似如下:

这时候我们看到 HCaptcha验证码会给我们一个问题,比如上图的问题是「请点击每张包含飞机的图片」,我们需要从下面的九张图中选择出含有飞机的图片,如果九张图片中,没有飞机,则点击「跳过 / Skip」按钮,如果有,则将所有带有飞机的图片都选择上,跳过按钮会变成「检查 / Verify」按钮,验证通过之后我们就可以看到如下的验证成功的效果了:

是不是整体流程和 ReCaptcha 还是还是非常相近的?

但其实这个比 ReCaptcha 简单一些,它的验证码图片每次一定是 3x3 的,没有 4x4 的,而且点击一个图之后不会再出现一个新的小图让我们二次选择,所以其破解思路也相对简单一些。

如何破解

整个流程其实我们稍微梳理下,就知道整体的的破解思路了,有这么两个关键点:

第一就是把上面的文字内容找出来,以便于我们知道要点击的内容是什么。

第二就是我们要知道哪些目标图片和上面的文字是匹配的,找到了依次模拟点击就好了。

听起来似乎很简单的对吧,但第二点是一个难点,我们咋知道哪些图片和文字匹配的呢?这就是一个难题。

前面 ReCaptcha 的破解过程我们了解过了使用 YesCaptcha 来进行图片的识别,除了 ReCaptcha,YesCaptcha 其实也支持 HCaptcha 的验证码识别,利用 YesCaptcha 我们也能轻松知道哪些图片和输入内容是匹配的。

下面让们来试试看。

YesCaptcha

在使用之前我们需要先注册下这个网站,网站地址是 https://yescaptcha.com/i/CnZPBu ,注册个账号之后大家可以在后台获取一个账户密钥,也就是 ClientKey,保存备用。

OK,然后我们可以查看下这里的官方文档:https://yescaptcha.atlassian.net/wiki/spaces/YESCAPTCHA/pages/24543233/HCaptchaClassification+Hcaptcha,这里介绍介绍了一个 API,大致内容是这样的。

首先有一个创建任务的 API,API 地址为 https://api.yescaptcha.com/createTask,然后看下请求参数:

这里我们需要传入这么几个参数:

type:内容就是 ****

queries:是验证码对应的 Base64 编码,这里直接转成一个列表就可以

question:对应的问题 ID,也就是识别目标的代号,这里其实就是问题整句的内容

corrdinate:一个返回结果的控制开关,默认会返回每张图片识别的 true / false 结果,也就是第 x 张图片是否和图片匹配,如果加上该参数,那么 API 就会返回对应匹配图片的索引。

比如这里我们可以 POST 这样的一个内容给服务器,结构如下:

{"clientKey": "cc9c18d3e263515c2c072b36a7125eecc078618f","task": {"type": "HCaptchaClassification","queries": ["/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8Uw...","/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8Uw...",..."/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8Uw...",],"question": "请单击每个包含卡车的图像。" // 直接上传问题整句}}

然后服务器就会返回类似这样的响应:

{"errorId": 0,"errorCode": "","status": "ready","solution": {"objects": [true, false, false, true, true, false, true, true] // 返回图片是否为目标,"labels": ["truck", "boat", "boat", "truck", "truck", "airplane-right", "truck", "truck"] // 返回图片对应的标签},"taskId": "5aa8be0c-94a5-11ec-80d7-00163f00a53c""}

OK,我们可以看到,返回结果的 solution 字段中的 objects 字段就包含了一串 true 和 false 的列表,这就代表了每张图片是否和目标匹配。

知道了这个结果之后,我们只需要将返回结果为 true 的图片进行模拟点击就好了。

代码基础实现

行,那有了基本思路之后,那我们就开始用 Python 实现下整个流程吧,这里我们就拿 https://democaptcha.com/demo-form-eng/hcaptcha.html 这个网站作为样例来讲解下整个识别和模拟点击过程。

识别封装

首先我们对上面的任务 API 实现一下封装,来先写一个类:

from loguru import loggerfrom app.settings import CAPTCHA_RESOLVER_API_KEY, CAPTCHA_RESOLVER_API_URLimport requestsclass CaptchaResolver(object):def __init__(self, api_url=CAPTCHA_RESOLVER_API_URL, api_key=CAPTCHA_RESOLVER_API_KEY):self.api_url = api_urlself.api_key = api_keydef create_task(self, queries, question):logger.debug(f'start to recognize image for question {question}')data = {"clientKey": self.api_key,"task": {"type": "HCaptchaClassification","queries": queries,"question": question}}try:response = requests.post(self.api_url, json=data)result = response.json()logger.debug(f'captcha recogize result {result}')return resultexcept requests.RequestException:logger.exception('error occurred while recognizing captcha', exc_info=True)

OK,这里我们就先定义了一个类 CaptchaResolver,然后主要接收两个参数,一个就是 api_url,这个对应的就是 https://api.yescaptcha.com/createTask 这个 API 地址,然后还有一个参数是 api_key,这个就是前文介绍的那个 ClientKey。

接着我们定义了一个 create_task 方法,接收两个参数,第一个参数 queries 就是每张验证码图片对应的 Base64 编码,第二个参数 question 就是要识别的问题整句,这里就是将整个请求用 requests 模拟实现了,最后返回对应的 JSON 内容的响应结果就好了。

基础框架

OK,那么接下来我们来用 Selenium 来模拟打开这个实例网站,然后模拟点选来触发验证码,接着识别验证码就好了。

首先写一个大致框架:

import timefrom selenium import webdriverfrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium.webdriver.remote.webelement import WebElementfrom selenium.webdriver.common.action_chains import ActionChainsfrom app.captcha_resolver import CaptchaResolverclass Solution(object):def __init__(self, url):self.browser = webdriver.Chrome()self.browser.get(url)self.wait = WebDriverWait(self.browser, 10)self.captcha_resolver = CaptchaResolver()def __del__(self):time.sleep(10)self.browser.close()

这里我们先在构造方法里面初始化了一个 Chrome 浏览器操作对象,然后调用对应的 get 方法打开实例网站,接着声明了一个 WebDriverWait 对象和 CaptchaResolver 对象,以分别应对节点查找和验证码识别操作,留作备用。

iframe 切换支持

接着,下一步我们就该来模拟点击验证码的入口,来触发验证码了对吧。

通过观察我们发现这个验证码和 ReCaptcha 非常类似,其入口其实是在 iframe 里面加载的,对应的 iframe 是这样的:

另外弹出的验证码图片又在另外一个 iframe 里面,如图所示:

Selenium 查找节点是需要切换到对应的 iframe 里面才行的,不然是没法查到对应的节点,也就没法模拟点击什么的了。

所以这里我们定义几个工具方法,分别能够支持切换到入口对应的 iframe 和验证码本身对应的 iframe,代码如下:

def get_captcha_entry_iframe(self) -> WebElement:self.browser.switch_to.default_content()captcha_entry_iframe = self.browser.find_element_by_css_selector('.h-captcha > iframe')return captcha_entry_iframedef switch_to_captcha_entry_iframe(self) -> None:captcha_entry_iframe: WebElement = self.get_captcha_entry_iframe()self.browser.switch_to.frame(captcha_entry_iframe)def get_captcha_content_iframe(self) -> WebElement:self.browser.switch_to.default_content()captcha_content_iframe = self.browser.find_element_by_xpath('//iframe[contains(@title, "Main content")]')return captcha_content_iframedef switch_to_captcha_content_iframe(self) -> None:captcha_content_iframe: WebElement = self.get_captcha_content_iframe()self.browser.switch_to.frame(captcha_content_iframe)

这样的话,我们只需要调用 switch_to_captcha_content_iframe 就能查找验证码图片里面的内容,调用 switch_to_captcha_entry_iframe 就能查找验证码入口里面的内容。

触发验证码

OK,那么接下来的一步就是来模拟点击验证码的入口,然后把验证码触发出来了对吧,就是模拟点击这里:

实现很简单,代码如下:

def trigger_captcha(self) -> None:self.switch_to_captcha_entry_iframe()captcha_entry = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#anchor #checkbox')))captcha_entry.click()time.sleep(2)self.switch_to_captcha_content_iframe()captcha_element: WebElement = self.get_captcha_element()if captcha_element.is_displayed:logger.debug('trigged captcha successfully')

这里首先我们首先调用 switch_to_captcha_entry_iframe 进行了 iframe 的切换,然后找到那个入口框对应的节点,然后点击一下。

点击完了之后我们再调用 switch_to_captcha_content_iframe 切换到验证码本身对应的 iframe 里面,查找验证码本身对应的节点是否加载出来了,如果加载出来了,那么就证明触发成功了。

找出识别目标

OK,那么现在验证码可能就长这样子了:

那接下来我们要做的就是两件事了,一件事就是把匹配目标,也就是问题本身找出来,第二件事就是把每张验证码保存下来,然后转成 Base64 编码。

好,那么怎么查找问题呢呢?用 Selenium 常规的节点搜索就好了:

def get_captcha_target_text(self) -> WebElement:captcha_target_name_element: WebElement = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '.prompt-text')))return captcha_target_name_element.text

通过调用这个方法,我们就能得到上图中完整的问题文本了。

验证码识别

接下来,我们就需要把每张图片进行下载并转成 Base64 编码了,我们观察下它的 HTML 结构:

我们可以看到,每个验证码其实都对应了一个 .task-image 的节点,然后里面有个 .image-wrapper 的节点,在里面有一个 .image 的节点,那图片怎么呈现的呢?这里它是设置了一个 style CSS 样式,通过 CSS 的 backgroud 来设置了验证码图片的地址。

所以,我们要想提取验证码图片也比较容易了,我们只需要找出 .image 节点的 style 属性的内容,然后提取其中的 url 就好了。

得到 URL 之后,转下 Base64 编码,利用 captcha_resolver 就可以对内容进行识别了。

所以代码可以写为如下内容:

def verify_captcha(self):# get target textself.captcha_target_text = self.get_captcha_target_text()logger.debug(f'captcha_target_text {self.captcha_target_text}')# extract all imagessingle_captcha_elements = self.wait.until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR, '.task-image .image-wrapper .image')))resized_single_captcha_base64_strings = []for i, single_captcha_element in enumerate(single_captcha_elements):single_captcha_element_style = single_captcha_element.get_attribute('style')pattern = re.compile('url\("(https.*?)"\)')match_result = re.search(pattern, single_captcha_element_style)single_captcha_element_url = match_result.group(1) if match_result else Nonelogger.debug(f'single_captcha_element_url {single_captcha_element_url}')with open(CAPTCHA_SINGLE_IMAGE_FILE_PATH % (i,), 'wb') as f:f.write(requests.get(single_captcha_element_url).content)resized_single_captcha_base64_string = resize_base64_image(CAPTCHA_SINGLE_IMAGE_FILE_PATH % (i,), (100, 100))resized_single_captcha_base64_strings.append(resized_single_captcha_base64_string)logger.debug(f'length of single_captcha_element_urls {len(resized_single_captcha_base64_strings)}')

这里我们提取出来了每张验证码图片的 url,这里是用正则表达式进行批评的,提取出 url 之后,我们然后将其存入了 resized_single_captcha_base64_strings 列表里面。

其中这里的 Base64 编码我们单独定义了一个方法,传入了图片路径和调整大小,然后可以返回编码后的结果,定义如下:

from PIL import Imageimport base64from app.settings import CAPTCHA_RESIZED_IMAGE_FILE_PATHdef resize_base64_image(filename, size):width, height = sizeimg = Image.open(filename)new_img = img.resize((width, height))new_img.save(CAPTCHA_RESIZED_IMAGE_FILE_PATH)with open(CAPTCHA_RESIZED_IMAGE_FILE_PATH, "rb") as f:data = f.read()encoded_string = base64.b64encode(data)return encoded_string.decode('utf-8')图片识别

好,那么现在我们已经可以得到问题内容了,也能得到每张图片对应的 Base64 编码了,我们直接利用 YesCaptcha 进行图像识别就好了,代码调用如下:

# try to verify using APIcaptcha_recognize_result = self.captcha_resolver.create_task(resized_single_captcha_base64_strings,self.captcha_target_text)if not captcha_recognize_result:logger.error('count not get captcha recognize result')returnrecognized_results = captcha_recognize_result.get('solution', {}).get('objects')if not recognized_results:logger.error('count not get captcha recognized indices')return

如果运行正常的话,我们可能得到如下的返回结果:

{"errorId": 0,"errorCode": "","status": "ready","solution": {"objects": [true, false, false, true, true, false, true, true] // 返回图片是否为目标,"labels": ["truck", "boat", "boat", "truck", "truck", "airplane-right", "truck", "truck"] // 返回图片对应的标签},"taskId": "5aa8be0c-94a5-11ec-80d7-00163f00a53c""}0

现在我们可以看到 sulution 里面的 objects 字段就包含了 true false 的列表,比如第一个 true 就代表了第一个验证码是和问题匹配的,第二个 false 就代表了第二个验证码图片和问题是不匹配的。那序号和图片又是怎么对应的呢

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
太和县环球嘉年华港口有限公司怎么样? 为什么抵触相亲? 鸡蛋怎么做好吃家常做法大全 为何抵触相亲 为什么很多人都抵触相亲? 鸡蛋怎么做才营养好吃呢? 怎么可以搞到110电话打过去给别人 植发后能保持多久?有人知道吗? 银联储蓄卡包括什么 怎么让电脑图标变小如何将电脑桌面上软件变小 The effect of art on people's daily lives写一篇英语作文 东方树叶是假茶吗? 优酷vip怎么免费领取? 优酷会员免费领取 化妆品包装盒没生产地址能销售吗 化妆品包装盒哪家价格低? 听语音时,为什么手机屏幕会黑屏? 为什么我的手机通话会自动黑屏啊? 小鸡也能飞游戏介绍 飞小鸡有什么绝巧 谁有领悟玄奥法则类的玄幻小说推荐一下被。主角要天才型但不要出来... 主角叫九凤大帝的小说 主角叫叶南的玄幻小说 主角叫杨昭的玄幻修仙小说 桥架伸缩节安装规范要求 肠粉加生粉有什么作用 肠粉米桨都加什么,为什么做出来粘,沾 QQ音乐锁定以及解锁桌面歌词方 怎么解开桌面歌词的锁定呢? 怎样取消QQ音乐桌面歌词的锁定? 点一下文件,文件就消失了 怎样才算是来源合法的资金? 灭火器三个使用步骤 为什么手机总是显示ip地址是192.168.0.1 为什么一搬的IP地扯都是192.168.1.X 为什么我们家里的IP都是192.168开头的? GIVE MORE,EXPECT LESS,怎么翻译? Work Hard Play Hard,Give More Patience & Carefully 翻译_百度... “Give me more hope,I'll more believe your heart”是什么意思,求高... 怎么查自己路由器的密码啊 怎么知道自己的宽带密码 法语的动词是要经常变位的么?请具体点说说! 怎样砍价成功几率大一点 王盟相关CP 多多买菜新人下单全额返会返还吗 拼多多买菜返现金是真的吗 拼多多买菜返现金怎么返 多多买菜满返的钱是何时能使用? 瓦罗兰特最强英雄是谁 英雄强度介绍 如何开启微信密友功能? 造物法则2:先锋英雄支线泰坦的宝藏怎么做介绍_造物法则2:先锋英雄支线...