文章目录
通过 IP 限制反爬实验介绍知识点课程环境 IP 限制实战用 Nginx 限制特定 IP关于 allow 和 deny 的使用说明Nginx 限制 IP 访问频率Python Flask 模拟 IP 黑名单 实验总结通过 IP 限制反爬
实验介绍
在常规的反爬手段中,IP 限制是应用广泛且比较有效的,但其存在一定的误杀
,因同一 IP 下可能不止一位用户。本实验从 Nginx 限制特定 IP 的配置开始学习,然后扩展到限制 IP 访问频次,最后通过文本文件模拟了黑名单 IP 库限制爬虫 IP 这一技术点。
知识点
Nginx 限制 IP 访问Nginx 控制 IP 访问频次用 Python Flask 配合黑名单限制 IP课程环境
蓝桥提供的 Ubuntu20+ 系统,系统内置 Nginx,内置 sublime text3 编辑器,Python3+ 版本。
课程实战参见 玩转 16 种反爬虫技巧
IP 限制实战
用 Nginx 限制特定 IP
首先学习利用 Nginx 配置限制特定 IP 访问我们的站点,限制 IP 有两种机制,即黑/白名单。
黑名单:在名单中的 IP无法访问;白名单:在名单中的 IP可以访问。
反爬中常见的是应用 IP 黑名单技术,假设你的网站安全等级较高,可以启用 IP 白名单机制。
下面为大家详细说明黑名单机制。
为了配合 Nginx 配置,先使用 Python Flask 获取一下蓝桥系统中本地环境的 IP。
在 Code 目录中中创建一个新目录03_demo
,然后创建index.py
文件,输入如下代码。
import loggingfrom flask import Flask, render_template, requestapp = Flask(__name__)@app.route('/')def index():ip = request.remote_addrlogging.debug(ip)return render_template('index.html', user_ip=ip)if __name__ == '__main__':# 注意蓝桥环境不能使用 80 端口,会出现异常app.run(host="0.0.0.0", port=8080)
在项目根目录templates
中新建index.html
文件,然后输入如下代码:
<!DOCTYPE html><html><head> </head><body><div class="container"><div class="header"><h3 class="text-muted">获取用户IP</h3></div><hr /><div>IP 地址是: <strong>{{user_ip}}</strong><hr /></div></div></body></html>
运行代码得到如下内容,由于 Flask 运行后可以使用两个 IP 地址访问,即127.0.0.1
和192.168.42.3
,所以后续限制 IP 时,也可以拿这两个 IP 下手。
到这里我们获取到了本地 IP,接下来就可以在 Nginx 中进行限制了。
打开/etc/nginx/conf.d/default.conf
文件,然后参考下图进行配置。
location / {root /usr/share/nginx/html;index index.html index.htm;allow 192.168.42.3;deny all;}
配置输入位置截图:
修改default.conf
文件之后,注意重新加载配置文件,命令如下:
# 重新加载配置sudo /etc/init.d/nginx reload
接下来在终端使用wget
关键字进行测试。
# 测试 127.0.0.1wget http://127.0.0.1# 测试 192.168.42.3wget http://192.168.42.3
得到的结果如下所示:
由于我们设置了仅允许(allow
)IP 地址为192.168.42.3时,才可以访问目标站点,所以第一次请求127.0.0.1时,系统返回 403 禁止。
关于 allow 和 deny 的使用说明
屏蔽操作的关键字是deny
:
屏蔽单个 IP
deny 127.0.0.1;
屏蔽多个 IP
deny 127.0.0.1;deny 127.0.0.1;
屏蔽全部 IP
deny all;
屏蔽 IP 段访问
# deny ip/mask# 屏蔽 192.0.0.0 到 192.255.255.254 访问的命令deny 192.0.0.0/8;# 屏蔽 192.168.0.0 到 192.168.255.254 访问的命令deny 192.168.0.0/16;#屏蔽 192.168.6.1 到 192.168.6.254 访问的命令deny 192.168.6.0/24;
扩展知识点 192.168.0.0/16 为 CIDR 的表示语法,学有余力的同学可以继续学习一下。
此时你应该发现,如果 IP 地址过多,每次都屏蔽一个会非常繁琐,因此blockip.conf
就出现了,它可以一次屏蔽多个 IP,而且在单独文件配置。
blockip.conf
文件需创建在default.conf
同目录/etc/nginx/conf.d/
中,所以提前修改该目录读写权限。
sudo chmod 777 /etc/nginx/conf.d/
blockip.conf
文件内容如下所示:
allow 192.168.42.3;deny all;
保存之后在default.conf
导入该文件即可。
include blockip.conf;
修改配置之后,使用sudo /etc/init.d/nginx reload
重新加载配置。
再次测试,发现与前文结果一致,证明导入配置文件已经生效。
允许操作的关键字是allow
:
允许单个 IP
allow 127.0.0.1;
允许所有 IP
allow all;
其余内容与上文拒绝操作一致。
需要注意的事项
Nginx 配置会从上至下依次判断,写在前面的语句会屏蔽后续的语句,具体配置如下所示:
# 先禁止所有,后续允许的也无法访问deny all;allow 127.0.0.1;allow 192.168.42.3;
解决上述问题的方式就是,将允许的 IP 配置前置。
allow 127.0.0.1;allow 192.168.42.3;deny all;
Nginx 限制 IP 访问频率
使用 Nginx 可以控制 IP 访问频率,涉及的两个配置,分别如下所示:
limit_req_zone $binary_remote_addr zone=one:10m rate=2r/s;
该配置需要写到/etc/nginx
目录中的nginx.conf
文件内,具体位置如下所示:
参数说明如下:
limit_req_zone:该变量用于限制请求频率,只能在http使用;$binary_remote_addr:二进制远程地址;zone=one:定义一个名称为one
的记录区,总容量为 10 M;rate:每秒的请求为 2 个(测试用,实战中适当调高)。
除了上述配置外,还需要在default.conf
中的location
块配置如下内容:
limit_req zone=one burst=3 nodelay;
参数说明如下:
zone=one:设置使用哪个配置区域来做限制,与上面limit_req_zone的name
对应;burst=3:burst配置在这里,我们设置了一个大小为 3 的缓冲区,当有大量请求过来时,超过访问频次限制的请求,先放到缓冲区内等待,但不能超过 3 个,否则超过的请求会直接报 503 的错误然后返回,其中的 3 可自行设置;nodelay:该参数表示超过的请求不被延迟处理。
该配置完成后,需要重启 Nginx 服务,否则配置不生效。
sudo /etc/init.d/nginx restart
测试使用 Python 代码实现:
import requestsprint(requests.get('http://127.0.0.1'))print(requests.get('http://127.0.0.1'))print(requests.get('http://127.0.0.1'))print(requests.get('http://127.0.0.1'))print(requests.get('http://127.0.0.1'))print(requests.get('http://127.0.0.1'))print(requests.get('http://127.0.0.1'))print(requests.get('http://127.0.0.1'))print(requests.get('http://127.0.0.1'))print(requests.get('http://127.0.0.1'))print(requests.get('http://127.0.0.1'))
运行代码之后,得到如下响应状态码,可以看到从第 5 个请求开始,返回的是 503,你可以修改上文提及的配置值,将其调大,然后继续模拟不同数量的请求。
Python Flask 模拟 IP 黑名单
使用 Python 去限制 IP,最佳的解决方案是使用 Python + Redis,但本系列实验的重点是反爬逻辑,所以本实验用普通的txt文件代替redis存储。
首先在03_demo
目录创建一个ban.txt
文件,该文件记录 IP 黑名单数据,每行存储一个 IP 地址,例如:
127.0.0.1183.247.199.114183.247.211.50……
接下来就可以在程序中读取该文件,然后通过判断请求端的 IP 地址是否存在于黑名单中,存在即返回 403 状态码。
在前文创建的index.py
文件中编入下述代码。
import loggingfrom flask import Flask, render_template, requestapp = Flask(__name__)def get_ban_ip():with open('ban.txt',"r") as f:ip_list = f.readlines()# 去除空格,并转换为集合set_ip = {ip.strip() for ip in ip_list}return set_ip@app.route('/')def index():# 获取客户端 IPip = request.remote_addrips = get_ban_ip()if ip in ips:# 判断 IP 是否在黑名单中,存在返回 403return "forbidden",403return render_template('index.html', user_ip=ip)if __name__ == '__main__':app.run(host="0.0.0.0", port=8080)
以上代码核心检测函数是get_ban_ip()
,它读取黑名单文件,并将其结果存储到集合中,然后通过in
运算符进行检测。
运行代码之后,你可以分别访问下述请求地址,获取结果。
http://127.0.0.1:8080 # 被禁止http://192.168.42.3:8080 # 可以访问
实验总结
本实验前部分主要集中讲解了 Nginx 对于 IP 限制的相关配置,在反爬实战中可以作为应急使用,第二部分的 Python Flask + IP 黑名单更加通用一些,而且在实际工作中,你可以构建一个 IP 和请求次数的键值对,然后设置每 IP 每秒访问频次瓶颈,当超过设置预设值时,进行屏蔽。
实战中还会碰到一种场景,爬虫程序不断切换代理 IP 访问我们的服务器,此时你需要做的是尽力维护好 IP 黑名单库,并且将 IP 与频次控制进行合理结合,恰当的判定对方是否为爬虫,然后封禁。
IP封禁很容易造成误伤,实战中要反复测试判定程序,尽量不放过一个爬虫程序,也不误伤一个正常用户。