使用多台拨号虚拟机(VPS)搭建动态IP池是一个强大的反反爬虫策略。下面我将为大家提供一个从原理到实践的详细指南。
拨号VPS(通常为ADSL拨号VPS)的特点是:每次重新拨号,运营商都会为其分配一个新的公网IP地址。通过自动化控制多台这样的VPS进行拨号换IP,并将它们组织成一个代理池,我们的爬虫就可以通过这个池子随机获取新鲜的、来自真实家庭宽带的有效IP地址,极大地降低被目标网站封禁的风险。
整个系统可以分为三个核心部分:
1、IP获取节点(拨号VPS):分布在各地、运行着拨号脚本和代理服务的虚拟机。
2、代理中间件(Proxy Middleware):部署在每个节点上的小型代理服务(如Squid, TinyProxy),允许你的爬虫通过它来发送请求。
3、中央控制与调度中心(IP池API):一个中心服务器,负责管理所有节点,收集可用IP,验证IP有效性,并提供API供爬虫获取代理。
1、准备VPS:
dial-up vps
, dynamic ip vps
。2、验证拨号功能:
pppoe-stop
和 pppoe-start
,或者一些自定义脚本如 ./dial.sh
。curl ifconfig.me
或 wget -qO- ifconfig.me
检查公网IP是否变化。记录这个命令,这是后续自动化的关键。你需要在每台VPS上安装一个轻量级的代理服务器,让爬虫可以通过它访问网络。
Port
行,设置一个端口,例如 8888
。Allow
行。默认是 Allow 127.0.0.1
,为了安全,你应该将其改为你的中央调度服务器的IP地址(或者你本地开发机器的IP),这样只有你的服务器能使用这个代理。如果只是测试,可以注释掉以允许所有IP(不安全!)。http://<你的VPS_ip>:8888
作为代理,看是否能正常上网。你需要一个脚本来自动完成“拨号 -> 获取新IP -> 上报给中央服务器”的流程。
auto_dial.py
):
#!/usr/bin/env python3 import requests import time import subprocess import logging # 配置中央API服务器的地址 API_SERVER = "http://your-api-server.com:5000" NODE_ID = "vps_node_1" # 每个节点唯一的标识符 logging.basicConfig(level=logging.INFO) def get_current_ip(): """获取当前的公网IP""" try: # 可以使用多个服务来确保稳定性 response = requests.get('http://ifconfig.me', timeout=10) return response.text.strip() except: return None def dial_new_ip(): """执行拨号命令""" logging.info("Dialing for a new IP...") # 使用你的VPS供应商提供的拨号命令 result = subprocess.run(['/path/to/your/dial-script'], shell=True, capture_output=True, text=True) if result.returncode == 0: logging.info("Dial successful.") return True else: logging.error(f"Dial failed: {result.stderr}") return False def report_ip(ip): """将新的IP上报给中央服务器""" data = {'node_id': NODE_ID, 'ip': ip} try: response = requests.post(f"{API_SERVER}/report", json=data, timeout=10) if response.status_code == 200: logging.info(f"Successfully reported IP: {ip}") else: logging.error(f"Failed to report IP. Status: {response.status_code}") except requests.exceptions.RequestException as e: logging.error(f"Error reporting IP: {e}") def main(): old_ip = get_current_ip() logging.info(f"Current IP: {old_ip}") if dial_new_ip(): # 等待网络重新连接 time.sleep(15) new_ip = None retries = 0 while new_ip is None and retries < 5: new_ip = get_current_ip() retries += 1 time.sleep(5) if new_ip and new_ip != old_ip: logging.info(f"New IP obtained: {new_ip}") report_ip(new_ip) else: logging.error("Failed to obtain a new IP after dialing.") else: logging.error("Dialing process failed.") if __name__ == "__main__": main()这是一个简单的Flask应用示例,它提供两个API端点:
/report
:供节点上报其当前IP和端口。/get_proxy
:供爬虫获取一个随机的可用代理。# app.py (运行在中央服务器)
from flask import Flask, request, jsonify
import random
import time
app = Flask(__name__)
# 在内存中存储可用的代理信息
# 实际应用中应使用Redis或数据库,并设置过期时间
proxy_pool = {}
@app.route('/report', methods=['POST'])
def report_ip():
data = request.get_json()
node_id = data.get('node_id')
ip = data.get('ip')
port = 8888 # 假设所有节点都用TinyProxy的默认端口
if node_id and ip:
proxy_url = f"http://{ip}:{port}"
proxy_pool[node_id] = {
'proxy': proxy_url,
'ip': ip,
'report_time': time.time()
}
print(f"Received report from {node_id}: {proxy_url}")
return jsonify({'status': 'success'})
else:
return jsonify({'status': 'error', 'message': 'Missing data'}), 400
@app.route('/get_proxy', methods=['GET'])
def get_proxy():
"""爬虫调用此接口获取一个随机代理"""
if not proxy_pool:
return jsonify({'status': 'error', 'message': 'No proxy available'}), 503
# 随机选择一个代理
node_id, proxy_info = random.choice(list(proxy_pool.items()))
return jsonify({'status': 'success', 'proxy': proxy_info['proxy'], 'node_id': node_id})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
在你的爬虫代码中(以Python的Scrapy或Requests为例),从中央API获取代理并使用它。
settings.py
中启用并编写自定义的下载中间件。
# settings.py DOWNLOADER_MIDDLEWARES = { 'myproject.middlewares.RotatingProxyMiddleware': 543, } # middlewares.py import requests from scrapy import signals class RotatingProxyMiddleware(object): def __init__(self): self.api_url = 'http://your-api-server.com:5000/get_proxy' def process_request(self, request, spider): proxy_info = requests.get(self.api_url).json() if proxy_info['status'] == 'success': request.meta['proxy'] = proxy_info['proxy'] # 也可以将node_id存入meta,方便失败时追溯 request.meta['node_id'] = proxy_info.get('node_id')1、IP有效性验证:中央服务器应定期(如每分钟)主动验证池中代理是否仍然有效(能否访问外网、速度如何),并及时剔除失效节点。
2、使用数据库:使用Redis来管理代理池,可以自然地为每个IP设置TTL(生存时间),实现自动过期。
3、认证与安全:为TinyProxy和中央API添加简单的认证,防止他人盗用你的代理资源。
4、频率控制:合理设置拨号频率,过于频繁可能导致VPS供应商封禁。根据你的业务需求找到平衡点。
5、成本考量:拨号VPS通常按流量或带宽计费,监控你的爬虫流量以避免产生意外高额费用。
6、法律与合规:务必遵守目标网站的 robots.txt
协议和相关法律法规。使用代理池并不意味着可以无视规则进行暴力爬取。尊重网站服务器,合理设置请求间隔。
这个方案技术含量较高,需要一定的运维和开发能力,但一旦搭建成功,将会是一个非常稳定和强大的爬虫基础设施。
总之,这套方法就是让多台云电脑轮流拨号换IP,再把它们变成代理门卫。你的爬虫每次请求前,先问调度中心要一个新鲜门卫的地址,用它去访问目标网站,这样就能有效隐藏自己,大大降低被封的风险。当然,操作得合法合规。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。