Python 爬虫,如何破解谷歌验证码?

Python猫

共 14094字,需浏览 29分钟

 ·

2021-09-03 22:25

之前介绍过 Google ReCAPTCHA 验证码的绕过方法,当时介绍的是用 2Captcha,然而有些朋友跟我反映说 2Captcha 价格比较贵,而且用起来比较复杂。

今天再给大家介绍另一个用于破解 Google ReCAPTCHA 的方法。

ReCAPTCHA 介绍

可能大家还没听说过什么是 ReCAPTCHA,可能由于某些原因,这个验证码在国内出现不多,不过想必大家应该多多少少见过或用过。它长这个样子:

这时候,只要我们点击最前面的复选框,验证码算法会首先利用其「风险分析引擎」做一次安全检测,如果直接检验通过的话,我们会直接得到如下的结果:

如果算法检测到当前系统存在风险,比如可能是陌生的网络环境,可能是模拟程序,会需要做二次校验。它会进一步弹出类似如下的内容:

比如上面这张图,验证码页面会出现九张图片,同时最上方出现文字「树木」,我们需要点选下方九张图中出现「树木」的图片,点选完成之后,可能还会出现几张新的图片,我们需要再次完成点选,最后点击「验证」按钮即可完成验证。或者我们可以点击下方的「耳机」图标,这时候会切换到听写模式,验证码会变成这样:

这时候我们如果能填写对验证码读的音频内容,同样可以通过验证。这两种方式都可以通过验证,验证完成之后,我们才能完成表单的提交,比如完成登录、注册等操作。这种验证码叫什么名字?这个验证码就是 Google 的 ReCAPTCHA V2 验证码,它就属于行为验证码的一种,这些行为包括点选复选框、选择对应图片、语音听写等内容,只有将这些行为校验通过,此验证码才能通过验证。相比于一般的图形验证码来说,此种验证码交互体验更好、安全性会更高、破解难度更大。

其实上文所介绍的验证码仅仅是 ReCAPTCHA 验证码的一种形式,是 V2 的显式版本,另外其 V2 版本还有隐式版本,隐式版本在校验的时候不会再显式地出现验证页面,它是通过 JavaScript 将验证码和提交按钮进行绑定,在提交表单的时候会自动完成校验。除了 V2 版本,Google 又推出了最新的 V3 版本,reCAPTCHA V3 验证码会为根据用户的行为来计算一个分数,这个分数代表了用户可能为机器人的概率,最后通过概率来判断校验是否可以通过。其安全性更高、体验更好。

体验

那哪里可以体验到 ReCAPTCHA 呢?我们可以打开这个网站:https://www.google.com/recaptcha/api2/demo,建议科学上网,同时用匿名窗口打开,这样的话测试不会受到历史 Cookies 的干扰,如图所示:

这时候,我们可以看到下方有个 ReCAPTCHA 的窗口,然后点击之后就出现了一个验证图块。

当然靠人工是能解的,但对于爬虫来说肯定不行啊,那怎么自动化解呢?

接下来我们就来介绍一个简单好用的平台。

解决方案

本次我们介绍的一个 ReCAPTCHA 破解服务叫做 YesCaptcha,主页是 http://yescaptcha.365world.com.cn/,它现在同时可以支持 V2 和 V3版本的破解。

我们这次就用它来尝试解一下刚才的 ReCAPTCHA 上的 V2 类型验证码:https://www.google.com/recaptcha/api2/demo。

简单注册之后,可以找到首页有一个 Token。我们可以复制下来以备后面使用,如图所示:

它有两个关键的 API,一个是创建验证码服务任务,另一个是查询任务状态,API 如下:

  • 创建任务:http://api.yescaptcha.365world.com.cn/v3/recaptcha/create

  • 查询状态:http://api.yescaptcha.365world.com.cn/v3/recaptcha/status

API 文档可以参考这里:http://docs.yescaptcha.365world.com.cn/

经过 API 文档可以看到使用的时候可以配置如下参数:

参数名是否必须说明
token请在个人中心获取 (Token)
siteKeyReCaptcha SiteKey (固定参数)
siteRefererReCaptcha Referer (一般也为固定参数)
captchaTypeReCaptchaV2(默认) / ReCaptchaV3
siteActionReCaptchaV3 选填 Action动作 默认verify
minScoreReCaptchaV3 选填 最小分数(0.1-0.9)

这里就有三个关键信息了:

  • token:就是刚才我们在 YesCaptcha 上复制下来的参数

  • siteKey:这个是 ReCAPACHA 的标志字符串,稍后我们会演示怎么找。

  • siteReferer,一般是 ReCAPTCHA 的来源网站的 Referer,比如对于当前的案例,该值就是 https://www.google.com/recaptcha/api2/demo

那 siteKey 怎么找呢?其实很简单,我们看下当前 ReCAPTCHA 的 HTML 源码,从源码里面找一下就好了:

这里可以看到每个 ReCAPTCHA 都对应一个 div,div 有个属性叫做 date-sitekey,看这里的值就是:

6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-

好,万事俱备了,只差代码了!

开工

我们就用最简单 requests 来实现下吧,首先把常量定义一下:

TOKEN = '50a07xxxxxxxxxxxxxxxxxxxxxxxxxf78'  # 请替换成自己的TOKEN
REFERER = 'https://www.google.com/recaptcha/api2/demo'
BASE_URL = 'http://api.yescaptcha.365world.com.cn'
SITE_KEY = '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-' # 请替换成自己的SITE_KEY

这里我们定义了这么几个常量:

  • TOKEN:就是网站上复制来的 token

  • REFERER:就是 Demo 网站的链接

  • API_BASE_URL:就是 YesCaptcha 的 API 网址

  • SITE_KEY:就是刚才我们找到的 data-sitekey

然后我们定义一个创建任务的方法:

def create_task():
    url = f"{BASE_URL}/v3/recaptcha/create?token={TOKEN}&siteKey={SITE_KEY}&siteReferer={REFERER}"
    try:
        response = requests.get(url)
        if response.status_code == 200:
            data = response.json()
            print('response data:', data)
            return data.get('data', {}).get('taskId')
    except requests.RequestException as e:
        print('create task failed', e)

这里就是调 API 来创建任务,没什么好说的。

如果创建成功之后会得到一个 task_id,接下来我们就需要用这个 task_id 来轮询查看任务的状态,定义如下的这么一个方法:

def polling_task(task_id):
    url = f"{BASE_URL}/v3/recaptcha/status?token={TOKEN}&taskId={task_id}"
    count = 0
    while count < 120:
        try:
            response = requests.get(url)
            if response.status_code == 200:
                data = response.json()
                print('polling result', data)
                status = data.get('data', {}).get('status')
                print('status of task', status)
                if status == 'Success':
                    return data.get('data', {}).get('response')
        except requests.RequestException as e:
            print('polling task failed', e)
        finally:
            count += 1
            time.sleep(1)

这里就是设置了最长轮询次数 120 次,请求的 API 就是查询任务状态的 API,会得到一个任务状态的结果,如果结果是 Success,那就证明任务成功了,解析其中的 response 结果就是验证码破解之后得到的 token。

两个方法调用一下:

if __name__ == '__main__':
    task_id = create_task()
    print('create task successfully', task_id)
    response = polling_task(task_id)
    print('get response:', response[0:40]+'...')

运行结果类似如下:

response data: {'status'0'msg''ok''data': {'taskId''1479436991'}}
create task successfully 1479436991
polling result {'status'0'msg''ok''data': {'status''Working'}}
status of task Working
polling result {'status'0'msg''ok''data': {'status''Working'}}
status of task Working
polling result {'status'0'msg''ok''data': {'status''Working'}}
status of task Working
polling result {'status'0'msg''ok''data': {'status''Success''response''03AGdBq27-ABqvNmgq96iuprN8Mvzfq6_8noknIed5foLb15oWvWVksq9KesDkDd7dgMMr-UmqULZduXTWr87scJXl3djhl2btPO721eFAYsVzSk7ftr4uHBdJWonnEemr9dNaFB9qx5pnxr3P24AC7cCfKlOH_XARaN4pvbPNxx_UY5G5fzKUPFDOV14nNkCWl61jwwC0fuwetH1q99r4hBQxyI6XICD3PiHyHJMZ_-wolcO1R9C90iGQyjzrSMiNqErezO24ODCiKRyX2cVaMwM9plbxDSuyKUVaDHqccz8UrTNNdJ4m2WxKrD9wZDWaSK10Ti1LgsqOWKjKwqBbuyRS_BkSjG6OJdHqJN4bpk_jAcPMO13wXrnHBaXdK4FNDR9-dUvupHEnr7QZEuNoRxwl8FnO2Fgwzp2sJbGeQkMbSVYWdAalE6fzJ8NwsFJxCdDyeyO817buBtvTJ4C06C1uZ92fpPTeYGJwbbicOuqbGfHNTyiSJeRNmt-5RKz0OUiPJOPnmVKGlWBOqwbwCW1WZt-E-hH4FEg4En5TITmmPb_feS9dWKUxudn1U0hHk2vV9PerjZLtI7F67KtgmcqRrARPbwnc6KyAi3Hy1hthP92lv4MRIcO2jx0Llvsja-G2nhjZB0ZoJwkb9106pmqldiwlXxky4Dcg7VPStiCYJvhQpRYol7Iq1_ltU2tyhMqsu_Xa8Z6Mr5ykRCLnmlLb8DV8isndrdwp84wo_vPARGRj7Up9ov-ycb5lDKTf1XRaHiMCa8d2WLy0Pjco9UnsRAPw0FW3MsBJah6ryHUUDho7ffhUUgV1k86ryJym6xbWch1sVC4D5owzrCFn6L-rSLc5SS1pza2zU5LK4kAZCmbXNRffiFrhUY8nP4T1xaR2KMhIaN8HhJQpR8sQh1Azc-QkDy4rwbYmxUrysYGMrAOnmDx9z7tWQXbJE4IgCVMx5wihSiE-T8nbF5y1aJ0Ru9zqg1nZ3GSqsucSnvJA8HV5t9v0QSG5cBC1x5HIceA-2uEGSjwcmYOMw8D_65Dl-d6yVk1YN2FZCgMWY5ewzB1RAFN1BMqKoITQJ64jq3lKATpkc5i7aTA2bRGQyXrbDyMRIrVXKnYMHegfMbDn0l4O81a8vxmevLspKkacVPiqLsAe-73jAxMvsOqaG7cKxMQO9CY3qbtD55YgN0W4p2jyNSVz3aEpffHRqYyWMsRI5LddLgaZQDoHHgGUhV580PSIdZJ5eKd0gOjxIYxKlr0IgbMWRmsG_TgDNImy1c5oey8ojl-zWpOQW7bnfq5Z4tZ10_sCTfoOZVLqRuOsqB1OOO9pLRQojLBP0HUiGhRAr_As9EIDu6F9NIQfdAmCaVvavJbi1CZITFjcywP-tBrHsxpwkCXlwl996MK_XyEDuyWnJVGiVSthUMY306tIh1Xxj93W3KQJCzsfJQcjN-3lGLLeDFddypHyG4yrpRqRHHBNyiNJHgxSk5SaShEhXvByjkepvhrKX3kJssCU04biqqmkrQ49GqBV9OsWIy0nN3OJTx8v05MP8aU8YYkYBF01UbSff4mTfLAhin6iWk84Y074mRbe2MbgFAdU58KnCrwYVxcAR8voZsFxbxNwZXdVeexNx5HlIlSgaAHLWm2kFWmGPPW-ZA7R8Wst-mc7oIKft5iJl8Ea0YFz8oXyVgQk1rd9nDR3xGe5mWL1co0MiW1yvHg'}}

如果其返回的是如上格式的数据,就代表 ReCAPTCHA 验证码已经识别成功了,其返回的 response 字段的内容就是识别的 token,我们直接拿着这个 token 放到表单里面提交就成功了。

那这个 token 怎么来用呢?其实如果我们用浏览器验证验证成功之后,点击表单提交的时候,在其表单里面会把一个 name 叫做 g-recaptcha-response 的 textarea 赋值,如果验证成功,它的 value 值就是验证之后得到的 token,这个会作为表单提交的一部分发送到服务器进行验证。如果这个字段校验成功了,那就没问题了。

所以,如上的过程相当于为我们模拟了点选验证码的过程,其最终得到的这个 token 其实就是我们应该赋值给 name 为 g-recaptcha-response 的内容。那么怎么赋值呢?很简单,用 JavaScript 就好了。我们可以用 JavaScript 选取到这个 textarea,然后直接赋值即可,代码如下:

document.getElementById("g-recaptcha-response").innerHTML="TOKEN_FROM_YESCAPTCHA";

注意这里的 TOKEN_FROM_YESCAPTCHA 需要换成刚才我们所得到的 token 值。我们做爬虫模拟登录的时候,假如是用 Selenium、Puppeteer 等软件,在模拟程序里面,只需要模拟执行这段 JavaScript 代码,就可以成功赋值了。执行之后,直接提交表单,我们查看下 Network 请求:

可以看到其就是提交了一个表单,其中有一个字段就是 g-recaptcha-response,它会发送到服务端进行校验,校验通过,那就成功了。所以,如果我们借助于 YesCaptcha 得到了这个 token,然后把它赋值到表单的 textarea 里面,表单就会提交,如果 token 有效,就能成功绕过登录,而不需要我们再去点选验证码了。最后我们得到如下成功的页面:

当然我们也可以使用 requests 来模拟完成表单提交:

def verify(response):
    url = "https://www.google.com/recaptcha/api2/demo"
    data = {"g-recaptcha-response": response}
    response = requests.post(url, data=data)
    if response.status_code == 200:
        return response.text

最后完善一下调用:

if __name__ == '__main__':
    task_id = create_task()
    print('create task successfully', task_id)
    response = polling_task(task_id)
    print('get response:', response[0:40]+'...')
    result = verify(response)
    print(result)

运行结果如下:

response data: {'status'0'msg''ok''data': {'taskId''1479436991'}}
create task successfully 1479436991
polling result {'status'0'msg''ok''data': {'status''Working'}}
status of task Working
polling result {'status'0'msg''ok''data': {'status''Working'}}
status of task Working
polling result {'status'0'msg''ok''data': {'status''Working'}}
status of task Working
polling result {'status'0'msg''ok''data': {'status''Success''response''03AGdBq27-ABqvNmgq96iuprN8Mvzfq6_8noknIed5foLb15oWvWVksq9KesDkDd7dgMMr-UmqULZduXTWr87scJXl3djhl2btPO721eFAYsVzSk7ftr4uHBdJWonnEemr9dNaFB9qx5pnxr3P24AC7cCfKlOH_XARaN4pvbPNxx_UY5G5fzKUPFDOV14nNkCWl61jwwC0fuwetH1q99r4hBQxyI6XICD3PiHyHJMZ_-wolcO1R9C90iGQyjzrSMiNqErezO24ODCiKRyX2cVaMwM9plbxDSuyKUVaDHqccz8UrTNNdJ4m2WxKrD9wZDWaSK10Ti1LgsqOWKjKwqBbuyRS_BkSjG6OJdHqJN4bpk_jAcPMO13wXrnHBaXdK4FNDR9-dUvupHEnr7QZEuNoRxwl8FnO2Fgwzp2sJbGeQkMbSVYWdAalE6fzJ8NwsFJxCdDyeyO817buBtvTJ4C06C1uZ92fpPTeYGJwbbicOuqbGfHNTyiSJeRNmt-5RKz0OUiPJOPnmVKGlWBOqwbwCW1WZt-E-hH4FEg4En5TITmmPb_feS9dWKUxudn1U0hHk2vV9PerjZLtI7F67KtgmcqRrARPbwnc6KyAi3Hy1hthP92lv4MRIcO2jx0Llvsja-G2nhjZB0ZoJwkb9106pmqldiwlXxky4Dcg7VPStiCYJvhQpRYol7Iq1_ltU2tyhMqsu_Xa8Z6Mr5ykRCLnmlLb8DV8isndrdwp84wo_vPARGRj7Up9ov-ycb5lDKTf1XRaHiMCa8d2WLy0Pjco9UnsRAPw0FW3MsBJah6ryHUUDho7ffhUUgV1k86ryJym6xbWch1sVC4D5owzrCFn6L-rSLc5SS1pza2zU5LK4kAZCmbXNRffiFrhUY8nP4T1xaR2KMhIaN8HhJQpR8sQh1Azc-QkDy4rwbYmxUrysYGMrAOnmDx9z7tWQXbJE4IgCVMx5wihSiE-T8nbF5y1aJ0Ru9zqg1nZ3GSqsucSnvJA8HV5t9v0QSG5cBC1x5HIceA-2uEGSjwcmYOMw8D_65Dl-d6yVk1YN2FZCgMWY5ewzB1RAFN1BMqKoITQJ64jq3lKATpkc5i7aTA2bRGQyXrbDyMRIrVXKnYMHegfMbDn0l4O81a8vxmevLspKkacVPiqLsAe-73jAxMvsOqaG7cKxMQO9CY3qbtD55YgN0W4p2jyNSVz3aEpffHRqYyWMsRI5LddLgaZQDoHHgGUhV580PSIdZJ5eKd0gOjxIYxKlr0IgbMWRmsG_TgDNImy1c5oey8ojl-zWpOQW7bnfq5Z4tZ10_sCTfoOZVLqRuOsqB1OOO9pLRQojLBP0HUiGhRAr_As9EIDu6F9NIQfdAmCaVvavJbi1CZITFjcywP-tBrHsxpwkCXlwl996MK_XyEDuyWnJVGiVSthUMY306tIh1Xxj93W3KQJCzsfJQcjN-3lGLLeDFddypHyG4yrpRqRHHBNyiNJHgxSk5SaShEhXvByjkepvhrKX3kJssCU04biqqmkrQ49GqBV9OsWIy0nN3OJTx8v05MP8aU8YYkYBF01UbSff4mTfLAhin6iWk84Y074mRbe2MbgFAdU58KnCrwYVxcAR8voZsFxbxNwZXdVeexNx5HlIlSgaAHLWm2kFWmGPPW-ZA7R8Wst-mc7oIKft5iJl8Ea0YFz8oXyVgQk1rd9nDR3xGe5mWL1co0MiW1yvHg'}}
status of task Success
get response: 03AGdBq27-ABqvNmgq96iuprN8Mvzfq6_8noknIe...
<!DOCTYPE HTML><html dir="ltr"><head><meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width, user-scalable=yes"><title>ReCAPTCHA demo</title><link rel="stylesheet" href="https://www.gstatic.com/recaptcha/releases/TbD3vPFlUWKZD-9L4ZxB0HJI/demo__ltr.css" type="text/css"></head><body><div class="recaptcha-success">Verification Success... Hooray!</div></body></html>

最后就可以发现,模拟提交之后,结果会有一个 Verification Success... Hooray! 的文字,就代表验证成功了!

至此,我们就成功完成了 ReCAPTCHA 的破解。

上面我们介绍的是 requests 的实现,当然使用 Selenium 等工具也可以实现,具体的 Demo 在文档也写好了,请大家参考文档的说明使用即可。

小福利

现在 YesCaptcha 的价格我觉得相比之前介绍过的 2Captcha 实惠很多了,它破解一次是花费 10 点数,10 块钱是 10000 点数,所以平均破解一次验证码一分钱,新用户是送 1000 点数,可以破解 100 次。我个人觉得很实惠了。

大家有需要的话可以试试看!网址是: http://yescaptcha.365world.com.cn/

溜了溜了~

Python猫技术交流群开放啦!群里既有国内一二线大厂在职员工,也有国内外高校在读学生,既有十多年码龄的编程老鸟,也有中小学刚刚入门的新人,学习氛围良好!想入群的同学,请在公号内回复『交流群』,获取猫哥的微信(谢绝广告党,非诚勿扰!)~


还不过瘾?试试它们




如何用 Python 实现电脑端自动化?

如何提高 Python 装饰器的使用效率?

坚持原创很难,但我不会放弃!

开源框架 Zappa:上线 Python 应用仅需一条命令!

2020年Python文章盘点,我选出了个人TOP10

深度剖析为什么 Python 中整型不会溢出?


如果你觉得本文有帮助
请慷慨分享点赞,感谢啦
浏览 38
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报