12月01, 2021

webdriver反爬破解

最近一个一直在用的网站,发现原来的代码不能正常执行数据抓取。仔细检查了网页中嵌入的加密后的JS代码,在里面找到了一段关于webdriver_evaluateB的代码,推测加密前的代码通过检测window.navigator.webdriver来达到反爬的目的

找到的了原因,马上在网上找到破解webdriver反爬的两个套路:

1. 通过反向代理拦截,改写response的js文件,跳过webdriver检查逻辑

mitmproxy 其实和 fiddler/charles 等抓包工具的原理有些类似,作为一个第三方,它会把自己伪装成你的浏览器向服务器发起请求,服务器返回的 response 会经由它传递给你的浏览器,你可以 通过编写脚本来更改这些数据的传递,从而实现对服务器的 “欺骗” 和对客户端的 “欺骗”

部分网站采用单独的 js 文件来识别 webdriver 的结果,我们可以通过 mitmproxy 拦截识别 webdriver 标识符的 js 文件,并伪造正确的结果。

安装 mitmproxy

安装地址:https://mitmproxy.org/ 可以cefp pipx安装

准备拦截脚本

def response(flow): 
        if '/js/yoda.' in flow.request.url:
        for webdriver_key in ['webdriver', '__driver_evaluate', '__webdriver_evaluate', '__selenium_evaluate', '__fxdriver_evaluate', '__driver_unwrapped', '__webdriver_unwrapped', '__selenium_unwrapped', '__fxdriver_unwrapped', '_Selenium_IDE_Recorder', '_selenium', 'calledSelenium', '_WEBDRIVER_ELEM_CACHE', 'ChromeDriverw', 'driver-evaluate', 'webdriver-evaluate', 'selenium-evaluate', 'webdriverCommand', 'webdriver-evaluate-response', '__webdriverFunc', '__webdriver_script_fn', '__$webdriverAsyncExecutor', '__lastWatirAlert', '__lastWatirConfirm', '__lastWatirPrompt', '$chrome_asyncScriptInfo', '$cdc_asdjflasutopfhvcZLmcfl_' ]:
            ctx.log.info('Remove "{}" from {}.'.format(
            webdriver_key, flow.request.url
            ))  
        flow.response.text = flow.response.text.replace('"{}"'.format(webdriver_key), '"NO-SUCH-ATTR"')  
    flow.response.text = flow.response.text.replace('t.webdriver', 'false')
    flow.response.text = flow.response.text.replace('ChromeDriver', '')

启动mitproxy拦截请求

mitmdump -s DriverPass.py -p 8001

其实,不只是 webdriver,selenium打开浏览器后,还会有这些特征码:

webdriver  
__driver_evaluate  
__webdriver_evaluate  
__selenium_evaluate  
__fxdriver_evaluate  
__driver_unwrapped  
__webdriver_unwrapped  
__selenium_unwrapped  
__fxdriver_unwrapped  
_Selenium_IDE_Recorder  
_selenium  
calledSelenium  
_WEBDRIVER_ELEM_CACHE  
ChromeDriverw  
driver-evaluate  
webdriver-evaluate  
selenium-evaluate  
webdriverCommand  
webdriver-evaluate-response  
__webdriverFunc  
__webdriver_script_fn  
__$webdriverAsyncExecutor  
__lastWatirAlert  
__lastWatirConfirm  
__lastWatirPrompt

2. 利用chrome的旧版本的BUG,禁用webdriver标识

hromeDriver 79.0.3945.36 版本修改了非无头模式下排除 “启用自动化” 时 window.navigator.webdriver 是未定义的问题,要想正常使用,需要把 Chrome 回滚 79 之前的版本,并找到对应的 ChromeDriver 版本,这样才可以!

当然,大家也可以参考 CDP(Chrome Devtools-Protocol) 文档,使用 driver.execute_cdp_cmd 在 selenium 中调用 CDP 的命令。下述代码只需要执行一次,之后只要不关闭这个 driver 开启的窗口,无论打开多少网址,它都会在网站自带的所有 JS 之前执行这个语句,从而达到隐藏 webdriver 的目的。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options


options = Options()
# 隐藏 正在受到自动软件的控制 这几个字
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)

driver = webdriver.Chrome(executable_path=r"E:\chromedriver\chromedriver.exe", options=options)

# 修改 webdriver 值
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
})

driver.get('https://www.baidu.com')

参考文档

本文链接:http://57km.cc/post/crack for anti-webdriver in spider.html

-- EOF --

Comments