网站爬虫预警及Redis漏斗添加反爬虫机制

本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!php

前言

做为一个长期从事seo工做的开发者,网站的原创资源就是咱们的资本,但很难避免被其余爬虫程序,几个小时以内所有爬走,与爬虫之间的博弈也就变成了一场持久的拉锯战。在长期的博弈中,也总结了一个比较实用的反爬虫方法,虽然不能保证防住百分之百的爬虫程序,但也能防住大部分,或者增长爬虫者的采集成本。前端

爬虫程序识别

识别爬虫程序最主要的标识有两个:python

一、user-agent,用户头信息,正常的用户访问都会带有浏览器信息,例如redis

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
复制代码

爬虫程序在请求的时候,若是没有刻意伪造,会带上所使用的语言标识,例如python request请求头信息为:算法

python-requests/2.25.1
复制代码

PHP curl请求,若是php.ini配置文件中的user_agent打开的话会为: PHP,没打开会没有user-agent数据库

user-agent的伪造应该是最简单也是0成本的,因此除非是特别明显的标识直接拦截,通常不根据这个去作限制。后端

二、ip,用户访问都会携带用户ip,咱们能够根据同一个ip在短期内访问的次数去判断是否是爬虫程序,固然ip也可使用代理ip进行伪造。数组

网站爬虫预警

主要利用kafka高并发和稳定的特性,在不影响业务的前提下,实现访问量的统计。用redis的有序列表,统计出指定时间段内访问量最高的ip,达到预警的目的。 以PHP网站为例浏览器

image.png 一、在网站程序的入口处判断用户IP是否在违禁IP的Redis集合里markdown

$ip = Tools::getClientIp();
$res = $redis->get('ip:f:' . $ip);
if ($res) {
    return false;
}
复制代码

Tools::getClientIp()的代码为:

public static function getClientIp() {
    $ip = '';
    if (getenv('HTTP_CLIENT_IP')) {
        $ip = getenv('HTTP_CLIENT_IP');
    } else if (getenv('HTTP_X_FORWARDED_FOR')) {
        $ip = getenv('HTTP_X_FORWARDED_FOR');
        $ips = explode(',', $ip);
        $ip = $ips[0];
    } else if (getenv('REMOTE_ADDR')) {
        $ip = getenv('REMOTE_ADDR');
    }
    return $ip;
}
复制代码

二、将合法的ip推送到kafka消息队列。不用kafka也能够,可使用其余的消息队列,例如RabbitMq,但因为是网站入口,并发量比较大,kafka在稳定性和处理大并发量上具备更大的优点,因此选择了kafka。

三、在kafka消费者程序中,将接收到的用户ip推到redis以小时为单位的有序集合中,这一步主要是为了统计每一个时间段,访问量最高的ip,经过人为观察或者脚本定时统计,封禁不合法的ip或者发邮件提醒。

// 集合key
$key = 'list:' . date('YmdH');
$redis->zincrby($key, 1, $ip);
复制代码

接下来使用redis漏斗添加限制不正常ip的访问速率。

Redis漏斗添加反爬虫机制

Redis4.0以后提供了一个限流模块:redis-cell,该模块使用漏斗算法并提供原子性的限流指令。 这个模块须要单独安装,具体安装方法可参照网上的一些安装方法,这里就不细说了。 说一下这个模块的参数

> cl.throttle 127.0.0.1 14 30 60 1
1) (integer) 0    # 0表示容许,1表示拒绝
2) (integer) 15    # 漏斗容量capacity
3) (integer) 14    # 漏斗剩余空间left_quota
4) (integer) -1    # 若是拒绝了,须要多长时间后再重试,单位秒
5) (integer) 2    # 多长时间后,漏斗彻底空出来,单位秒
复制代码

该指令意思为,容许127.0.0.1的ip 行为的频率为每60s最多30次,漏斗初始容量为15(由于是从0开始计数,到14为15个),默认每一个行为占据的空间为1(可选参数)。 若是被拒绝,取返回数组的第四个值进行sleep便可做为重试时间,也能够异步定时任务来重试。

$res = $redis->executeRaw(['cl.throttle', $ip, 14, 30, 60]);
if ($res[0]) {
    $redis->setex('ip:f:' . $ip, $res[3], 1);
}
复制代码

总结

一、天天各个时间段ip访问次数的有序集合数据,访问量最高的数据应按期写入到数据库,并按期删除。

二、ip漏斗限流是个很是危险的操做,仍是应该常常观察访问日志找出爬虫程序的规律,肯定合理的限流参数。

相关文章
相关标签/搜索