Contents

绕过 Cloudflare 保护进行全站爬取——使用 Cyotek WebCopy + Fiddler

前言

Cloudflare作为一个CDN服务商,它最有存在感的时候(也是最令人反感的时候)就是浏览网站时蹦出它的DDoS保护页面了。一般情况下倒还好,顶多像下图中的页面一样,留人片刻。在某些特殊网络环境中,或进行一些特殊操作(比如本文中,我们准备搞的爬虫)时,Cloudflare会强制用户输入图形验证码,而且最近还从谷歌的reCaptcha切换到了自家的hCaptcha1,原因是嫌reCaptcha要钱。更新之后,一些开源的Cloudflare反反爬虫方案234也全都凉了,其中NodeJS库3的作者直接表示弃更,把项目的Github仓库设置为归档模式了。

/zh/2020/scraping-cloudflare-with-webcopy/00.png

但开源项目投降了咱们不能投降,工作需要哇。结合各个爬虫工具的优劣和特点,同时鉴于作者本人很懒——倾向于选择带GUI界面的工具,因此最后决定采用 Cyotek WebCopy 加 Fiddler 作为爬虫实现方案,前者负责任务调度,后者负责关键请求参数、返回内容的预处理、后处理。

本文以资源网站 https://b4ckdoorarchive.club/HELL-ARCHIVE 作为例子,演示如何使用Cyotek WebCopy 方便快速的创建一个爬虫任务,并通过 Fiddler 脚本控制爬虫的请求、返回行为,通过半自动的方式爬取一个受 Cloudflare 保护的资源网站。

技术选型

我知道,如果是我自己看到这篇文章,看完上面一段我就会马上抄起键盘开始bb,为什么不用xxxxx和xxxxx?下面我就列举我所了解的一些同类替代品,讲一讲在本文特定需求下,这些工具存在的优点和最终否决它们的原因。

做一个爬虫我们需要两个功能组件。一是任务调度,负责网站目录扫描、Web请求的触发、下载文件的组织与存储。二是请求构造,在这里我们指的是:通过HTTP代理、中间件等各种方式,在Web请求发送、返回Web响应前后,对数据内容进行修改。针对我们的需求(套了Cloudflare的网站),这里存在额外工作量:利用浏览器解码 JS captcha,并将鉴权结果Cookie塞到每一个请求中,并在Cookie过期时处理错误状态。现在我们已知,没有自动化脚本可以完成这个工作,因此我们需要手动在浏览器中解captcha,并将cookie及时填回到爬虫中,这个手动过程可能需要完成3~4次。

当然,一些框架可以同时完成这两件工作,比如scrapy。但我们还是一步一步分开来讲。

任务调度组件:

Cyotek WebCopy(最终选择)

  • 优点:
    • GUI,我喜欢。界面条理清晰,能够明确展示下载成功数量、错误数量、进度条
    • 有sitemap功能,能够在任务启动前预览sitemap,并实时反馈爬虫参数调整对爬取范围的影响。
    • 接入HTTP代理很方便(至少不像httrack一样垃圾),方便后续接入其他工具修改Web请求。
  • 缺点:
    • 没有多线程。不知道是不是配置问题。
    • 不支持断点续传,重启任务后会重头开始爬,也没有scrapy和httrack一样的缓存机制。

scrapy

  • 优点:功能全面,一步到位。要啥有啥。
  • 缺点:
    • 需要写代码,工作量在1天~1周左右。没必要。
    • 没法解码captcha,自动化的优点跟没有差不多。

httrack

  • 优点:GUI,我喜欢。
  • 缺点:
    • GUI只有参数配置,没有运行过程的监控,日志的信息量也几乎没有,看不到进度,也看不到报错信息,自然无法除错。
    • 可定制性极差,不能修改请求。后端接入http代理,尝试各种方式没有成功。
    • 断点续传功能存在问题,断掉之后很难除错。

archivebox

  • 目前v0.4.3正在大规模重构,一个PR5都鸽了一年了。不想出问题替他改bug,我完全不想看开源项目的代码。

wget

  • 优点:有缓存6(timestamping)功能,说明可以断点续传。
  • 缺点:定制性较差,没有过滤URL功能。

请求构造组件:

Fiddler(最终选择)

  • 有Fiddler Script作为请求控制接口,功能不太多,能够用脚本设置条件截获、修改请求,凑合够用。
  • 可以一键向系统证书区注入CA证书,方便HTTPS数据劫持。这是个独一无二的快捷功能,没有任何其他工具可以做到。

scrapy

  • 需要写代码。麻烦。

burpsuite

  • 只支持Java 8。 四哥挑战崇山峻岭去了,不更新了。 我电脑里只有Java 11,才不装什么J8呢。而且不清楚burp有没有脚本功能。

mitmproxy

  • 没有GUI还需要用户交互的工具,就是垃圾。mitmweb那就是个玩具。

WebCopy

  • 可以修改部分请求参数(header、UA等),但任务启动后参数没办法动态修改,不满足需求。

爬虫实现

本文用到的软件,Cyotek WebCopy 和 Fiddler,都是免费的:

Cyotek WebCopy Downloads - Copy websites locally for offline browsing • Cyotek

https://www.cyotek.com/cyotek-webcopy/downloads

Download Fiddler Web Debugging Tool for Free by Telerik

https://www.telerik.com/download/fiddler

获取Cloudflare验证Cookie

为了让爬虫正常工作,我们需要手动解一下Cloudflare的验证码,并把服务器返回的Cookie记录下来。

首先用浏览器访问页面( https://b4ckdoorarchive.club/HELL-ARCHIVE ),按提示操作hCaptcha。Cloudflare这个验证码的特点是,分类比较少,比较常见的是雨伞、飞机、船、自行车,但很多图片都是很奇怪的拍摄角度和部分被摄物体(比如一张图只有自行车的轱辘)。不过相对于谷歌验证码的形式还是比较简单的。

/zh/2020/scraping-cloudflare-with-webcopy/01.png

验证成功后进入页面,打开浏览器开发者工具,刷新一下页面,在 “网络” 标签中,点击一个网络请求并将Cookie值和 User-Agent 值复制出来备用。我们这一步就算OK了。

/zh/2020/scraping-cloudflare-with-webcopy/02.png

一定要熟练掌握这一步操作哦,在整个网站爬取过程中我们可能重复操作3~4次。这个页面和开发者工具窗口也先别关了,留着后面要用。

爬虫配置

首先在WebCopy中新建一个项目,这没什么难的,跟着新建向导一路下一步就行了。

需要注意的有两点。首先,在菜单栏点击 Project - Project Properties 进入项目选项。

  1. 在User Agent设置中,将爬虫的UA设置成与浏览器相同。在网上随便找个站长工具或者在浏览器开发者工具里都能找到自己的UA。这一步很重要,因为CloudFlare通过UA验证Cookie的可用性。
  2. 在Query Strings设置中,勾选 Strip query string segments 。因为我们爬取的界面是一个文件列表页面,页面中最顶部有几个链接是用来排序的,我懒得写过滤规则,勾上这个就保证我们下载的文件只有列表中的文件和index.html,不包含杂七杂八的链接内容。

其次,在菜单栏点击 Project - Proxy Server... 将代理服务器设置为 Fiddler 的本地端口,默认为 127.0.0.1:8080

Fiddler配置

我们需要用Fiddler修改WebCopy发出的请求内容,实现两个功能:

  1. 在请求发送前,插入我们第一步中获取到的Cookie。
  2. 在返回结果前,判断一下Cloudflare有没有返回什么错误信息,如果有的话,触发断点人工介入处理。

打开Fiddler并将右侧栏切换到 FiddlerScript 这个标签中。默认情况下,Fiddler会给我们提供一个代码模板。在这里代码基于 JScript.NET 。咱们不用在意细节,也不用看文档,照葫芦画瓢就行了。

我们先把我们刚刚获取到的Cookie存进去,在 Handler 类的最开头定义一个 tamperedCookie 变量。我们把它放在最开头就是为了一会儿Cookie失效的时候,方便修改。

/zh/2020/scraping-cloudflare-with-webcopy/03.png

接下来,往下翻到类定义中的 OnBeforeRequest 方法,在最开头插入我们对Cookie的修改(实现功能1)。

/zh/2020/scraping-cloudflare-with-webcopy/04.png

再往下翻,在 OnBeforeResponse 方法中,判断HTTP状态码是否为503,如果匹配的话,设置一个特殊字段7,Fiddler看到这个字段就会打一个断点,跳出一个提示(实现功能2),我们将在下一节讲解如何修改返回数据的内容。

/zh/2020/scraping-cloudflare-with-webcopy/05.png

修改全部完成后,点击 Save Script 保存脚本,一定要记得点哦。

运行、监控爬虫状态

接下来,在WebCopy中点击右上方那个大大的按钮 Copy 就可以启动爬虫了!这个爬虫是不是超级方便!

让进度条走着,我们别急。根据作者的经验,在进度条走了大概四分之一的时候,Cloudflare的Cookie就会失效。这时我们就需要重新获取一个新的Cookie。一定要及时跟进处理,否则WebCopy的请求就会超时,它自己就去请求下一个资源了。

当Cookie失效后,Fiddler遇到503返回值会触发一个breakpoint,弹出类似下图的通知。

/zh/2020/scraping-cloudflare-with-webcopy/06.png

报错的请求内容如下。这时候,这个报错的请求已经被Fiddler拦下了,同时WebCopy处于阻塞状态,它还没知道这个请求报错。我们改掉了它,WebCopy就永远不会知道曾经发生过什么。

/zh/2020/scraping-cloudflare-with-webcopy/07.png

我们返回第二步中打开的浏览器窗口,F5刷新网页,Cloudflare此时会让我们再完成一次hCaptcha。根据提示完成校验码,然后重复第二步的操作,将更新后的Cookie填到FiddlerScript里我们先前定义的变量中,点击 Save Script 保存脚本。

注意,此时前一个被拦截的请求还处于阻塞状态。被截断的请求在session左侧列表中的图标如下图所示。我们选中并按 R 重放刚刚被拦截的请求,如果Cookie没问题的话,重放的请求返回状态码就是正常的200了。我们需要将这个正常返回的数据替换到刚刚被截断的请求中。

/zh/2020/scraping-cloudflare-with-webcopy/08.png

选中正常返回的请求session,在右侧窗口中,通过下面的方式点点点,就能在Raw标签中得到整个原始HTTP数据,复制所有内容,再选中刚刚被拦截的请求,粘贴所有内容。

/zh/2020/scraping-cloudflare-with-webcopy/09.png

操作完成后,点绿色按钮放行,WebCopy就会收到一条正常的返回数据了。

当进度条都走完了之后,WebCopy会汇总返回结果,同时列出爬虫遇到的所有错误。其中的HTTP 500经验证,就是服务器配置的问题,浏览器访问也一样下载不了。下面的几个超时就是作者为本文截图的时候手慢导致WebCopy超时了。当然,右键浏览器打开,缺失的个别文件也很容易能够下载到。

/zh/2020/scraping-cloudflare-with-webcopy/10.png

至此,我们的爬虫工作就完成了。

结语

3.66GB,运行时间55分钟。也不是一点代码都没写,但我们也看到了,绝对不用写一大堆代码。如果给我两个选项,

  1. scrapy,写代码55分钟,运行10分钟。
  2. webcopy,写代码10分钟,运行55分钟。

那我肯定选后者啊!单线程慢了点,刷会儿b站就过去了,怎地也比coding还要掉头发强吧?

我就是喜欢GUI,我就是不喜欢写代码!鼠标点点点,就是生产力!

直接丢封面图8

/zh/2020/scraping-cloudflare-with-webcopy/11.png

参考资料


  1. Moving from reCAPTCHA to hCaptcha https://blog.cloudflare.com/moving-from-recaptcha-to-hcaptcha/ ↩︎

  2. Anorov/cloudflare-scrape: A Python module to bypass Cloudflare’s anti-bot page. https://github.com/Anorov/cloudflare-scrape ↩︎

  3. codemanki/cloudscraper: Node.js library to bypass cloudflare’s anti-ddos page https://github.com/codemanki/cloudscraper ↩︎ ↩︎

  4. AurevoirXavier/cloudflare-bypasser-rust: A Rust crate to bypass Cloudflare’s anti-bot page. https://github.com/AurevoirXavier/cloudflare-bypasser-rust ↩︎

  5. v0.4.3 (first Django release) by pirate · Pull Request #207 · pirate/ArchiveBox https://github.com/pirate/ArchiveBox/pull/207 ↩︎

  6. wget - The non-interactive network downloader - man page https://www.mankier.com/1/wget#-N ↩︎

  7. Breakpoints in Fiddler https://www.telerik.com/blogs/breakpoints-in-fiddler ↩︎

  8. 表情包生成器: Meme Templates - Imgflip https://imgflip.com/memetemplates ↩︎