来写一下令爬虫工程师闻风丧胆的极验验证码的绕过方案,对接的是一个俄罗斯的打码平台 2captcha

先来看案例,网址:https://account.quandashi.com/

在登录账号的时候,会弹出极验的点选验证码

应对这种相对专业、更新频率较高的验证码,还是直接对接打码平台比较高效,首先就是在2captcha注册一个账号,充值,然后对接文档2captcha的接口文档

通过查阅文档,我们得知,极验的验证过程,无非就是获取 challenge gt api_server,发送到接口后返回 validate seccode ,然后拿到这两个参数去验证的过程

接下来,我们通过抓包分析各个参数的获取过程

challenge 和 gt

从抓包得知,这两个参数可以从 /gee-test-code 接口获取,实现代码:

1
2
3
4
def get_gt_challenge():
api = f"https://account.quandashi.com/passport/gee-test-code?t={round(time.time() * 10 ** 3)}"
res = session.get(api).json()
return res["challenge"], res["gt"]

validate 和 seccode

带上challenge两个参数,发送到 2captcha的 /in.php 接口

1
2
3
4
5
6
7
8
9
10
11
def send_to_captcha(gt, challenge):
in_api = "http://2captcha.com/in.php"
form_data = {
"key": key_2captcha,
"method": "geetest",
"gt": gt,
"challenge": challenge,
"pageurl": page_url,
}
res = session.get(in_api, params=form_data)
return res.text.strip("OK|")
  • pageurl 是可选的,就是从哪个页面进行验证
  • key 即是自己的 2captcha凭证

请求接口后会返回一个 captcha_id,后续要根据这个id去请求 /res.php 接口,获取验证结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def get_validate_seccode(captcha_id):
"""
Make a 15-20 seconds timeout
"""
res_api = "http://2captcha.com/res.php"
params = {
"key": key_2captcha,
"id": captcha_id,
"action": "get",
}
res = session.get(res_api, params=params)
if res.text.startswith("OK"):
vali_result = json.loads(res.text.strip("OK|"))
print(vali_result)
return vali_result["geetest_validate"], vali_result["geetest_seccode"]
elif res.text == "CAPCHA_NOT_READY":
return "not ready"
elif res.text == "ERROR_CAPTCHA_UNSOLVABLE":
return "unsolvable"

处理的结果可能有以下几种情况:

  • OK 处理成功,拿到 validateseccode ,就可以进行登录请求了
  • CAPCHA_NOT_READY ,验证码还没处理好,需要等一段时间再次请求
  • ERROR_CAPTCHA_UNSOLVABLE 无法处理验证码,需要重新获取 challenge 拿去处理

拿到 validateseccode 就可以去请求登录接口了

1
2
3
4
5
6
7
8
9
10
11
12
def login():
api = "https://account.quandashi.com/passport/dologin"

challenge, seccode, validate = gen_session_id()
form_data = {
"adminAccount": "",
"adminPwd": "",
"geetest_challenge": challenge,
"geetest_validate": validate,
"geetest_seccode": seccode,
}
res = session.post(api, data=form_data)

登录成功: