webdriver break

  1. # coding: utf-8  
    # modify_response.py  
      
    import re  
    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"')  
          flow.response.text = flow.response.text.replace('t.webdriver', 'false')  
          flow.response.text = flow.response.text.replace('ChromeDriver', '')  

 

 

 

 

2----------------------------------------------->>>>>>>>>>>>>>>>>>>>>>>>>>

elenium_绕过检测机制_2

2019年02月19日 17:32:16 进击的rookie of python 阅读数:182

一行js代码识别Selenium+Webdriver及其应对方案

有不少朋友在开发爬虫的过程中喜欢使用Selenium + Chromedriver,以为这样就能做到不被网站的反爬虫机制发现。

先不说淘宝这种基于用户行为的反爬虫策略,仅仅是一个普通的小网站,使用一行Javascript代码,就能轻轻松松识别你是否使用了Selenium + Chromedriver模拟浏览器。

我们来看一个例子。

使用下面这一段代码启动Chrome窗口:

 
  1. from selenium.webdriver import Chrome

  2.  
  3. driver = Chrome()

现在,在这个窗口中打开开发者工具,并定位到Console选项卡,如下图所示。

 

webdriver break

 

 

现在,在这个窗口输入如下的js代码并按下回车键:

window.navigator.webdriver

可以看到,开发者工具返回了true。如下图所示。

 

webdriver break

 

 

但是,如果你打开一个普通的Chrome窗口,执行相同的命令,可以发现这行代码的返回值为undefined,如下图所示。

 

webdriver break

 

 

所以,如果网站通过js代码获取这个参数,返回值为undefined说明是正常的浏览器,返回true说明用的是Selenium模拟浏览器。一抓一个准。这里给出一个检测Selenium的js代码例子:

 
  1. webdriver = window.navigator.webdriver;

  2. if(webdriver){

  3. console.log('你这个傻逼你以为使用Selenium模拟浏览器就可以了?')

  4. } else {

  5. console.log('正常浏览器')

  6. }

  7. 复制代码

网站只要在页面加载的时候运行这个js代码,就可以识别访问者是不是用的Selenium模拟浏览器。如果是,就禁止访问或者触发其他反爬虫的机制。

那么对于这种情况,在爬虫开发的过程中如何防止这个参数告诉网站你在模拟浏览器呢?

可能有一些会js的朋友觉得可以通过覆盖这个参数从而隐藏自己,但实际上这个值是不能被覆盖的:

 

webdriver break

 

 

对js更精通的朋友,可能会使用下面这一段代码来实现:

Object.defineProperties(navigator, {webdriver:{get:()=>undefined}});

运行效果如下图所示:

 

webdriver break

 

 

确实修改成功了。这种写法就万无一失了吗?并不是这样的,如果此时你在模拟浏览器中通过点击链接、输入网址进入另一个页面,或者开启新的窗口,你会发现,window.navigator.webdriver又变成了true。如下图所示。

 

webdriver break

 

 

那么是不是可以在每一个页面都打开以后,再次通过webdriver执行上面的js代码,从而实现在每个页面都把window.navigator.webdriver设置为undefined呢?也不行。

因为当你执行:driver.get(网址)的时候,浏览器会打开网站,加载页面并运行网站自带的js代码。所以在你重设window.navigator.webdriver之前,实际上网站早就已经知道你是模拟浏览器了。

接下来,又有朋友提出,可以通过编写Chrome插件来解决这个问题,让插件里面的js代码在网站自带的所有js代码之前执行。

这样做当然可以,不过有更简单的办法,只需要设置Chromedriver的启动参数即可解决问题。

在启动Chromedriver之前,为Chrome开启实验性功能参数excludeSwitches,它的值为['enable-automation'],完整代码如下:

 
  1. from selenium.webdriver import Chrome

  2. from selenium.webdriver import ChromeOptions

  3.  
  4. option = ChromeOptions()

  5. option.add_experimental_option('excludeSwitches', ['enable-automation'])

  6. driver = Chrome(options=option)

此时启动的Chrome窗口,在右上角会弹出一个提示,不用管它,不要点击停用按钮。

再次在开发者工具的Console选项卡中查询window.navigator.webdriver,可以发现这个值已经自动变成undefined了。并且无论你打开新的网页,开启新的窗口还是点击链接进入其他页面,都不会让它变成true。运行效果如下图所示。

 

webdriver break

 

 

截至 2019 年 2 月 12 日 20:46 分,本文所讲的方法可以用来登录知乎。如果使用 Selenium 直接登录知乎,会弹出验证码;先使用本文的方法再登录知乎,能够成功伪装成真实的浏览器,不会弹出验证码。

实际上,Selenium + Webdriver能被识别的特征不止这一个。关于如何隐藏其他特征,请关注我的微信公众号。

webdriver break

-------------------------------------------->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

selenium + chromedriver 被反爬的解决方法

2018年09月01日 12:57:19 黑蚂蚁 阅读数:9007

问题背景:这个问题是在爬取某夕夕商城遇到的问题,原本的方案是用selenium + chromedriver + mitmproxy开心的刷,但是几天之后,发现刷不出来了,会直接跳转到登陆界面(很明显,是遭遇反爬了)

讲实话,这还是第一次用硒被反爬的,于是进行大规模的测试对比。 

同台机器,用铬浏览器正常访问是不用跳转到登陆界面的,所以不是IP的问题。再用提琴手抓包对比了一下两个请求头,请求头都是一样的,所以忽略标头的反爬。

最后通过分析,可能是硒被检测出来了。于是就去查资料。大概的查到是和webdriver的有关系的。因为这个在服务端是可以检测到的。于是通过fiddler抓包,全局搜索了一下webdriver,发现在js中果然是有判断的。导致selenium爬取的时候,被转到登陆界面。

 

解决方法:mitmproxy

因为mitmproxy可以拦截请求,所以在响应中,将包含的webdriver的JS中的关键字替换成其他的字符就可以了。

 
  1. if "/_next/static/js/common_pdd" in flow.request.url:

  2. flow.response.text = flow.response.text.replace("webdriver", "userAgent")

我是这样替换的。这样js解析的参数就变了,问题花刃而解。可以正常爬取数据了。

 

另外国外网上也有很多方法,比如修改webdriver里的一些特定参数名称,我尝试了一下,没有生效。 

这篇这是暂时记录一下,之后的博客里,会详细的写解决流程!!

 

----------------------------------------------------------------->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

如何突破网站对selenium的屏蔽

2018年10月23日 15:13:25 半吊子Py全栈工程师 阅读数:4489

使用selenium模拟浏览器进行数据抓取无疑是当下最通用的数据采集方案,它通吃各种数据加载方式,能够绕过客户JS加密,绕过爬虫检测,绕过签名机制。它的应用,使得许多网站的反采集策略形同虚设。由于selenium不会在HTTP请求数据中留下指纹,因此无法被网站直接识别和拦截。

这是不是就意味着selenium真的就无法被网站屏蔽了呢?非也。selenium在运行的时候会暴露出一些预定义的Javascript变量(特征字符串),例如"window.navigator.webdriver",在非selenium环境下其值为undefined,而在selenium环境下,其值为true(如下图所示为selenium驱动下Chrome控制台打印出的值)。

webdriver break

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

  1. webdriver  
  2. __driver_evaluate  
  3. __webdriver_evaluate  
  4. __selenium_evaluate  
  5. __fxdriver_evaluate  
  6. __driver_unwrapped  
  7. __webdriver_unwrapped  
  8. __selenium_unwrapped  
  9. __fxdriver_unwrapped  
  10. _Selenium_IDE_Recorder  
  11. _selenium  
  12. calledSelenium  
  13. _WEBDRIVER_ELEM_CACHE  
  14. ChromeDriverw  
  15. driver-evaluate  
  16. webdriver-evaluate  
  17. selenium-evaluate  
  18. webdriverCommand  
  19. webdriver-evaluate-response  
  20. __webdriverFunc  
  21. __webdriver_script_fn  
  22. __$webdriverAsyncExecutor  
  23. __lastWatirAlert  
  24. __lastWatirConfirm  
  25. __lastWatirPrompt  
  26. $chrome_asyncScriptInfo  
  27. $cdc_asdjflasutopfhvcZLmcfl_  

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

下面讲一个具体的例子。

鲲之鹏的技术人员近期就发现了一个能够有效检测并屏蔽selenium的网站应用:大众点评网的验证码表单页,如果是正常的浏览器操作,能够有效的通过验证,但如果是使用selenium就会被识别,即便验证码输入正确,也会被提示“请求异常,拒绝操作”,无法通过验证(如下图所示)。

webdriver break

分析页面源码,可以找到 https://static.meituan.net/bs/yoda-static/file:file/d/js/yoda.e6e7c3988817eb17.js 这个JS文件,将代码格式化后,搜索webdriver可以看到如下代码:

webdriver break

 可以看到它检测了"webdriver", "__driver_evaluate", "__webdriver_evaluate"等等这些selenium的特征串。提交验证码的时候抓包可以看到一个_token参数(很长),selenium检测结果应该就包含在该参数里,服务端借以判断“请求异常,拒绝操作”。

现在才进入正题,如何突破网站的这种屏蔽呢?

我们已经知道了屏蔽的原理,只要我们能够隐藏这些特征串就可以了。但是还不能直接删除这些属性,因为这样可能会导致selenium不能正常工作了。我们采用曲线救国的方法,使用中间人代理,比如fidder, proxy2.py或者mitmproxy,将JS文件(本例是yoda.*.js这个文件)中的特征字符串给过滤掉(或者替换掉,比如替换成根本不存在的特征串),让它无法正常工作,从而达到让客户端脚本检测不到selenium的效果。

下面我们验证下这个思路。这里我们使用mitmproxy实现中间人代理),对JS文件(本例是yoda.*.js这个文件)内容进行过滤。启动mitmproxy代理并加载response处理脚本:

  1. mitmdump.exe -S modify_response.py  

其中modify_response.py脚本如下所示:

view plaincopy to clipboardprint?

# coding:utf-8
# modify_response.py

import re
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"')
            flow.response.text=flow.response.text.replace('t.webdriver','false')
            flow.response.text=flow.response.text.replace('ChromeDriver','')

在selnium中使用该代理(mitmproxy默认监听127.0.0.1:8080)访问目标网站,mitmproxy将过滤JS中的特征符串,如下图所示:

webdriver break

经多次测试,该方法可以有效的绕过大众点评的selenium检测,成功提交大众点评网的验证码表单。

转载自:http://www.site-digger.com/html/articles/20180821/653.html

 

selenium爬虫被检测到 解决方法

    2019年2月13日 18:21   459 人阅读  0 条评论

本人之前在做X宝,X评,X团的爬虫项目时,均遇到了获取cookies这个重要的问题,而获取cookies的前提是实现用户登录,登陆的过程就不赘述了,相信大家都遇到了滑块,滚动条等反爬手段,(本人用webdriver**),可大厂的技术团队还是给了我们一个更难解决的问题,就是通过js给webdriver请求响应错误信息。那我们的思考路线就是如何让这个js文件功能作废,本人使用的方法是通过 mitmproxy 蔽掉识别 webdriver 标识符的 js 文件。 首先下载mitproxy,pip安装方法:

  pip install mitmproxy

基本使用方法:

给本机设置代理ip 127.0.0.1端口8001(为了让所有流量走mitmproxy)具体方法请百度。

2. 启动mitmproxy。

windows:

mitmdump -p 8001

Linux:

mitmproxy -p 8001

3. 打开chrome的开发者工具,找到目标网站是通过哪个js文件控制webdriver相应的, 如:

webdriver break

4. 开始写干扰脚本(DriverPass.py):

import re
from mitmproxy import ctx

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

5. 退出刚才的mitmproxy状态,重新用命令行启动mitmproxy干扰脚本 监听8001端口的请求与响应。

mitmdump -s DriverPass.py -p 8001

 

6. 现在别管mitmproxy,启动webdriver 顺利获得cookies。

 

 

 

反爬虫中chrome无头浏览器的几种检测与绕过方式

2018年08月18日 02:06:34 FserSuN 阅读数:7060

chrome无头浏览器的几种检测方式

本文测试使用的chrome版本为 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3514.2 Safari/537.36

1.UserAgent检测

无头模式下的UA会带有HeadlessChrome关键字

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/70.0.3521.2 Safari/537.36
  • 1

因此可以检查UA中的关键字

if (/HeadlessChrome/.test(navigator.userAgent)) {
  // headless...
}
  • 1
  • 2
  • 3

2.Webdriver检测

无头模式下navigator.webdriver为true,因此可以进行如下检测。

// Webdriver Test
if (navigator.webdriver) {
  // headless...
}
  • 1
  • 2
  • 3
  • 4

为了绕过这个检测,重新设置该属性即可。

Object.defineProperty(navigator, 'webdriver', {
    get: () => false,
  });
  • 1
  • 2
  • 3

补充说明:大麦网或淘宝网的滑块验证码首先就会检测环境,
通常会利用sufei_data文件检测当前浏览器信息,其中检测webdriver代码如下

        function r() {
            return "$cdc_asdjflasutopfhvcZLmcfl_"in u || f.webdriver
        }
        
// 完整的检测代码,这个文件会经常升级        
// https://g.alicdn.com/secdev/sufei_data/3.6.8/index.js
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

因此在尝试拖动滑块的时候,先要修改该属性。不然如何修改路径都会提示错误,并要求重试。

3.chrome属性检测

在无头模式下window.chrome属性是undefined,而在正常有界面模式下,定义如下。

csi: ƒ ()
embeddedSearch: {searchBox: {…}, newTabPage: {…}}
loadTimes: ƒ ()
app: (...)
runtime: (...)
webstore: (...)
get app: ƒ nativeGetter()
set app: ƒ nativeSetter()
get runtime: ƒ nativeGetter()
set runtime: ƒ nativeSetter()
get webstore: ƒ nativeGetter()
set webstore: ƒ nativeSetter(
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

因此可以进行如下形式检测

if (!window.chrome || !window.chrome.runtime) {
  // headless...
}
  • 1
  • 2
  • 3

绕过检测修改属性即可

 window.navigator.chrome = {
    runtime: {},
    // etc.
  };
  • 1
  • 2
  • 3
  • 4

4.Permissions检测

(async () => {
  const permissionStatus = await navigator.permissions.query({ name: 'notifications' });
  if(Notification.permission === 'denied' && permissionStatus.state === 'prompt') {
    // headless
  }
})();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

无头模式下Notification.permission与navigator.permissions.query会返回相反的值。
因此绕过的方式如下。

// Pass the Permissions Test.
await page.evaluateOnNewDocument(() => {
  const originalQuery = window.navigator.permissions.query;
  return window.navigator.permissions.query = (parameters) => (
    parameters.name === 'notifications' ?
      Promise.resolve({ state: Notification.permission }) :
      originalQuery(parameters)
  );
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

5. Plugins长度检测

无头模式下navigator.plugins.length返回0

if (navigator.plugins.length === 0) {
  // headless
}
  • 1
  • 2
  • 3

绕过方式如下

Object.defineProperty(navigator, 'plugins', {
    get: () => [1, 2, 3, 4, 5],
  });
  • 1
  • 2
  • 3

注意:反爬除了检查长度,还会检查内容。如果你设置了长度,别忘了再设置内容。防止被反爬。

6.The Languages检测

navigator.languages检测方法

if (!navigator.languages || navigator.languages.length === 0) {
  // headless
}
  • 1
  • 2
  • 3

绕过方法

  Object.defineProperty(navigator, 'languages', {
    get: () => ['en-US', 'en'],
  });
  • 1
  • 2
  • 3

7.原文地址

https://intoli.com/blog/not-possible-to-block-chrome-headless/