目录
1. 引言:为什么要搭建 IP 池?
问题来了! 你写了一个爬虫,信心满满地去采集全球各大网站公开数据,结果没爬几次,IP就不能用了?网站返回403?甚至验证码狂弹?
为什么?因为大部分网站都有安全验证机制,如果同一个 IP 频繁请求,就会被识别为异常行为,导致访问受阻。
怎么办?
✅ 使用代理 IP 轮换,让爬虫的 IP 不断变换,控制每个IP的请求频率,降低被识别的风险。
✅ 搭建 IP 池,让爬虫可以自动获取可用代理,稳定运行。
今天,我们就来使用 IPIPGO 搭建一个属于自己的 IP 池,并且实现全球数据的公开访问。
2. 获取代理 IP
2.1 获取API链接
- 注册/登录 :打开 IPIPGO 官网,注册并登录账号
- 领取代理 IP:进入用户中心完成认证获得代理IP,如果不够,可以自行选购
- 获取API链接:进入API 提取页面,设置代理IP 参数并生成API链接
📌 API 链接示例
http://api.ipipgo.com/ip?cty=00&c=10&pt=1&ft=txt&pat=\n&rep=1&key=你的API密钥&ts=3
📌 代码解析
c=10
:获取 10 个代理 IP(可调整)ft=txt
:返回格式为纯文本,每行一个 IPkey=你的API密钥
:你的专属 API 密钥,一般生成后直接复制链接即可,无需手动替换
💡 提示:你可以在 IPIPGO 后台查看 API 详情,也可以选择其他参数,如指定国家或地区的代理
2.2 代理 IP 的格式
IPIPGO 返回的代理 IP 形式如下(每行一个):
172.65.64.115:13192
185.180.196.73:24561
102.129.249.53:10080
- IP 地址:
172.65.64.115
- 端口号:
13192
- 完整代理:
http://172.65.64.115:13192
2.3 使用 API 获取代理 IP
有了 API 链接后,我们可以用 Python 代码自动获取代理 IP
📌 代码示例
import requests
API_URL = "http://api.ipipgo.com/ip?cty=00&c=10&pt=1&ft=txt&pat=\n&rep=1&key=你的API密钥&ts=3"
def fetch_proxies():
response = requests.get(API_URL) # 发送请求获取代理IP
if response.status_code == 200: # 判断是否请求成功
proxies = response.text.strip().split("\n") # 按行分割 IP
print("获取到代理 IP:", proxies)
return proxies
else:
print("API 请求失败!请检查密钥或套餐状态。")
return []
fetch_proxies()
📌 代码解析
requests.get(API_URL)
:向 API 发送请求,获取代理 IPresponse.status_code == 200
:检查 API 请求是否成功(200 表示成功)response.text.strip().split("\n")
:将返回的文本按换行符拆分,获取一个 IP 列表print(proxies)
:打印获取到的代理 IP
3. 搭建 IP 池:存储 & 管理代理 IP
3.1 代理 IP 应该存在哪?
获取到代理 IP 后,我们需要存储它们,方便后续管理。以下是几种常见的存储方式:
存储方式 | 优点 | 适用场景 |
---|---|---|
纯文本 (txt ) | 简单易用 | 适合小规模测试 |
SQLite 数据库 | 支持查询、去重、定期更新 | 适合中等规模的爬取 |
Redis | 高效缓存,支持分布式 | 适合大规模爬取 |
这里,我们选择 SQLite,因为它比文本存储更灵活,比 Redis 更简单,适合大多数应用场景
3.2 自动存储代理 IP 到 SQLite
📌 代码示例
import sqlite3
conn = sqlite3.connect("proxy_pool.db")
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS proxies (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip TEXT UNIQUE,
last_checked TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
is_valid INTEGER DEFAULT 1
)
""")
conn.commit()
def store_proxies(proxies):
for proxy in proxies:
cursor.execute("INSERT OR IGNORE INTO proxies (ip) VALUES (?)", (proxy,))
conn.commit()
print(f"成功存储 {len(proxies)} 个代理 IP")
proxies = fetch_proxies()
store_proxies(proxies)
📌 代码解析
sqlite3.connect("proxy_pool.db")
:连接 SQLite 数据库(如果不存在,会自动创建)CREATE TABLE IF NOT EXISTS proxies
:创建存储代理 IP 的表INSERT OR IGNORE INTO proxies (ip) VALUES (?)
:避免重复存储相同的代理 IPconn.commit()
:提交数据,使存储生效
✅ 这样,每次获取的新 IP 都会自动存到数据库中,并避免重复存储!
4. 维护 IP 池:检测 & 轮换代理 IP
4.1 自动检测代理 IP 是否可用
📌 代码示例
def check_proxy(proxy):
try:
response = requests.get("http://httpbin.org/ip", proxies={"http": f"http://{proxy}", "https": f"http://{proxy}"}, timeout=5)
return response.status_code == 200
except:
return False
def update_proxy_status():
cursor.execute("SELECT ip FROM proxies")
all_proxies = cursor.fetchall()
for (proxy,) in all_proxies:
status = 1 if check_proxy(proxy) else 0
cursor.execute("UPDATE proxies SET is_valid = ? WHERE ip = ?", (status, proxy))
conn.commit()
print("代理检测完成")
update_proxy_status()
📌 代码解析
check_proxy(proxy)
:测试代理 IP 是否可用,使用httpbin.org/ip
返回的 IP 信息status = 1 if check_proxy(proxy) else 0
:根据代理是否可用更新数据库状态UPDATE proxies SET is_valid = ?
:将不可用的代理标记为0
(失效)
5. 让爬虫使用代理 IP 池
5.1 随机选取可用代理
爬虫在运行时,如何选择一个可用的代理 IP 呢?最简单的方法就是从 IP 池中随机选择一个可用的代理 IP,并将其应用到爬虫请求中。这样可以避免一直使用同一个 IP,降低被封的风险。
📌 代码示例
import random
def get_random_proxy():
cursor.execute("SELECT ip FROM proxies WHERE is_valid=1 ORDER BY RANDOM() LIMIT 1")
result = cursor.fetchone()
return result[0] if result else None
proxy = get_random_proxy()
print(f"使用代理: {proxy}")
📌 代码解析
SELECT ip FROM proxies WHERE is_valid=1 ORDER BY RANDOM() LIMIT 1
:从数据库中随机选择一个可用(is_valid=1
)的代理 IPcursor.fetchone()
:返回查询的第一行结果return result[0] if result else None
:如果查询到代理 IP,则返回;否则返回None
5.2 爬取全球公开网页
当我们搭建好 IP 池后,接下来的关键就是让爬虫能够自动使用代理池中的 IP 进行网页数据爬取。
📌 代码示例
import requests
target_url = "https://example.com" # 目标网站
proxy = get_random_proxy() # 从代理池中获取一个可用代理
if proxy:
proxies = {"http": f"http://{proxy}", "https": f"http://{proxy}"} # 设置代理
try:
response = requests.get(target_url, proxies=proxies, timeout=5) # 发送请求
print(response.text[:500]) # 打印前500个字符,防止输出过长
except requests.RequestException:
print("请求失败") # 代理可能失效,需要切换
else:
print("没有可用的代理 IP")
📌 代码解析
proxy = get_random_proxy()
:从 IP 池中随机选取一个可用的代理 IPproxies = {"http": f"http://{proxy}", "https": f"http://{proxy}"}
:为requests
设置代理requests.get(target_url, proxies=proxies, timeout=5)
:通过代理发送 HTTP 请求,超时时间设为 5 秒print(response.text[:500])
:打印网页内容的前 500 个字符,防止输出过长影响阅读except requests.RequestException:
:如果请求失败(如代理不可用、超时),会捕获异常并提示请求失败
6. 定期优化 IP 池:自动更新与清理
6.1 定期获取新代理 IP 并清理无效 IP
为了保持 IP 池的可用率,我们需要定期从获取新的代理 IP,并且清理掉那些已经失效的 IP,这样可以确保爬虫的稳定运行,避免使用无效的代理。
📌 代码示例
import schedule
import time
def refresh_proxies():
new_proxies = fetch_proxies()
store_proxies(new_proxies)
print("代理 IP 已更新!")
def update_proxy_status():
cursor.execute("SELECT ip FROM proxies")
all_proxies = cursor.fetchall()
for (proxy,) in all_proxies:
status = 1 if check_proxy(proxy) else 0
cursor.execute("UPDATE proxies SET is_valid = ? WHERE ip = ?", (status, proxy))
conn.commit()
print("代理检测完成")
schedule.every(10).minutes.do(refresh_proxies)
schedule.every(15).minutes.do(update_proxy_status)
while True:
schedule.run_pending()
time.sleep(60)
📌 代码解析
schedule.every(10).minutes.do(refresh_proxies)
:每 10 分钟获取一次新的代理 IPschedule.every(15).minutes.do(update_proxy_status)
:每 15 分钟检查一次代理 IP 的可用性while True: schedule.run_pending()
:不断执行定时任务
7. 总结
至此,你已经成功搭建了一个可用的全球代理 IP 池,并能用它进行网页数据爬取!定期优化 IP 池,智能切换代理,让你的爬虫更加稳定高效,高效全球公开网络数据!