網站爬蟲預警及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漏斗限流是個很是危險的操做,仍是應該常常觀察訪問日誌找出爬蟲程序的規律,肯定合理的限流參數。

相關文章
相關標籤/搜索