做爬虫抓取时,我们经常会碰到网站针对IP地址封锁的反爬虫策略。但只要有大量可用的IP资源,问题自然迎刃而解。
以前尝试过自己抓取网络上免费代理IP来搭建代理池,可免费IP质量参差不齐,不仅资源少、速度慢,而且失效快,满足不了快速密集抓取的需求。
收费代理提供的代理资源质量明显提升,最终选定使用站大爷作为代理提供平台。
站大爷每天能提供大概5万个不重复的短效高匿代理,每个代理存活期为2分钟,总IP数有20亿,IP数量足够使用。价格为包天30元,包月500元,还有半年及一年的套餐可供选择。只要能满足项目要求,提供优质稳定的服务,这些成本值得付出。
高匿代理才可以真正用来防止爬虫被封锁,如果使用普通代理,爬虫的真实IP还是会暴露。
站大爷提供了大量的代理服务器资源,主要考虑如何将这些服务器分配给爬虫服务器使用。最初的想法是使用Redis作为代理服务器资源队列,一个程序自动获取站大爷API提供的代理,验证可用后push到Redis里,每个程序再从Redis中pop一个代理进行抓取,但这样的缺点是不太好控制每台爬虫服务器的代理质量,有的代理速度快,有的速度比较慢,影响抓取效率,其次就是需要自行维护一套代理验证、分配的程序,增加了代码量,不便后期维护。
为了解决这些问题,我想到可以使用 Squid 提供的父代理功能,自动将爬虫服务器的请求转发给代理服务器。Squid提供了自动轮询功能,自动验证并剔除不可用的代理。减少了我们多余的验证步骤。
爬虫软件只需将代理设置为 Squid 服务器即可,不需要每次重新设置为其他的代理服务器。
这套方案明显减少了工作量,提高了易用性和可维护性。
- 首先获取代理平台提供的代理服务器资源
- 建议购买短效代理,购买后在后台获取API地址并设置IP白名单等参数
- 将获取到的代理服务器写入squid配置文件
- 解析网站提供的代理服务器,按照一定规则写入
/etc/squid/squid.conf
- 重新配置 squid
- 自动更新,重复1-3
- 由于网站提供的代理存活时间只有2分钟,所以需要每隔一段时间重新获取一批新IP
实现上述要求的代码如下:
文章中代码可能会不定期更新,获取最新代码请访问 https://github.com/xNathan/squid_proxy_pool 并关注
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
#!/usr/bin/env python
# coding: utf-8
# zdy.py
"""
Squid+站大爷搭建代理IP池
Author: xNathan
Blog: https://xnathan.com
Github: https://github.com/xNathan
"""
from gevent import monkey # isort:skip
monkey.patch_all() # isort:skip
import logging
import os
import time
import requests
from gevent.pool import Pool
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s: - %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
)
# 使用StreamHandler输出到屏幕
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
ch.setFormatter(formatter)
logger.addHandler(ch)
# Squid的配置文件语法
# 将请求转发到父代理
PEER_CONF = "cache_peer %s parent %s 0 no-query weighted-round-robin weight=1 connect-fail-limit=2 allow-miss max-conn=5\n"
# 可用代理
GOOD_PROXIES = []
pool = Pool(50)
def check_proxy(proxy):
"""验证代理是否可用
:param proxy list:[ip, port]"""
global GOOD_PROXIES
ip, port = proxy
_proxies = {"http": "{}:{}".format(ip, port)}
try:
ip_url = "http://2019.ip138.com/ic.asp"
res = requests.get(ip_url, proxies=_proxies, timeout=10)
assert ip in res.content
logger.info("[GOOD] - {}:{}".format(ip, port))
GOOD_PROXIES.append(proxy)
except Exception as e:
logger.error("[BAD] - {}:{}, {}".format(ip, port, e))
def update_conf():
with open("/etc/squid/squid.conf.original", "r") as F:
squid_conf = F.readlines()
squid_conf.append("\n# Cache peer config\n")
for proxy in GOOD_PROXIES:
squid_conf.append(PEER_CONF % (proxy[0], proxy[1]))
with open("/etc/squid/squid.conf", "w") as F:
F.writelines(squid_conf)
def get_proxy():
global GOOD_PROXIES
GOOD_PROXIES = []
# 1. 获取代理IP资源
api_url = "http://s.zdaye.com/?api=YOUR_API&count=100&fitter=1&px=2"
res = requests.get(api_url).content
if len(res) == 0:
logger.error("no data")
elif "bad" in res:
logger.error("bad request")
else:
logger.info("get all proxies")
proxies = []
for line in res.split():
proxies.append(line.strip().split(":"))
pool.map(check_proxy, proxies)
pool.join()
# 2. 写入Squid配置文件
update_conf()
# 3. 重新加载配置文件
os.system("squid -k reconfigure")
logger.info(">>>> DONE! <<<<")
def main():
start = time.time()
while True:
# 每30秒获取一批新IP
if time.time() - start >= 30:
get_proxy()
start = time.time()
time.sleep(5)
if __name__ == "__main__":
main()
|
- 按Squid 搭建正向代理服务器、Squid 配置高匿代理介绍的方法搭建运行 Squid 高匿服务器
- 备份原始配置文件
cp /etc/squid/squid.conf /etc/squid/squid.conf.original
,以供软件使用
- 在squid服务器上运行
python zdy.py
如果按照上述方法搭建好代理IP池,只需要在爬虫代码中设置设置squid代理服务器地址和端口(比如139.xxx.xxx.66:3188)。
1
2
3
4
5
6
7
8
9
10
11
12
|
#!/usr/bin/env python
# coding: utf-8
"""
代理IP池实例演示
"""
from __future__ import print_function
import requests
s = requests.Session()
s.proxies.update({"http": "139.xxx.xxx.66:3188"})
print(s.get("http://httpbin.org/ip"))
|
每次运行这个程序时,返回的IP都不一样,而且仅有一个,说明IP代理池已经搭建成功,可以应用在网络爬虫项目中。
这套解决方案结合了网络上的大量优质代理资源以及Squid服务器提供的特性,基本解决了网站对于爬虫IP的封锁。
成本比较低,而且有比较高的易用性,很方便地能结合到各种爬虫应用中,只需要增加一个代理地址即可,而由 Squid 统一管理父代理,不需要在爬虫程序中进行代理的获取验证等等操作,便于维护。
实际使用中还没有发现什么特别重大的问题,更多扩展性还有待后续继续研究。
项目地址: https://github.com/xNathan/squid_proxy_pool
文章作者
xNathan
上次更新
2019-04-18
许可协议

本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。