-
当看到
cookies
中有datadome
, 代表存在datadome
验证, 有以下三种情况, 举个例子:-
当你要访问
https://www.vinted.com/
, 挂代理请求https://www.vinted.com/
:- 状态码不是
403
(无感模式
):- 打开 f12 查看是否有
/js/
结尾并且接口响应如下类似:
{ "status": 200, "cookie": "datadome=66wPBABk21P4x28BLuVse__8_z141EPJEjbgi1HBvNGBcHmX91OT1Z9Z63G4x_suPlRPQ_tgwljYmI5mWxpmkMJ3pKrcnAVKHZs2ymS_2O4nM5wEblvP~~nK3orSol0W; Max-Age=31536000; Domain=.soundcloud.com; Path=/; Secure; SameSite=Lax" }
无感
验证类型, 必须要传js_url
(该/js
结尾的 url), 该种模式会在我们的接口响应的extra
参数中返回一个did
参数, 该参数对于该页面后续的datadome
验证非常重要!!!- 如果首页是
无感模式
, 则后续的关键数据接口(如登录
、查询
等)中携带有datadome
cookie, 并且会返回以下类似响应:
则过掉该验证码需要传{ "url": "https://geo.captcha-delivery.com/captcha/?initialCid=AHrlqAAAAAMAqpOrr0GfIWgAudQ9Vg==&cid=w9vlJ4Xaf117hm82ORPnno7AnVvPPCoZ2gCDLj~Nch09ENObNXSzDWFekvMpp8ScynMSrB3~jsXcFtU9Y8mhOUscfnu1k_a~4_GMyGRE29_Gy~skFDqfX8tQJv1Va5Fv&referer=http%3A%2F%2Fapi-auth.soundcloud.com%2Fweb-auth%2Fidentifier%3Fq%3Desbiya1%2540gmail.com%26client_id%3D1q3v4x1lu3DpcWb4fAz0urivByipMEMK&hash=7FC6D561817844F25B65CDD97F28A1&t=fe&s=48134&e=faa8c1fb03676ac05d3bbe1d876a2d60168a7a2bab3adb5366483fc829465498" }
href
(当前浏览器页面的地址),captcha_url
(响应中的 urlhttps://geo.captcha-delivery.com/captcha/?initialCid=AHrlqAAAAAMAqpOrr0GfIWgAudQ9Vg==&cid=w9vlJ4Xaf117hm82ORPnno7AnVvPPCoZ2gCDLj~Nch09ENObNXSzDWFekvMpp8ScynMSrB3~jsXcFtU9Y8mhOUscfnu1k_a~4_GMyGRE29_Gy~skFDqfX8tQJv1Va5Fv&referer=http%3A%2F%2Fapi-auth.soundcloud.com%2Fweb-auth%2Fidentifier%3Fq%3Desbiya1%2540gmail.com%26client_id%3D1q3v4x1lu3DpcWb4fAz0urivByipMEMK&hash=7FC6D561817844F25B65CDD97F28A1&t=fe&s=48134&e=faa8c1fb03676ac05d3bbe1d876a2d60168a7a2bab3adb5366483fc829465498
) 以及上面所说的无感
模式返回的did
参数必须携带 还有cookies: {"datadome": '无感模式返回的 datadome'}
也就是使用无感模式返回的datadome
cookie 访问你的目标数据接口又继续返回了滑块验证码或者设备验证码模式的话, 则需要携带href
、captcha_url
、did
、cookies
- 打开 f12 查看是否有
- 状态码
403
(设备验证模式
): - 状态码
403
(滑块验证码
):
- 状态码不是
-
简单说就是先请求你目标页面地址, 状态码
200
就走无感模式,403
就走验证码模式, 类似以下伪代码流程:
# 请求目标页面 href resp = session.get(href, headers=headers) # 状态码 200 为无感验证模式, if resp.status_code == 200: res = DatadomeCracker( user_token=USER_TOKEN href=href, user_agent=user_agent, js_url="https://dd.vinted.lt/js", js_key=js_key, proxy=proxy, ).crack() # 状态码 403, 指定 interstitial 为 true, 保证过掉遇到的所有 datadome 验证码模式, 获取最终有效 datadome elif resp.status_code == 403: res = DatadomeCracker( user_token=USER_TOKEN, href=href, user_agent=user_agent, interstitial=True, proxy=proxy, ).crack()
-
版本 | 接口地址 |
---|---|
通用版(universal) |
http://api.nocaptcha.io/api/wanda/datadome/universal |
参数名 | 说明 | 必须 |
---|---|---|
User-Token |
用户密钥, 主页获取 |
是 |
Content-Type |
application/json |
是 |
Developer-Id |
开发者 ID, 开发者用户使用, 用户主页邀请链接的字符串(如 xxx/register?c=abcdef, 则 abcdef 为开发者 ID) |
否 |
参数名 | 类型 | 说明 | 必须 |
---|---|---|---|
href |
String |
触发 datadome 验证的页面地址 |
是 |
proxy |
String |
无需保持代理一致, 若传代理请使用海外代理, 格式请传 ip:port 或 usr:pwd@ip:port (如果有问题联系管理员) |
是 |
js_url |
String |
js 模式下需要传该参数, /js/ 结尾的返回 datadome cookie 的接口, 如: https://dwt.soundcloud.com/js/ |
否 |
js_key |
String |
js 模式下需要传该参数, f12 搜索 ddjskey 值, 如: E6EAF460AA2A8322D66B42C85B62F9 |
否 |
captcha_url |
String |
post(xhr) 接口触发的 "url": "/captcha?initCid=xxx" |
否 |
interstitial |
Boolean |
是否会触发 interstitial 设备验证模式, 默认 false |
否 |
user_agent |
String |
自定义 user_agent, 必须保持 user-agent 一致 |
否 |
did |
String |
js 模式返回的指纹 id(存在 extra 属性中), 后续 xhr 接口出现的滑块验证码请传该参数 |
否 |
cookies |
String |
当前页面的 cookies |
否 |
timeout |
Integer |
验证超时时间 |
否 |
参数名 | 类型 | 说明 |
---|---|---|
status |
Integer |
调用是否成功, 1 成功, 0 失败, 请使用该值判断 |
msg |
String |
调用结果中文说明 |
id |
String |
该次请求 id(唯一, 可用作后续记录查询) |
data.datadome |
String |
验证通过返回的可用的 datadome cookie, 可用于后续验证接口 |
cost |
String |
验证耗时(毫秒) |
{
"status": 1,
"msg": "验证成功",
"id": "639e056b-49bd-4895-94ab-68d59e00873e",
"cost": "4635.12ms",
"data": {
"datadome": "HYvnTVSxppxMMrSk_Z_MOHoSKkQRd2ppQr~pOeo2nDlL7Lg7QBwb2ew5OYQxSSSH1CR9NzO78A25KHM7kLV6OydtvwvJZ773Jil1mPC7ZoFSQQDrDYVeHZtjq_BWUai6"
}
}
pip install -U pynocaptcha -i https://pypi.python.org/simple
from pynocaptcha import DatadomeCracker
cracker = DatadomeCracker(
user_token="xxx",
href="https://soundcloud.com/",
js_url='https://dwt.soundcloud.com/js/',
proxy="user:pass@ip:port",
debug=True,
)
ret = cracker.crack()
print(ret)