【python爬虫】selenium骚操作:模拟用户行为获取百度翻译的token、BAIDUID、yjs

    技术2022-07-11  97

    前情提要

    爬过百度翻译的朋友们应该都知道: 百度翻译的 sign 参数破解需要一些逆向能力,已经有很多大神讲了,我就不重复了。破解 sign 后还可能遇到另一个问题:同一个 token 和 cookie 可翻译的次数有限,次数过多时会触发百度的反爬机制。 大规模调用的时候需要更多的 token 和 cookie 。

    那么需求来了:我们需要一个 token 和 cookie 池。 发送请求的时候,User-Agent、cookie、token三个值缺一不可。 cookie中最重要的两个值是:BAIDUID、yjs_js_security_passport。 yjs_js_security_passport 的构造机制比较复杂,是由很多函数经过加密处理过的,逆向能力较弱的小伙伴只能缴枪投降。

    换个思路,既然 User-Agent 不变,我们可以试试用 selenium 看能不能直接读取到 token 和 cookie。

    开启浏览器

    from selenium import webdriver from selenium.webdriver.chrome.options import Options import time import requests import re #以下三行为无头模式运行,无头模式不开启浏览器,也就是在程序里面运行的 # chrome_options = Options() # chrome_options.add_argument("--headless") # browser = webdriver.Chrome(executable_path=(r'C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe'), options=chrome_options) #以下一行为有头模式运行,开启浏览器,在程序外面运行的。 #executable_path请放自己的chromedriver.exe路径 browser = webdriver.Chrome(executable_path=(r'C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe')) url = "https://fanyi.baidu.com" browser.get(url)

    获取token

    我们发现token值可以在源代码中直接获取。 因为在<script>标签中,所以我们用正则表达式提取:

    #获取token token = re.findall(r"token: '(.*?)'", browser.page_source)[0] print('token = ', token)

    获取cookie

    可以用 browser.get_cookies() 方法获取cookie

    #获取cookie cookie_items = browser.get_cookies() print(cookie_items)

    cookie_items 数据类型如下:cookie名存储在 ‘name’ 中,cookie值存储在 ‘value’ 中。

    [ {'domain': '.fanyi.baidu.com', 'expiry': 1625133859, 'httpOnly': False, 'name': 'Hm_lvt_64ecd82404c51e03dc91cb9e8c025574', 'path': '/', 'secure': False, 'value': '1593597860'}, {'domain': '.baidu.com', 'expiry': 1593770659, 'httpOnly': False, 'name': '__yjsv5_shitong', 'path': '/', 'secure': False, 'value': '1.0_7_3a72b0201970664024201a227cd1a3ef5b6f_300_1593597859671_42.120.72.105_b3aeb0f3'}, {'domain': 'fanyi.baidu.com', 'expiry': 1679997859, 'httpOnly': False, 'name': 'SOUND_PREFER_SWITCH', 'path': '/', 'secure': False, 'value': '1'}, {'domain': 'fanyi.baidu.com', 'expiry': 1679997859, 'httpOnly': False, 'name': 'REALTIME_TRANS_SWITCH', 'path': '/', 'secure': False, 'value': '1'}, {'domain': 'fanyi.baidu.com', 'expiry': 1679997859, 'httpOnly': False, 'name': 'SOUND_SPD_SWITCH', 'path': '/', 'secure': False, 'value': '1'}, {'domain': 'fanyi.baidu.com', 'expiry': 1679997859, 'httpOnly': False, 'name': 'HISTORY_SWITCH', 'path': '/', 'secure': False, 'value': '1'}, {'domain': '.fanyi.baidu.com', 'httpOnly': False, 'name': 'Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574', 'path': '/', 'secure': False, 'value': '1593597860'}, {'domain': 'fanyi.baidu.com', 'expiry': 1679997859, 'httpOnly': False, 'name': 'FANYI_WORD_SWITCH', 'path': '/', 'secure': False, 'value': '1'}, {'domain': '.baidu.com', 'expiry': 1625133858, 'httpOnly': False, 'name': 'BAIDUID', 'path': '/', 'secure': False, 'value': 'FAE67AC784551906C5007293413E0DF5:FG=1'} ]

    我们把完整的cookie字段拼接一下:

    #组装cookie字符串 cookie_str = "" for item_cookie in cookie_items: item_str = item_cookie["name"]+"="+item_cookie["value"]+"; " cookie_str += item_str print('cookie = ', cookie_str) cookie = Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1593597860; __yjsv5_shitong=1.0_7_3a72b0201970664024201a227cd1a3ef5b6f_300_1593597859671_42.120.72.105_b3aeb0f3; SOUND_PREFER_SWITCH=1; REALTIME_TRANS_SWITCH=1; SOUND_SPD_SWITCH=1; HISTORY_SWITCH=1; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1593597860; FANYI_WORD_SWITCH=1; BAIDUID=FAE67AC784551906C5007293413E0DF5:FG=1;

    模拟用户行为

    按照上面的代码,我们获得了 token 和 cookie。但是 cookie 中并不含 yjs_js_security_passport,这是为什么呢? 我们猜测是只打开了网页,并没有 ‘翻译’ 的动作,才没有生成 yjs_js_security_passport。 接下来我们模拟一下用户的真实动作。

    #在输入框输入‘test’,然后点击‘翻译’按键 browser.find_element_by_xpath("//*[@id='baidu_translate_input']").send_keys("test") time.sleep(1) browser.find_element_by_xpath("//*[@id='translate-button']").click() time.sleep(1)

    果不其然,我们得到了 yjs_js_security_passport。

    token = 9b8bb341109338ba7e875bd9a9dd88ba cookie = yjs_js_security_passport=aa994f15dc218dba1a732d1185d8f6f93ecc10b9_1593599172_js; HISTORY_SWITCH=1; FANYI_WORD_SWITCH=1; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1593599169; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1593599169; __yjsv5_shitong=1.0_7_e812f76cb8c9ac4d0b646ada6f3f9f38548f_300_1593599170022_42.120.72.105_4272f097; SOUND_PREFER_SWITCH=1; SOUND_SPD_SWITCH=1; REALTIME_TRANS_SWITCH=1; BAIDUID=9FC8D8494F2ABEC8540D36AA87919AA1:FG=1;

    然后我兴高采烈的拿着token、cookie、User-Agent、sign去模拟请求百度翻译了。 但是!返回错误:error:998。

    冷静分析

    error:997 是 sign 参数计算错误。 error:998 是 token、cookie、User-Agent、sign 不对应错误。 cookie 是直接获取的;User-Agent 一直不变,sign 计算值没有错。 那只能是 token 没有获取正确。 回退到模拟用户行为那一步,我发现点击 ‘翻译’ 按钮后,网页并没有出现正常的翻译结果! selenium 点击翻译后,右侧依旧是空白。 我猜这应该是百度翻译对 selenium 的识别。(百度真棒) 但是在这个情况下,我手动点击了一下 ‘翻译’ 按钮,发现整个页面刷新了一下!刷新了一下!刷新了一下!(重要的事情说三遍)然后再输入 ‘test’ 就可以正常显示结果了!

    骚操作来了

    我们可以在一开始加载完页面的时候就刷新一次! 我们可以在一开始加载完页面的时候就刷新一次! 我们可以在一开始加载完页面的时候就刷新一次! 不就能正常访问页面了么?! selenium 刷新页面是用 refresh() 方法,代码如下:

    #模仿人类行为欺骗浏览器 browser.refresh() time.sleep(1) browser.find_element_by_xpath("//*[@id='baidu_translate_input']").send_keys("test") time.sleep(1) browser.find_element_by_xpath("//*[@id='translate-button']").click() time.sleep(1)

    激动人心的时刻到了,我们得到了真实的 token !鼓掌 ~ ~

    token = d4097247f1dbb4b6cb402997af0d83b4 cookie = yjs_js_security_passport=bd599955dc8342fd96fbdb7646fb388194da2b82_1593600965_js; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1593600963; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1593600961; __yjsv5_shitong=1.0_7_71d0d2e0248f50163b158f1be6eef5fb59e7_300_1593600962749_42.120.72.105_264a785b; SOUND_PREFER_SWITCH=1; SOUND_SPD_SWITCH=1; REALTIME_TRANS_SWITCH=1; BAIDUID=EBBC5244ED06FB5222636C1A75C13D7C:FG=1;

    并且每次运行得到的 token 和 cookie 都不一样。 nice,接下来就可以建立一个自己的 token 和 cookie 池了。

    愿大家前程似锦,加油!

    Processed: 0.011, SQL: 9