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

容器

背景介绍:

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

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

picture.image

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

picture.image

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

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

picture.image

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

webdriver__driver_evaluate__webdriver_evaluate
__fxdriver_unwrapped__fxdriver_evaluate__selenium_evaluate
_Selenium_IDE_Recorder__selenium_unwrapped__driver_unwrapped
calledSelenium_WEBDRIVER_ELEM_CACHE__webdriver_unwrapped
_seleniumdriver-evaluatewebdriver-evaluate
ChromeDriverwselenium-evaluatewebdriverCommand
__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代理,无法正常登录,启动代理后,可以正常登录):

未启动代理的效果:

picture.image

启动代理后的效果:

picture.image

总结

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

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

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

0
0
0
0
关于作者

文章

0

获赞

0

收藏

0

相关资源
vivo 容器化平台架构与核心能力建设实践
为了实现规模化降本提效的目标,vivo 确定了基于云原生理念构建容器化生态的目标。在容器化生态发展过程中,平台架构不断演进,并针对业务的痛点和诉求,持续完善容器化能力矩阵。本次演讲将会介绍 vivo 容器化平台及主要子系统的架构设计,并分享重点建设的容器化核心能力。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论