admin管理员组

文章数量:1130349

1. 引言

许多爬虫初学者在接触到无头浏览器的时候都会有一种如获至宝的感觉,仿佛看到了爬虫的终极解决方案。无论是所有爬虫教程中都会出现的PhantomJS、Selenium,亦或是相对冷门的Nightmare,到后来居上的Puppeteer,都能够作为爬虫工程师的利刃,撕开反爬的一道道屏障。无头浏览器难道就是爬虫的终点了吗?那必然不是,否则各位爬虫工程师就只值3000块一个月了。

首先,无论多强大多轻便的无头浏览器,在同等配置的机器上,并发永远不可能高过python的一行request请求。在大规模数据采集中,服务器成本是必须考虑的问题,采集同样规模的数据,人家服务器成本花了1万块,你给霍霍了十几万,你猜老板会不会问候你老豆。其次,用无头浏览器写过爬虫的人应该都会觉得,很难靠headless browser搞出来一个复杂的、长期稳定的、可靠的大型爬虫,它们更适合应用在一些小规模的数据采集场合。最后,也是最重要的,无头浏览器并不是无敌的,反爬的一方不会乖乖束手就擒,你有张良计,他自然就有过强梯,反爬一方会通过某些方法检测出无头浏览器,然后把这些请求全部处理掉,某些网站你使用无头浏览器甚至无法打开首页。

上段说的最后一点,也就是针对无头浏览器的反爬攻防,就是本文所要讨论的内容。PhantomJS和Selenium已经日薄西山,本文只研究后来居上的Puppeteer。

2. 从蛛丝马迹中认出Puppeteer

2.1 webdriver

介绍

webdriver可以说是Puppeteer最明显的一个特征,检测也非常简单,获取navigator.webdriver这一属性,在默认启动的Puppeteer中,它的值为true,而在正常浏览器中,navigator里是没有这一属性的,是undefined。

await page.evaluateOnNewDocument(() => {
   
   
  Object.defineProperty(navigator, 'webdriver', {
   
   
    get: () => false,
  });
});

简单解释一下这段代码,在新建页面之前,将webdriver的get方法强制返回false。那么类似于if (navigator.webdriver)这样的检测就不会生效了。

var attr = window.navigator, result = [];
do {
   
   
    Object.getOwnPropertyNames(attr).forEach(function(a) {
   
   
        result.push(a)
    })
} while (attr=Object.getPrototypeOf(attr));

这段代码中,获取了navigator中所有属性名,而非属性值,也就是说,即便你把webdriver的值改为false了,这个属性仍然是在的。但是,在正常使用的chrome中,navigator是没有这一属性的,一旦检测到webdriver这个属性名,大概率可以判定为puppeteer。

破盾

破盾就不能针对puppeteer下手了,反正我是没有办法在检测前delete掉navigator.webdriver这个属性。
在发现这段盾的代码后,给它后面注入一点:

result = result.filter(function(item) {
   
   
    return item != "webdriver"
});
<

1. 引言

许多爬虫初学者在接触到无头浏览器的时候都会有一种如获至宝的感觉,仿佛看到了爬虫的终极解决方案。无论是所有爬虫教程中都会出现的PhantomJS、Selenium,亦或是相对冷门的Nightmare,到后来居上的Puppeteer,都能够作为爬虫工程师的利刃,撕开反爬的一道道屏障。无头浏览器难道就是爬虫的终点了吗?那必然不是,否则各位爬虫工程师就只值3000块一个月了。

首先,无论多强大多轻便的无头浏览器,在同等配置的机器上,并发永远不可能高过python的一行request请求。在大规模数据采集中,服务器成本是必须考虑的问题,采集同样规模的数据,人家服务器成本花了1万块,你给霍霍了十几万,你猜老板会不会问候你老豆。其次,用无头浏览器写过爬虫的人应该都会觉得,很难靠headless browser搞出来一个复杂的、长期稳定的、可靠的大型爬虫,它们更适合应用在一些小规模的数据采集场合。最后,也是最重要的,无头浏览器并不是无敌的,反爬的一方不会乖乖束手就擒,你有张良计,他自然就有过强梯,反爬一方会通过某些方法检测出无头浏览器,然后把这些请求全部处理掉,某些网站你使用无头浏览器甚至无法打开首页。

上段说的最后一点,也就是针对无头浏览器的反爬攻防,就是本文所要讨论的内容。PhantomJS和Selenium已经日薄西山,本文只研究后来居上的Puppeteer。

2. 从蛛丝马迹中认出Puppeteer

2.1 webdriver

介绍

webdriver可以说是Puppeteer最明显的一个特征,检测也非常简单,获取navigator.webdriver这一属性,在默认启动的Puppeteer中,它的值为true,而在正常浏览器中,navigator里是没有这一属性的,是undefined。

await page.evaluateOnNewDocument(() => {
   
   
  Object.defineProperty(navigator, 'webdriver', {
   
   
    get: () => false,
  });
});

简单解释一下这段代码,在新建页面之前,将webdriver的get方法强制返回false。那么类似于if (navigator.webdriver)这样的检测就不会生效了。

var attr = window.navigator, result = [];
do {
   
   
    Object.getOwnPropertyNames(attr).forEach(function(a) {
   
   
        result.push(a)
    })
} while (attr=Object.getPrototypeOf(attr));

这段代码中,获取了navigator中所有属性名,而非属性值,也就是说,即便你把webdriver的值改为false了,这个属性仍然是在的。但是,在正常使用的chrome中,navigator是没有这一属性的,一旦检测到webdriver这个属性名,大概率可以判定为puppeteer。

破盾

破盾就不能针对puppeteer下手了,反正我是没有办法在检测前delete掉navigator.webdriver这个属性。
在发现这段盾的代码后,给它后面注入一点:

result = result.filter(function(item) {
   
   
    return item != "webdriver"
});
<

本文标签: 爬虫攻防无头浏览器指南