以淘宝为例教你如何突破网站对selenium的屏蔽

背景介绍:

一般情况下,访问网站都会消耗服务器的资源。而机器人可以做到比人更快的访问速度,更持续的访问时间,这对网站资源占用消耗是远远超过人的,而当服务器资源被大量占用的时候, 就不能为人提供正常的网络服务。而且机器人一般是直接获取需要的数据,不加载不必要的的信息,速度大大超过人的浏览速度。例如很多网站都有图片,甚至广告,加载都需要时间。一个视频网站,好几年了几万条的数据,半个小时采集完成。这种高频率的访问,服务器就得满负荷工作,带宽也会被占据,最后别人要访问就会受限制。基于这样的一个背景下,很多网站会对一些自动化的工具去访问网页作出一些检测,并限制别人通过脚本的方式去进行访问。

比如,通过selenium去操作淘宝首页,去登录。再不做任何处理的情况下,你会发现,每次输入完账号密码之后,都会弹出一个要输入验证的框:

以淘宝为例教你如何突破网站对selenium的屏蔽

不同的网站,需要验证的信息可能不一样,有的可能是需要输入验证码,或者进行什么人机验证之类的,你可能会想,那就滑动一下进行验证就好了,事实上,这种被识别为自动化的脚本进行访问的,验证之后也出报错或者出现其他未知的异常:

以淘宝为例教你如何突破网站对selenium的屏蔽

 

网站是如何检测出来是机器人在操作的呢?

selenium在运行的时候会暴露出一些预定义的Javascript变量(特征字符串),例如"window.navigator.webdriver",在非selenium环境下其值为undefined,而在selenium环境下,其值为true(如下图所示为selenium驱动下Chrome控制台打印出的值)。

以淘宝为例教你如何突破网站对selenium的屏蔽

 

除此之外,还有一些其它的标志性字符串(不同的浏览器可能会有所不同),常见的特征串如下所示:

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

了解了这个特点之后,就可以在浏览器客户端JS中通过检测这些特征串来判断当前是否使用了selenium,并将检测结果附加到后续请求之中,这样服务端就能识别并拦截后续的请求。

 

如何绕过网站的这个验证呢?

在微信群看到有人在问怎么绕过这个验证,然后往上查了一下资料,大部分给的方案是:

在启动浏览器的时候加上一些配置,比如:

 

option = webdriver.ChromeOptions()option.add_experimental_option("excludeSwitches", ['enable-automation'])driver = webdriver.Chrome(chrome_options=option)

试过了,发现不行,还有的说让手动把webdriver的属性设置为undefined:


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

发现这样设置之后,也并不能解决登陆淘宝网站的问题(或许不同网站的校验规则不一样,有的只是做了简单校验,淘宝的校验复杂点吧)。

最终,在网上查到了另一种方式,使用python的mitmproxy库进行操作。

顾名思义,mitmproxy 就是用于 MITM 的 proxy,MITM 即中间人***(Man-in-the-middle attack)。用于中间人***的代理首先会向正常的代理一样转发请求,保障服务端与客户端的通信,其次,会适时的查、记录其截获的数据,或篡改数据,引发服务端或客户端特定的行为。

使用 pip install mitmproxy 

新建一个py文件,命名随意,这里命名为modify_response.py

# coding: utf-8
# modify_response.py

from mitmproxy import ctx


def response(flow):
    """修改响应数据
    """
    if '/js/yoda.' in flow.request.url:
        # 屏蔽selenium检测
        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"')
            print(webdriver_key)
        flow.response.text = flow.response.text.replace('t.webdriver', 'false')
        flow.response.text = flow.response.text.replace('ChromeDriver', '')

然后运行脚本:

mitmdump.exe -p 端口号  -s modify_response.py

然后再执行selenium的脚本即可实现正常的通过selenium进行登录淘宝网站,之前设置的ChromeOptions也要加上。具体代码如下:

from selenium import webdriver
from time import sleep

option = webdriver.ChromeOptions()
option.add_experimental_option("excludeSwitches", ['enable-automation'])

driver = webdriver.Chrome(chrome_options=option)
driver.maximize_window()
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
   "source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})""",
})
driver.get('https://www.taobao.com/')
driver.find_element_by_link_text('亲,请登录').click()
sleep(2)
driver.find_element_by_xpath('//input[@name="fm-login-id"]').send_keys('淘宝用户名')
sleep(2)
driver.find_element_by_xpath('//input[@name="fm-login-password"] ').send_keys('对应的密码')
sleep(2)
driver.find_element_by_xpath('//div[@class="fm-btn"]').click()
sleep(10)
#driver.quit()

效果演示(会运行2次脚本,第一次运行脚本时没有启动mitmproxy代理,无法正常登录,启动代理后,可以正常登录):

未启动代理的效果:

以淘宝为例教你如何突破网站对selenium的屏蔽

 

启动代理后的效果:

以淘宝为例教你如何突破网站对selenium的屏蔽

 

总结

1、百度到的方法解决不了我们遇到的问题的时候,如何去解决?百度到的结果有时候只能为我们提供一个思路,尽量多看发帖时间在最近的,有的只是拿着以前别人写的东西copy一下,没有自己去实战过 ,并不一定能帮你解决问题,但是思路也许是对的

2、业务这边文章中的操作可以解决登录淘宝的问题,但或许不能解决所有的场景,需要针对不同的网站做些适当的调整,至于mitmproxy到底是什么,具体用法怎么用,为什么这么用 ,这里就不仔细介绍。

3、我觉得IT行业是一个更新换代非常快的行业,不管从事哪个岗位,培养一定的自学能力和解决问题的能力很重要,前辈们虽为我们总结和积累了很多经验,可以让我们少走一些弯路,但能够掌握解决问题的思路和方法更重要。

上一篇:hello world.java


下一篇:MATLAB 求解特征方程的根轨迹图稳定性分析