注意: 由于完整版答案超出了Stack Overflow的长度限制,您需要前往GitHub阅读扩展版本,其中包含更多提示和详细信息。
为了防止网站爬虫(也称为Webscraping,Screenscraping,Web数据挖掘,Web收割或Web数据提取),了解这些爬虫的工作原理以及阻止它们正常工作的方法非常有帮助。
有各种类型的爬虫,每种都有不同的工作方式:
爬虫,例如谷歌机器人或网站复制程序如HTtrack, 递归地跟随链接到其他页面以获取数据。这些有时会用于有针对性的抓取以获取特定数据,通常与HTML解析器结合使用,从每个页面中提取所需数据。
Shell脚本:有时会使用常见的Unix工具进行抓取:Wget或Curl下载页面,Grep(Regex)提取数据。
HTML解析器,例如基于Jsoup、Scrapy和其他的解析器。类似于基于shell脚本的正则表达式方法,这些方法通过根据HTML中的模式从页面中提取数据,通常忽略其他内容。
例如:如果您的网站有一个搜索功能,这样的抓取器可能会提交搜索请求,然后从结果页面HTML中获取所有结果链接及其标题,以仅获取搜索结果链接及其标题。这是最常见的方法。
屏幕抓取器,例如Selenium或PhantomJS,它们在真实的浏览器中打开您的网站,运行JavaScript、AJAX等,然后从网页中获取所需文本,通常的方法是:
网页抓取服务,例如ScrapingHub或Kimono。事实上,有些人的工作就是找出如何抓取您的网站并提取内容供他人使用。
毫不奇怪,专业的抓取服务最难阻挡,但如果您使其难以找到如何抓取您的网站,并且需要耗费时间,这些服务(以及雇佣他们的人)可能不会费心抓取您的网站。
将您的网站嵌入其他网站的页面中,使用frames,并将您的网站嵌入移动应用程序中。
虽然技术上不算抓取,但移动应用程序(Android和iOS)可以嵌入网站,并注入自定义CSS和JavaScript,从而完全改变您的页面外观。
人工复制-粘贴:人们会复制和粘贴您的内容以便在其他地方使用。
这些不同种类的爬虫之间有很多重叠,即使它们使用不同的技术和方法,许多爬虫的行为也会相似。
这些建议大多是我自己的想法,遇到编写爬虫时遇到的各种困难,以及来自网络的信息和思路的碎片。
如何停止爬取
你无法完全防止它,因为无论你做什么,决心的爬虫仍然可以找出如何进行爬取。但是,您可以通过执行以下几项操作来停止大量的爬取:
监控您的日志和流量模式;如果发现异常活动,请限制访问:
定期检查日志,并在出现自动访问(爬虫)迹象的异常活动情况下,例如来自相同IP地址的许多相似操作,您可以阻止或限制访问。
具体来说,一些想法:
限制频率:
仅允许用户(和爬虫)在一定时间内执行有限数量的操作 - 例如,只允许来自任何特定IP地址或用户的几次搜索每秒钟。这将减慢爬虫的速度,并使它们无效。如果操作完成得太快或比真实用户更快,则还可以显示验证码。
检测异常活动:
如果您看到异常活动,例如从特定IP地址发出许多类似请求,某人查看过多的页面或执行异常数量的搜索,则可以防止访问,或为随后的请求显示验证码。
不要仅按IP地址监视和限制频率 - 还要使用其他指标:
如果要阻止或限制频率,请不要仅基于每个IP地址进行操作;您可以使用其他指标和方法来识别特定用户或爬虫。一些可帮助您识别特定用户/爬虫的指标包括:
例如,如果您从单个IP地址收到许多请求,所有这些请求都使用相同的用户代理,屏幕大小(使用JavaScript确定)以及用户(在这种情况下为爬虫)始终以相同的方式和定期间隔点击按钮,则可能是屏幕刮削器;您可以暂时阻止类似的请求(例如,阻止来自该特定IP地址的具有该用户代理和屏幕大小的所有请求),这样您就不会给该IP地址上的真实用户带来不便,例如在共享互联网连接的情况下。
您还可以进一步采取措施,即使它们来自不同的IP地址,也可以识别出类似的请求,表示分布式刮削(使用僵尸网络或代理网络的刮削器)。如果您收到许多完全相同的请求,但它们来自不同的IP地址,则可以阻止。再次注意不要无意中阻止真实用户。
对于运行JavaScript的屏幕刮削器,这可能是有效的,因为您可以从中获取大量信息。
安全堆栈交换上的相关问题:
使用验证码而不是暂时阻止访问:
实现限制频率的简单方法是暂时阻止访问一定时间,但使用验证码可能更好,有关验证码的部分请参见下面的部分。
需要注册和登录
如果您的网站可行,要求创建帐户才能查看您的内容。这是防止网络爬虫的好方法,但也会成为真实用户的障碍。
- 如果您需要注册和登录,您可以准确地跟踪用户和网络爬虫的操作。这样,您就可以轻松检测到特定帐户被用于网络爬取并禁用它。诸如速率限制或检测滥用(例如短时间内大量搜索)的事情变得更加容易,因为您可以识别特定的网络爬虫而不仅仅是IP地址。
为了避免脚本创建多个账户,您应该:
要求创建帐户才能查看内容会让用户和搜索引擎远离您的网站;如果您要求用户必须创建帐户才能查看文章,他们可能会转向其他网站。
从云主机和网络爬虫服务的IP地址阻止访问
有时候,网络爬虫会从网页托管服务(例如亚马逊网络服务或GAE)或VPS运行。对于来自这些云托管服务使用的IP地址发起的请求,限制访问您的网站(或显示验证码)。
同样,您也可以限制来自代理或VPN提供商使用的IP地址的访问,因为爬虫可能会使用这些代理服务器来避免检测到许多请求。
请注意,通过阻止代理服务器和VPN的访问,您将对真实用户产生负面影响。
如果您确实阻止/限制了访问,请确保不要告诉爬虫是什么原因导致了阻止,从而给他们提供修复其爬虫的线索。因此,显示类似以下文本的错误页面是一个坏主意:
- 您的IP地址请求过多,请稍后再试。
- 错误,用户代理标头不存在!
相反,显示一个友好的错误消息,不要告诉爬虫是什么原因导致的。类似下面的内容更好:
抱歉,出了点问题。如果问题仍然存在,您可以通过
helpdesk@example.com
联系支持。
这样做对真实用户更加友好,万一他们看到了这样的错误页面。如果一个真实用户看到错误消息,您还应该考虑显示验证码来代替硬性阻止,以便不会阻止合法用户并引起他们与您联系。
如果怀疑您的网站正在被爬取,请使用验证码。
验证码(“完全自动化区分计算机和人类的测试”)非常有效地阻止了爬虫。不幸的是,它们也很容易激怒用户。
因此,在怀疑可能存在爬虫并希望停止爬取但又不想阻止访问的情况下,它们非常有用。如果怀疑有爬虫,则可以考虑在允许访问内容之前显示验证码。
使用验证码时需要注意以下事项:
不要自己开发,使用像Google的reCaptcha这样的东西:它比你自己实现验证码要容易得多,比一些你自己想出来的模糊和扭曲文本解决方案更加用户友好(用户通常只需要勾选一个框),而且对于脚本编写者来说,它也更难解决,比从你的网站提供简单图像要困难得多。
不要在HTML标记中包含验证码的解决方案:我曾经看到一个网站在页面本身中有验证码的解决方案(虽然相当隐蔽),因此使其变得几乎无用。不要做这样的事情。同样,使用像reCaptcha这样的服务,您就不会有这种问题(如果您正确地使用它)。
验证码可以批量解决:有一些验证码解决服务,真正的低薪人员批量解决验证码。同样,使用reCaptcha在这里是一个好主意,因为他们有保护措施(例如用户解决验证码的相对较短时间)。除非您的数据真的很有价值,否则不太可能使用这种服务。
将文本内容作为图像提供
你可以在服务器端将文本呈现为图像,并提供该图像以显示,这将阻止简单的网络爬虫提取文本。但是,这对于屏幕阅读器、搜索引擎、性能和几乎所有其他方面都不利。在某些地方(如美国残疾人法案等方面)这也是非法的,而且很容易通过一些OCR方法规避它,所以不要这样做。
你可以使用CSS Sprites实现类似的效果,但这也有同样的问题。
不要公开完整数据集:
如果可行,不要提供一个脚本/机器人获取您的所有数据集的方法。例如:您有一个新闻网站,其中有许多单独的文章。您可以使这些文章只能通过网站内的搜索来访问,并且如果您没有在网站上列出所有文章及其URL的列表,则这些文章将仅通过使用搜索功能才能访问。这意味着想要从您的网站上获取所有文章的脚本将不得不对可能出现在您的文章中的所有短语进行搜索,以便找到它们,这将耗时、效率极低,并且希望会让网络爬虫放弃。
如果:
- 机器人/脚本不需要完整的数据集。
- 您的文章通过类似
example.com/article.php?articleId=12345
的 URL 进行服务。这(以及类似的事情)将允许爬虫简单地迭代所有的 articleId
并以此请求所有文章。
- 还有其他方法可以最终找到所有文章,例如编写一个脚本来跟随链接,这些链接会导向其他文章。
- 搜索 "and" 或 "the" 等内容几乎可以揭示一切,所以要注意这一点。(您可以通过仅返回前 10 或 20 个结果来避免这种情况)。
- 您需要搜索引擎来找到您的内容。
不要公开您的 API、端点等:
确保您不会意外公开任何 API。例如,如果您正在使用 AJAX 或从 Adobe Flash 或 Java Applets(天哪!)中进行网络请求来加载数据,则轻松查看页面的网络请求并确定这些请求的目标,然后反向工程并在爬虫程序中使用这些端点。确保您混淆您的端点并使其难以被他人使用,如所述。
为了防止HTML解析器和爬虫:
由于HTML解析器通过识别HTML中的可识别模式来从页面中提取内容,我们可以故意更改这些模式以破坏这些爬虫,甚至干扰它们。大多数这些技巧也适用于其他爬虫,如蜘蛛和屏幕抓取程序。
经常更改您的HTML
直接处理HTML的爬虫是通过从HTML页面的特定可识别部分提取内容来进行的。例如:如果您网站上的所有页面都有一个id为“article-content”的
,其中包含文章的文本,则编写一个脚本以访问您网站上的所有文章页面,并提取每个文章页面上的div的内容文本,然后就可以在其他地方重复使用这些爬虫所需的格式中获取该爬虫的所有文章。
如果您经常更改HTML和页面结构,则此类爬虫将不再起作用。
您可以经常更改HTML中元素的ID和类,甚至可以自动更改。因此,如果您的div.article-content
变成了div.a4c36dda13eaf0
,并且每周都会更改,则爬虫在最初时将正常工作,但一周后将会崩溃。确保还要更改您的id /类的长度,否则爬虫将使用div.[any-14-characters]
来查找所需的div。还要注意其他类似的漏洞。
如果无法从标记中找到所需的内容,则爬虫将从HTML结构的方式中获取它。因此,如果所有文章页面都相似,即在h1
之后的每个div
内的div
都是文章内容,则爬虫将基于此获取文章内容。同样,为了打破这一点,您可以定期和随机地添加/删除额外的标记到您的HTML中,例如添加额外的div
或span
。使用现代服务器端HTML处理,这应该不太困难。
需要注意的事项:
实现、维护和调试将会很繁琐和困难。
它会妨碍缓存。特别是如果您更改HTML元素的id或class,这将需要相应地更改CSS和JavaScript文件,这意味着每次更改它们时,浏览器都必须重新下载它们。这将导致重复访问者的页面加载时间变长,并增加服务器负载。如果您只更改一次每周,那么这不会是一个大问题。
聪明的爬虫仍然可以通过推断实际内容的位置来获取您的内容,例如,知道页面上的一个大文本块可能是实际文章。这使得仍然可以从页面中找到并提取所需的数据。Boilerpipe正是这样做的。
基本上,请确保对于每个类似的页面,脚本无法轻松找到实际的、期望的内容。
有关如何在PHP中实现此功能的详细信息,请参见如何防止依赖XPath的网络爬虫获取页面内容。
基于用户位置改变您的HTML
这与之前的提示有些类似。如果根据用户的位置/国家(通过IP地址确定)提供不同的HTML,可能会破坏向用户提供的爬虫程序。例如,如果有人正在编写从您的网站中爬取数据的移动应用程序,它最初可以正常工作,但是当实际分发给用户时,它会出现问题,因为这些用户可能在不同的国家,因此获取不同的HTML,而嵌入式爬取器并未设计用于消耗这些HTML。
经常更改您的HTML,积极地干扰爬虫!
例如:您的网站上有一个搜索功能,位于 example.com/search?query=somesearchquery
,返回以下HTML:
<div class="search-result">
<h3 class="search-result-title">Stack Overflow has become the world's most popular programming Q & A website</h3>
<p class="search-result-excerpt">The website Stack Overflow has now become the most popular programming Q & A website, with 10 million questions and many users, which...</p>
<a class"search-result-link" href="/stories/story-link">Read more</a>
</div>
(And so on, lots more identically structured divs with search results)
作为您可能已经猜到的,这很容易被爬取:所有爬虫需要做的就是使用查询访问URL,并从返回的HTML中提取所需数据。除了如上所述定期更改HTML之外,您还可以将旧的标记与旧的id和类一起保留,用CSS隐藏它,并填充虚假数据,从而污染爬虫。以下是搜索结果页面的更改方式:
<div class="the-real-search-result">
<h3 class="the-real-search-result-title">Stack Overflow has become the world's most popular programming Q & A website</h3>
<p class="the-real-search-result-excerpt">The website Stack Overflow has now become the most popular programming Q & A website, with 10 million questions and many users, which...</p>
<a class"the-real-search-result-link" href="/stories/story-link">Read more</a>
</div>
<div class="search-result" style="display:none">
<h3 class="search-result-title">Visit Example.com now, for all the latest Stack Overflow related news !</h3>
<p class="search-result-excerpt">Example.com is so awesome, visit now !</p>
<a class"search-result-link" href="http://example.com/">Visit Now !</a>
</div>
(More real search results follow)
这意味着编写用于根据类或ID从HTML中提取数据的爬虫仍将似乎起作用,但它们将获取假数据甚至广告,这些数据是真实用户永远看不到的,因为它们被CSS隐藏。
干扰爬虫:向页面插入假的不可见蜜罐数据
在前面的示例上添加,您可以向HTML添加不可见的蜜罐项以捕获爬虫。下面是一个可以添加到先前描述的搜索结果页面的示例:
<div class="search-result" style="display:none">
<h3 class="search-result-title">This search result is here to prevent scraping</h3>
<p class="search-result-excerpt">If you're a human and see this, please ignore it. If you're a scraper, please click the link below :-)
Note that clicking the link below will block access to this site for 24 hours.</p>
<a class"search-result-link" href="/scrapertrap/scrapertrap.php">I'm a scraper !</a>
</div>
(The actual, real, search results follow.)
一个用来获取所有搜索结果的爬虫将会捕捉到这个链接,就像页面上的任何其他真实搜索结果一样,并访问该链接以查找所需内容。一个真正的人类用户根本看不到它(因为它被CSS隐藏了),也不会访问该链接。一个真正的、可取的蜘蛛,比如Google的蜘蛛,也不会访问该链接,因为你在robots.txt中禁止了/scrapertrap/。
你可以让你的scrapertrap.php做一些阻止访问该IP地址或强制使用验证码的操作。
不要忘记在你的robots.txt文件中禁止你的蜜罐(/scrapertrap/
),这样搜索引擎爬虫就不会掉进去。
你可以/应该结合之前的提示,经常更改你的HTML。
也要经常更改它,因为网络爬虫最终会学会避开它。更改蜜罐URL和文本。还要考虑更改用于隐藏的内联CSS,并使用ID属性和外部CSS代替,因为网络爬虫会学会避开任何具有用于隐藏内容的style
属性和CSS的内容。还要尝试仅在某些时候启用它,以便网络爬虫最初可以工作,但一段时间后就会破坏。这也适用于之前的提示。
恶意人员可以通过分享链接到你的蜜罐,甚至将该链接嵌入到某个地方作为图片(例如,在论坛上)来阻止真正用户的访问。经常更改URL,并使任何禁止时间相对较短。
如果检测到网络爬虫,请提供虚假和无用的数据
如果你检测到明显的网络爬虫,可以提供虚假和无用数据;这会破坏网络爬虫从你的网站获取的数据。你还应该使这些虚假数据与真实数据无法区分,以便网络爬虫不知道它们被搞了。
例如:你有一个新闻网站;如果你检测到一个网络爬虫,不要阻止访问,而是提供虚假的
随机生成的 文章,这将污染网络爬虫获取的数据。如果你的虚假数据与真实数据无法区分,你就会让网络爬虫很难得到他们想要的东西,也就是真正的数据。
如果 User Agent 为空/缺失,则不接受请求
通常,懒惰编写的网络爬虫不会在请求中发送 User Agent 标头,而所有浏览器和搜索引擎蜘蛛都会发送。
如果你收到一个没有 User Agent 标头的请求,你可以显示验证码,或者简单地阻止或限制访问。(或者像上面描述的那样提供虚假数据,或者其他什么方法...)
虽然很容易欺骗,但作为对付编写不良的网络爬虫的措施,值得实施。
不要接受常见爬虫的用户代理请求;将被爬取者使用的黑名单添加到其中。在某些情况下,爬虫会使用没有真实浏览器或搜索引擎蜘蛛使用的用户代理,例如:"Mozilla"(只有这个,没有其他。我在这里看到了一些关于使用它进行爬取的问题。真正的浏览器永远不会仅使用它),“Java 1.7.43_u43”(默认情况下,Java的HttpUrlConnection使用类似于此的东西),"BIZCO EasyScraping Studio 2.0",“wget”,“curl”,“libcurl”等(有时会使用Wget和cURL进行基本抓取)。如果您发现特定的用户代理字符串由网站爬虫使用,并且真实浏览器或合法蜘蛛不使用该字符串,则还可以将其添加到黑名单中。
如果不请求资源(CSS,图像),它就不是真正的浏览器。真正的浏览器(几乎总是)会请求和下载诸如图像和CSS之类的资源。 HTML解析器和爬虫不会这样做,因为它们只对实际页面及其内容感兴趣。
你可以记录对资源的请求,如果只有HTML的请求很多,可能是一个网站抓取器。
需要注意的是,搜索引擎机器人、古老的移动设备、屏幕阅读器和配置不正确的设备也可能不会请求资源。
使用Cookie并要求使用它们来跟踪用户和网站抓取器的操作。
你可以要求启用Cookie以查看您的网站。这将阻止经验不足和新手网站抓取器编写者,但是对于一个网站抓取器来说发送Cookie很容易。如果您使用并要求Cookie,则可以使用它们跟踪用户和网站抓取器的操作,从而实现基于每个用户而非每个IP的速率限制、阻止或显示验证码等。
例如:当用户执行搜索时,设置唯一标识符Cookie。在查看结果页面时,请验证该Cookie。如果用户打开了所有搜索结果(可以从Cookie中看出),则很可能是一个网站抓取器。
使用Cookie可能无效,因为网站抓取器也可以发送Cookie,并根据需要丢弃它们。如果您的网站只能使用Cookie,还会阻止禁用Cookie的真实用户的访问。
请注意,如果使用JavaScript设置和检索Cookie,则会阻止不运行JavaScript的网站抓取器,因为他们无法检索和发送Cookie。
使用JavaScript + Ajax加载内容
在页面本身加载后,您可以使用JavaScript + AJAX来加载内容。这将使HTML解析器无法访问内容,因为它们不运行JavaScript。对于编写爬虫的新手和经验不足的程序员,这通常是一个有效的威慑。
请注意以下事项:
混淆您的标记、脚本和所有其他网络请求。
如果您使用Ajax和JavaScript来加载数据,请混淆传输的数据。例如,您可以在服务器上对数据进行编码(使用简单的base64或更复杂的方法),然后通过Ajax获取数据并在客户端解码和显示。这意味着检查网络流量的人不会立即看到您的页面如何工作和加载数据,而且对于直接请求您的端点数据,他们将不得不反向工程您的解密算法。
如果您使用Ajax加载数据,应该使其难以在未首先加载页面的情况下使用端点,例如通过要求一些会话密钥作为参数,这可以嵌入到JavaScript或HTML中。
您还可以直接在初始HTML页面中嵌入混淆的数据,并使用JavaScript对其进行解混淆并显示,这将避免额外的网络请求。这样做将显着增加使用仅运行HTML的解析器提取数据的难度,因为编写爬虫程序的人必须反向工程您的JavaScript(您也应该混淆它)。
您可能需要定期更改混淆方法,以破坏已经破解它的爬虫程序。
然而,这样做有几个缺点:
非技术性:
杂项:
还有商业的爬虫保护服务,例如 Cloudflare 的反爬虫或 Distill Networks(这里详细介绍了其工作原理here),它们可以代替您执行这些操作以及更多其他操作。
在真实用户可用性与防爬虫之间找到平衡:您所做的一切都会以某种方式对用户体验产生负面影响,请寻求妥协。
不要忘记您的移动站点和应用程序。如果您有一个移动应用程序,则也可以进行屏幕抓取,并且可以检查网络流量以确定其使用的 REST 终端点。
爬虫可以抓取其他爬虫:如果有一个网站从您的网站中抓取内容,则其他爬虫可以从该爬虫的网站中进行抓取。
进一步阅读: