还是用 headless 浏览器操作 Selenium 过时了,Playwright 是微软的,google 的是 Puppeteer,包装 Chromium 等浏览器给测试等场景用。
一、爬虫基本知识
网站的网页数据有两种呈现方式。
一种是同步加载的。另一种是异步加载的,也即我们常说的用ajax。
如果是同步加载的没有JavaScripts加载数据需求,单独用AngleSharp直接解析网页就可以搞定.
如果是异步加载的有JavaScripts加载数据需求的,就需要上真正的无头浏览器组件才能搞定。
在与反爬虫的对抗中,我们爬虫的大招有两个:
(一)多种ip跟换方式(例如adsl|代理|tor等)。
(二)无头浏览器,使用自动化的技术来进行自动数据抓取,模拟鼠标与键盘事件,可以用于破解验证码,js解析,诡异的模糊数据这类型的反爬虫技术。
(三)浏览器插件
使用的是beautifulsoup+requests 直接对ajax的api爬数据就好了,你所说的爬的url,只是从用户角度来模拟的 上面几位提到的直接查看发起的请求,然后分析请求的规律,猜出请求的接口是如何设计的,这样的话,比爬取HTML页面更快,但是有一个问题,就是有可能人家接口的调用方式你不一定能完全猜测出来,为了更高的成功率(对于我的业务来讲,速度不是最主要的,虽然他也很重要),我使用过两种方式,可以爬取几乎任何网站任何形式的内容。
Chrome 浏览器用来成为我整个爬取的底层技术,我的插件则用来控制浏览器,服务器端发起一次爬取请求,插件收到之后,使用Chrome打开网页,然后直接抓取网页上面的验证码图片,如果我判断出网站是要求手机验证的,那么就直接点击一下发送验证码(插件直接发起一次点击事情),这个时候,服务器端则通知用户端输入(若是图片验证码,客户端也会直接显示出来),然后提交,插件将用户提交的数据填写到打开的网页中,点击提交。 因为网页就是浏览器打开的,所以,爬取任何数据都不是问题了。
(四)Remote Browser
Remote Browser 基于 Web Extensions API 标准构建,是一个使用 JavaScript 以编程方式控制诸如 Chrome 和 Firefox 之类的网络浏览器的库。此前你可能已经听说过类似的浏览器自动化框架,例如 Puppeteer 和 Selenium。
Remote Browser 与这些框架非常相似,它可用于完成与 UI 测试、服务器端渲染(SSR)以及网页抓取相关的各种任务。但不同之处在于它使用标准的跨浏览器兼容技术构建,其主要目标是促进与现有 API 的交互,而不是创建自己新的 API。
下面这段示例代码的作用是导航至选项卡并使用 Remote Browser 进行截图
import Browser from 'remote-browser';
(async () => {
// Create and launch a new browser instance.
const browser = new Browser();
await browser.launch();
// Directly access the Web Extensions API from a remote client.
const tab = await browser.tabs.create({ url: 'https://intoli.com' });
const screenshot = await browser.tabs.captureVisibleTab();
})();var options = new ConnectOptions()
{
BrowserWSEndpoint = $"wss://www.externalbrowser.io?token={apikey}"
};
const browser = await puppeteer.connect({ browserWSEndpoint: 'wss://chrome.browserless.io/' });(五)编程直接控制浏览器
获取当前谷歌安装位置
调用谷歌命令,将html直接打印成pdf并保存成文件方法
c#
https://www.debugger.wiki/article/html/1628426160308886
二、无头浏览器(无界面的浏览器)迭代发展的三个阶段
按出现时间顺序,选最新阶段出现的无头浏览器
第1阶段:PhantomJS
第2阶段:selenium-webdriver
第3阶段:Puppeteer
PuppeteerSharp :for .net
第4阶段:Puppeteer
Microsoft.PlaywrightA web browser without a graphical user interface, controlled programmatically. Used for automation, testing, and other purposes.
PhantomJS(放弃)
早期的无头浏览器王者,但自2017年起已停止维护。其核心引擎(QtWebKit)陈旧,无法适配现代Web标准,已被后续工具完全取代.
在最新版中的 Selenium 中已经不支持 PhantomJS了
selenium-webdriver
它通过驱动各浏览器的原生驱动(如ChromeDriver、geckodriver)来控制真实浏览器。用来模拟浏览器操作(selenium + webdriver)来写爬虫。
浏览器自动化的“老大哥”,支持多语言,速度慢、操作繁琐
Puppeteer
由Google Chrome团队开发,通过DevTools协议直接控制Chromium/Chrome。
Chrome 团队连续放了两个大招 Headless Chrome 和对应的 NodeJS API Puppeteer,直接让 PhantomJS 和 Selenium IDE for Firefox 作者宣布没必要继续维护其产品.
作为selenium+webdriver的优秀替代,ppeteer就是一个很好的选择。
谷歌出品,专注于 Chromium 浏览器,速度快但默认只支持 Chrome/Chromium。
Puppeteer
Puppeteer 是一个通过 DevTools Protocol 控制 headless chrome 的 high-level Node 库,也可以通过设置使用 非 headless Chrome.我们手工可以在浏览器上做的事情 Puppeteer 都能胜任:
生成网页截图或者 PDF
爬取大量异步渲染内容的网页,基本就是人肉爬虫
模拟键盘输入、表单自动提交、UI 自动化测试github:https://github.com/puppeteer/puppeteer
PuppeteerSharp
Puppeteer Sharp是官方Node.JS Puppeteer API的.NET 移植。
作者博客: http://www.hardkoded.com/
项目地址:https://github.com/hardkoded/puppeteer-sharp
Headless Chrome设置教程,chrome无头浏览器(无界面的浏览器),彻底告别phantomjs
chrome发布了Headless Chrome,就是可以实现和phantomjs一样无头浏览器,以后使用selenium chromewebdriver不需要再弹出浏览器。 我也一直在跟踪这个功能,Google花了好长时间找方法才设置成功,现在分享给国内,其实设置很简单(我用的是Python3.6版本):
1:将chrome升级到最新的60版本,只有这个版本或者更新的版本才支持Headless
2:在代码行里设置chrome,加上这行代码即可options.add_argument("--headless") 或者options.add_argument("headless") ,暂时还没看出两者区别。 .
A list of (almost) all headless web browsers in existence
https://www.cnblogs.com/VAllen/p/PuppeteerSharp-AngleSharp-CrawlerSamples.html
Playwright for .NET
由微软官方团队积极维护。
原生支持所有现代渲染引擎:Chromium、Firefox、WebKit。
天生跨浏览器,速度比 Selenium 快,API 设计更现代、好用,已经成了很多自动化和爬虫项目的首选
CloakBrowser
github:https://github.com/CloakHQ/CloakBrowser
CloakBrowser 完全不在这个层面玩。它 fork 了 Chromium 源码,直接在 C++ 层面修改了 49 个位置的代码,重新编译出一个定制的 Chromium 二进制文件。补丁覆盖的范围:
每次启动都会从一个种子生成一套全新的、内部一致的指纹身份——GPU 型号、硬件参数、屏幕尺寸、Canvas/WebGL/Audio 噪声、字体列表全部联动。不是随机拼凑,而是像一个真实的设备配置。
blog:https://www.cnblogs.com/itech/p/20077581
三、反爬虫技术
网站现在反爬虫检测技术:
验证码(CAPTCHA)
行为模式
浏览器指纹 - User-Agent 检查
会话行为
是否人类交互
不是只看“时间间隔”
限流与 IP 封禁
1.爬虫被识别的原因
1.1 特征码的问题
1.1.1 phantomjs (放弃)
phantomjs 会被好些网站自动认作爬虫。因为正常人是不会用这个浏览器的。
1.2.1 selenium(puppeteer也会被识别)
1.2.1 通过辨认一些带有selenium特征的javascript预定义变量来实现的
因为浏览器中的window.navigator.webdriver属性被JS暴露了出来,而被服务器端所识别,触发了服务器的反爬策略,导致爬取失败。
Chrome从v63版本开始添加了这一属性,那么我们就可以使用低于v63版本的Chrome来实现即可(v62.0.3202.62版本测试通过,当然也不要忘了将chromedriver换成对应的版本)这种识别是通过辨认一些带有selenium特征的javascript预定义变量来实现的,且不同的浏览器所能暴露出来的特征不一样。
例如:"window.navigator.webdriver",在非selenium环境下其值为undefined,而在selenium环境下,其值为true。
解决方法1:用的chrome,解决方法是改掉这些变量的名称。
自己下chromedriver的源码,把里面特征变量的名字改掉,然后重新编译,结果似乎是骗过了目标网站。
注意:在此之前你最好不要被网站加入黑名单里,因为你的浏览器有自己独特的指纹可以被追踪。
解决方法2:手动打开浏览器,然后用selenium控制这个浏览器跑程序。
selenium打开浏览器,自己手动操作一样不行。解决方法就是手动打开浏览器,然后用selenium控制这个浏览器跑程序。
总结:用来模拟浏览器操作(selenium + webdriver)来写爬虫。但是稍微有点反爬的网站都会对selenium和webdriver进行识别,被爬网站只需要在前端js添加一下判断脚本,很容易就可以判断出是真人访问还是webdriver。虽然也可以通过中间代理的方式进行js注入屏蔽webdriver检测,但是webdriver对浏览器的模拟操作(输入、点击等等)都会留下webdriver的标记,同样会被识别出来,要绕过这种检测,只有重新编译webdriver,麻烦自不必说,难度不是一般大。
1.2 通过多种技术来实现对机器人的识别
爬虫要用一些调度策略,避免触发机器人识别程序。机器人识别程序有些很简单,比如,根据单位时间内访问的网页数量,有些比较复杂,比如根据访问的网页间关系,还有更复杂的根据监听网页上的事件。
解决办法:
Headers should be similar to common browsers, including :
User-Agent : use a recent one (see https://developers.whatismybrowser.com/useragents/explore/), or better, use a random recent one if you make multiple requests (see https://github.com/skratchdot/random-useragent)
Accept-Language : something like "en,en-US;q=0,5" (adapt for your language)
Accept: a standard one would be like "text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8"
If you make multiple request, put a random timeout between them
If you open links found in a page, set the Referer header accordingly
Images should be enabled
Javascript should be enabled
Check that "navigator.plugins" and "navigator.language" are set in the client javascript page context
Use proxies
传统方案(playwright-stealth、puppeteer-extra-plugin-stealth)的工作方式是在页面加载前注入一段 JS,覆盖 navigator.webdriver、修改 chrome 对象、伪造 Canvas 指纹。问题是:
网站可以在 JS 注入之前就读取指纹
注入的 JS 本身可以被检测到
Chrome 一更新,补丁就失效
四、 undetected chromedrive 技术
1.通过 Chloudflare 反爬虫检测源项目undetected-chromedriver(py)
此项目在近期的 1.5.0 更新中解决了 Cloudflare 的爬虫检测问题。
https://blog.csdn.net/weixin_41951954/article/details/124730933
https://github.com/ultrafunkamsterdam/undetected-chromedriver
2.cloudflare scrape
A simple PHP module to bypass Cloudflare's anti-bot page
https://github.com/Anorov/cloudflare-scrape
为了绕过这个 CloudFlare 开发的 Python 库 cloudflare-scrape
用上它就可以无感爬取使用了 CloudFlare 的网站。
https://cloud.tencent.com/developer/article/1512177
playwright+ocr
传统方案(playwright-stealth、puppeteer-extra-plugin-stealth)的工作方式是在页面加载前注入一段 JS,覆盖 navigator.webdriver、修改 chrome 对象、伪造 Canvas 指纹。问题是:
网站可以在 JS 注入之前就读取指纹
注入的 JS 本身可以被检测到
Chrome 一更新,补丁就失效
CloakBrowser
CloakBrowser 完全不在这个层面玩。它 fork 了 Chromium 源码,直接在 C++ 层面修改了 49 个位置的代码,重新编译出一个定制的 Chromium 二进制文件
CloakBrowser 49 个 C++ 源码级补丁,不是在 JS 层面打补丁,而是从根本上消除了 Chromium 的自动化痕迹。reCAPTCHA v3 拿 0.9,Cloudflare Turnstile 直接过,TLS 指纹和正常 Chrome 一模一样。
| 类别 | 补丁内容 |
|---|---|
| Canvas/WebGL/Audio | 在渲染层注入噪声,指纹每次不同但内部一致 |
| GPU 信息 | vendor/renderer 字符串替换为真实硬件值 |
| 硬件参数 | 屏幕分辨率、CPU 核心数、内存大小全部伪装 |
| Navigator | webdriver=false、plugins.length=5、chrome 对象完整存在 |
| UA 字符串 | 去掉 HeadlessChrome 标识,返回正常 Chrome/146.0.0.0 |
| WebRTC | ICE 候选和 IP 地址自动匹配代理出口 |
| TLS 指纹 | ja3/ja4/Akamai 指纹与正常 Chrome 完全一致 |
| CDP 行为 | 键盘、鼠标、滚轮操作全部人类化 |
| 网络时序 | DNS/连接/SSL 时间归零,Proxy-Connection 头剥离 |
Camoufox 也是 C++ 源码级补丁,但它基于 Firefox,而 CloakBrowser 基于 Chromium。对大多数 Playwright/Puppeteer 用户来说,Chromium 生态的兼容性好得多。
CloakBrowser for .NET
https://github.com/CloakHQ/CloakBrowser/blob/main/dotnet/README.md
五、反爬虫检测方案对比
| 特性 | Playwright | playwright-stealth | undetected-chromedriver | Camoufox | CloakBrowser |
|---|---|---|---|---|---|
| reCAPTCHA v3 | 0.1 | 0.3-0.5 | 0.3-0.7 | 0.7-0.9 | 0.9 |
| Cloudflare Turnstile | 失败 | 偶尔 | 偶尔 | 通过 | 通过 |
| 补丁级别 | 无 | JS 注入 | 配置补丁 | C++(Firefox) | C++(Chromium) |
| Chrome 更新后存活 | — | 经常失效 | 经常失效 | 是 | 是 |
| 维护状态 | 活跃 | 停滞 | 停滞 | 不稳定 | 活跃 |
Useful links
反爬虫中 chrome 无头浏览器的几种检测与绕过方式 chrome 无头浏览器的几种检测方式
前端如何检测 Chrome-Headless 不被爬虫虐
爬虫如何隐藏 Headles-Chrome 不被检测出来
Detecting Headles Chrome(MAKING CHROME HEADLESS UNDETECTABLE)
Can a website detect when you are using Selenium with chromedriver?
IT IS *NOT* POSSIBLE TO DETECT AND BLOCK CHROME HEADLESS
MAKING CHROME HEADLESS UNDETECTABLE
