天天看点

反反爬虫(0) :还在用 selenium 裸爬吗? 你已经被盯上了!破解WebDriver反爬虫

文章目录

    • selenium简介
    • 反爬虫
    • 反反爬虫
      • 配置 Selenium 选项
      • 控制已打开的浏览器
      • mitmproxy中间人
    • 待续...

selenium简介

当我们使用 requests 抓取页面的时候,得到的结果可能会和在浏览器中看到的不一样,正常显示的页面数据,使用 reuquests 却没有得到结果。这是因为 requests 获取的都是原始 HTML 文档,而浏览器中的页面则是经过 Javascript 数据处理后生成的结果,这些数据的来源有多种,可能是通过 AJax 加载的,也可能是经过 Javascript 和特定算法计算后生成的。

此时解决方法通常有两种:

  • 深挖 Ajax 的逻辑,把接口地址和其加密参数构造逻辑完全找出来,再用 Python 复现,构造 Ajax请求
  • 通过模拟浏览器的方式,绕过这个过程。

这里我们主要介绍下第二种方式,模拟浏览器爬取。

Selenium 是一个自动化测试工具,利用它可以驱动浏览器执行特定的操作。比如点击,下拉等操作,同时还可以获取浏览器当前呈现的页面源代码,做到 所见即所得。对于一些使用 Javascript 动态渲染的页面来说,此种抓取方式非常有效!

反反爬虫(0) :还在用 selenium 裸爬吗? 你已经被盯上了!破解WebDriver反爬虫

反爬虫

但是,使用 Selenium 调用 ChromeSriver 来打开网页,还是与正常打开网页有一定的区别的。现在很多网站都加上了对 Selenium 的检测,来防止一些爬虫的恶意爬取。

大多数情况下,检测的基本原理是检测当前浏览器窗口下的

window.navigator

对象是否包含

webdriver

这个属性。在正常使用浏览器的情况下,这个属性是

undefined

,然后一旦我们使用了 selenium,这个属性就被初始化为

true

,很多网站就通过 Javascript 判断这个属性实现简单的反 selenium爬虫。

这时候我们可能想到通过 Javascript 直接把这个 webdriver 属性置空,比如通过调用

execute_script

方法来执行如下代码:

这行 Javascript 的确可以把 webdriver 属性置空,但是 execute_script 调用这行 Javascript 语句实际上是在页面加载完毕之后才执行的,执行得太晚了,网站早在页面渲染之前就已经对 webdriver 属性进行了检测,所有用上述方法并不能达到效果。

反反爬虫

基于上边举例的反爬措施,我们主要可以使用如下方法解决:

配置 Selenium 选项

但是

ChromeDriver 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')
           

另外如下配置也可以去除 webdriver 特征

options = Options()
options.add_argument("--disable-blink-features")
options.add_argument("--disable-blink-features=AutomationControlled")
           

控制已打开的浏览器

既然使用 selenium 打开的浏览器存在一些特定参数,那么我们可以另辟蹊径,直接手动打开一个真实的浏览器,然后再使用 selenium 控制不就可以了吗!

  • 利用 Chrome DevTools 协议打开一个浏览器,它允许客户检查和调试 Chrome 浏览器

    (1)关闭所有打开的 Chrome 窗口

    (2)打开 CMD,在命令行中输入命令:

    # 此处 Chrome 的路径需要修改为你本机的 Chrome 安装位置
    # --remote-debugging-port 指定任何打开的端口
    "C:\Program Files(x86)\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222
               
    若路径正确,此时会打开一个新的 Chrome 窗口
  • 使用 selenium 连接这个打开的 Chrome 窗口
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    
    options = Options()
    # 此处端口需要与上一步中使用的端口保持一致
    # 其它大多博客此处使用 127.0.0.1:9222, 经测试无法连接, 建议采用 localhost:9222
    # 具体原因参见: https://www.codenong.com/6827310/
    options.add_experimental_option("debuggerAddress", "localhost:9222")
    
    driver = webdriver.Chrome(executable_path=r"E:\chromedriver\chromedriver.exe", options=options)
    
    driver.get('https://www.baidu.com')
               

但是使用本方法也存在一些弊端:

浏览器一旦启动,selenium中对浏览器的配置就不在生效了,例如

–-proxy-server

等,当然你也可以一开始启动 Chrome 的时候就加上

mitmproxy中间人

mitmproxy

其实和

fiddler/charles

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

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

参考:使用 mitmproxy + python 做拦截代理

待续…

其实,不只是 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
...
           

如果你不相信,我们可以来做一个实验,分别使用 正常浏览器,

selenium+Chrome

selenium+Chrome headless

打开这个网址:https://bot.sannysoft.com/

反反爬虫(0) :还在用 selenium 裸爬吗? 你已经被盯上了!破解WebDriver反爬虫

当然,这些例子并不是为了打击各位的自信,仅仅是希望大家不要学会了部分技术就开始沾沾自喜,时刻保持一颗赤子之心,怀着对技术的热情继续前进。爬虫与反爬虫这场没有硝烟的战争,还在继续 …