屏蔽一些不友好的蜘蛛

网站上的内容总希望有人看,有搜索引擎或者索引服务收录。可是某些搜素引擎真让人受不了,它的机器人爬虫(蜘蛛,robot,spider,crawler,wanderer)可能会在每天的某个时段集中力量对你的网站进行地毯式访问,甚至不遵守 robots.txt 的声明。终于忍不住要对一些蜘蛛动手了,将它们屏蔽在了网站的大门口。

最近发现的这个烦人的蜘蛛是 YisouSpider。它每天都会来访问 cnzhx.net,基本上一次访问持续半个小时到一个小时之间,爬行页面成百上千。而且它不遵守 robots.txt 中的禁止声明,拼命的抓取带有 replytocom 参数的页面(之前曾经在 WordPress 站点通过 robots.txt 限制百度索引范围一文中介绍过这个,一个 WordPress 站点页面带这个参数和不带这个参数的内容基本上没有差别)。这两个因素合在一起,让我对这个 YisouSpider 忍无可忍了:在 YisouSpider 疯狂抓取页面的时间段,服务器 CPU 占用暴涨,网站响应速度变慢。所以干脆还是屏蔽它吧。

除了 YisouSpider,还有 EasouSpider 也是不太遵守 robots.txt 的声明,但是它没有 YisouSpider 那么疯狂。另外,百度蜘蛛也有不守规则的时候,还有 360spider,也经常会无视 robots.txt 而访问带 replytocom 参数的页面。甚至 Google 都会这么干。

我现在能想到的比较好的屏蔽它们的方法就是配置服务器,让它们到不了网站那一层。可以用 mod_rewrite 或者 mod_setenvif 这两个 Apache 组件完成。让这些被屏蔽的 bot 直接收到 403 禁止访问的回复而无法访问具体页面也就不会占用更多 CPU 资源和消耗更多流量了。

0. 部署

下面讲到的代码(Apache 配置规则)既可以放在 Apache 的配置文件中,也可以放在网站目录的 .htaccess 文件中(如果 Apache 配置中设置了 AllowOverride 的话)。

我是单独创建了一个配置文件 badbot.conf 放在了 Apache 配置目录 /etc/httpd/conf.d/ 中(虚拟主机配置文件 vhost.conf 也在这里)。详见在此 VPS 上配置 LAMP 服务器那篇文章。推荐用方法 2。

1. 用 mod_rewrite

mod_rewrite 是 Apache 的地址重写组件,一般的服务器都加载提供此组件。最常见的应用是将动态地址(带 ? 查询参数的 URL)改写成比较好看的层级目录的形式。mod_rewrite 有个指令 RewriteCond 可以根据多种变量来重写 url,甚至可以通过 F(Forbidden)参数来拒绝访问。

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /

    # 始终允许访问 robots.txt 和 error.html
    RewriteCond %{REQUEST_URI} !^/robots\.txt$
    RewriteCond %{REQUEST_URI} !^/error\.html$

    RewriteCond %{HTTP_USER_AGENT} EasouSpider [NC,OR]
    RewriteCond %{HTTP_USER_AGENT} YisouSpider [NC,OR]
    RewriteCond %{HTTP_USER_AGENT} Sogou\ web\ spider [NC]
    RewriteRule ^.*$ - [F,L]
</IfModule>

其中:

  • <IfModule mod_rewrite.c> 表示有加载 mod_rewrite 组件的时候才起作用,</IfModule> 用来结束这一部分;
  • %{HTTP_USER_AGENT} 表示按照访问者的用户类型来匹配;
  • NC 参数表示 nocase,不区分大小写
  • OR 表示此条不符合条件就试试匹配下一条;
  • [F,L] 中 F 表示禁止访问,L 表示不用再继续处理了,到此为止(都禁止了当然是到此为止了);
  • # 开头的行表示注释,不起作用。

如果还想继续添加别的蜘蛛,比如 360Spider,可以在其中添加:

RewriteCond %{HTTP_USER_AGENT} 360Spider [NC,OR]

只要蜘蛛的类型说明中包含 360spider 字符串就会被禁止访问。因为使用的是正则表达式处理,所以写这些规则的时候应该注意针对性要强,如果只是写个 bot,就会匹配所有包含 bot 字符串的蜘蛛,那么 Google 也不能幸免了。

关于 mod_rewrite 还可以参考之前的一篇文章使用 mod_rewrite 屏蔽不友好的访问

注意:上面的规则,我在本地的虚拟机里部署之后工作良好,可是部署到这个 VPS 上之后就会误判,导致除了首页之外的所有页面都出错。到现在还没搞清楚问题出在什么地方,所以我用了下面的 mod_setenvif 方法。虽然 Apache 官方介绍可以工作在服务器(httpd.conf)范围上,但是我想还是将这个放在虚拟主机范围上(VirtualHost 定义里)比较好。反正我的情况是在 <VirtualHost> 定义中可以工作,在 badbot.conf 中就不能工作。

2. 用 mod_setenvif

mod_setenvif 可以根据访问请求的不同细节使用正则表达式来匹配设置不同的内部环境变量。这里要用的就是根据 User-Agent 来给所有匹配的访问设置一个内部变量 bad_bot,最后再统一针对有 bad_bot 变量的访问设置一个禁止访问的规则。

<Location />
    <IfModule mod_setenvif.c>
        SetEnvIfNoCase User-Agent "EasouSpider" bad_bot
        SetEnvIfNoCase User-Agent "YisouSpider" bad_bot
        SetEnvIfNoCase User-Agent "LinksCrawler" bad_bot
        SetEnvIfNoCase User-Agent "EtaoSpider" bad_bot
        SetEnvIfNoCase User-Agent "LinksCrawler" bad_bot
        SetEnvIfNoCase User-Agent "linkdex.com" bad_bot
        SetEnvIfNoCase User-Agent "rogerbot" bad_bot
        SetEnvIfNoCase User-Agent "AskTbPTV" bad_bot
        SetEnvIfNoCase User-Agent "brandwatch" bad_bot

        <IfModule mod_authz_core.c>
        # check ref: http://httpd.apache.org/docs/trunk/mod/mod_authz_core.html for explanation of the logic
        <RequireAll>
            Require all granted
            <RequireNone>
                Require env bad_bot
            </RequireNone>
        </RequireAll>
        </IfModule>
        <IfModule !mod_authz_core.c>
            Order Allow,Deny
            Allow from all
            Deny from env=bad_bot
        </IfModule>
    </IfModule>
</Location>

因为与前面的 mod_rewrite 类似,这里很多东西不做介绍了。其中,

  • <Location /> 是设定作用范围为全站,</Location> 表示结束这一节;
  • SetEnvIfNoCase 表示不区分大小写来匹配,如果 User-Agent 中包含后面双引号里面的字符串,就给该请求设置一个内部变量 bad_bot;
  • 可以设置多条规则,它们是并行的;
  • 然后到下面的 Order Allow,Deny 表示处理顺序为允许再禁止,即,如果没有碰到禁止的规则就允许;
  • 所以下面紧接着就指定 Allow from All,表示允许所有;
  • 然后 Deny from env=bad_bot 禁止所有内部变量设置为 bad_bot 的访问请求。
  • 新增兼容 Apache 2.4 的 Require 方法。为了使代码可同时用于 Apache 2.2 和 2.4,这里采用了 IfModule 来进行条件判断。

上面两个方法任选其一既可。推荐用方法 2。

更新说明

2014.12.20

方法 2 中的 Allow Deny 语法在 Apache 2.4 中就改成 Require 了。这里修改了方法 2 的代码使之兼容两种表达方式。同时在方法 2 的列表中新增了几个不太友好的 bot。©

本文发表于水景一页。永久链接:<http://cnzhx.net/blog/ban-some-bad-spiders/>。转载请保留此信息及相应链接。

8 条关于 “屏蔽一些不友好的蜘蛛” 的评论

    • 嗯,Soso 和 Sogou 也挺多,不过在我这里最严重的就是 YisouSpider 和 MJ12bot 了。崩溃的是它们都是集中抓取,搞得服务器不堪重负。

  1. 请教,搜狗爬虫怎么写?中间带空格的。
    RewriteCond %{HTTP_USER_AGENT} Sogou web spider [NC,OR]
    RewriteCond %{HTTP_USER_AGENT} sogou spider [NC]

    另外,上述这些放在哪有讲究吗?放在VirtualHost里还是外面?
    谢谢。

    • 我自己现在用的是上面的第二种方法:http://cnzhx.net/blog/ban-some-bad-spiders/#mod_setenvif
      文中也说了,测试 mod_rewrite 方法的时候出了点问题。
      根据我的测试,Rewrite 规则需要放到 VirtualHost 里面才能正常工作。而我这里有多个 VirtualHost,每个都加就太不方便了。上面的第二个方法就没有这样的问题。
      另外,空格好像没有影响的,但是时间长了我也记不清楚了。

    • 嗯,对了,空格的话需要用 \ 符号做转义。也就是,
      RewriteCond %{HTTP_USER_AGENT} Sogou\ web\ spider [NC]

  2. 引用通告: Apache + PHP-FPM 与 Mod_deflate | 水景一页

时间过去太久,评论已关闭。
如果您有话要说,请到讨论区留言并给出此文章链接。
谢谢您的理解 :-)