学习目标
读完这一讲,你能:
- 理解分布式爬虫的技术架构
- 识别代理 IP 来源的法律风险
- 设计一个"白帽子"分布式爬虫架构
技术原理
代理池架构
import random
import requests
class ProxyPool:
def __init__(self):
self.proxies = []
def add_proxy(self, proxy_url):
self.proxies.append(proxy_url)
def get_proxy(self):
return random.choice(self.proxies) if self.proxies else None
def fetch(self, url):
proxy = self.get_proxy()
proxies = {'http': proxy, 'https': proxy} if proxy else None
return requests.get(url, proxies=proxies, timeout=10)
# 代理来源分级
PROXY_SOURCES = {
'free_public': {'quality': 'low', 'legal_risk': 'medium'},
'paid_datacenter': {'quality': 'medium', 'legal_risk': 'low'},
'paid_residential': {'quality': 'high', 'legal_risk': 'medium'},
'pirated_residential': {'quality': 'high', 'legal_risk': 'high'},
'botnet': {'quality': 'high', 'legal_risk': 'extreme'},
}
代理 IP 分几类:
- 数据中心代理:来自 AWS、阿里云等云服务器的 IP。便宜、量大、容易被识别。
- 住宅代理:来自真实家庭网络的 IP。贵、难被识别、但来源复杂。
- 移动代理:来自手机基站的 IP。最贵、最像真人。
设备指纹
"""
设备指纹的构成要素
"""
DEVICE_FINGERPRINT_COMPONENTS = {
'canvas': 'Canvas 2D 渲染特征',
'webgl': 'WebGL 显卡和渲染特征',
'fonts': '已安装字体列表',
'timezone': '时区设置',
'language': '语言偏好',
'screen': '屏幕分辨率',
'navigator': '浏览器和操作系统信息',
'webrtc': 'WebRTC 泄漏的本地 IP',
}
服务器通过收集这些特征,生成一个唯一标识。即使换了 IP,只要设备指纹一样,服务器就能认出你。
伪造设备指纹 vs 随机化特征
# 伪造:声称自己是 iPhone,但实际上是服务器
fake_fingerprint = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0)',
'Screen': '390x844',
'Platform': 'iPhone',
}
# 随机化:每次请求稍微变化一些特征,模拟不同设备
import random
def randomize_fingerprint(base):
"""在基础特征上随机微调,模拟正常用户的设备差异"""
variants = {
'Screen': [
'1920x1080', '1366x768', '1440x900', '1536x864',
],
'ColorDepth': [24, 32],
}
result = base.copy()
for key, options in variants.items():
if key in result:
result[key] = random.choice(options)
return result
伪造 = 声称自己是某个特定设备。随机化 = 每次稍微变化,模拟正常用户的多样性。法律上,前者风险远高于后者。
架构师律师通过真实判例分享爬虫的法律边界
真实判例
晟品案
法院认定的事实:"使用伪造用户代理(User-Agent)及网际协议地址(IP)绕过服务器的访问频率限制"。
这里有两个关键词:"伪造"和"绕过"。代理 IP 如果只是从付费代理服务商购买的数据中心 IP,通常不构成"伪造"。但如果你使用住宅代理,而这些住宅代理的来源是被劫持的路由器、物联网设备——那就是另一回事了。
物联网僵尸网络代理
黑产中有一种代理:入侵家庭路由器、摄像头、智能电视,把它们变成代理节点。你的爬虫通过这些节点发请求,服务器看到的是"来自某个家庭的正常 IP"。
这种代理的法律风险链:
- 黑产入侵物联网设备 → 构成非法控制计算机信息系统罪
- 黑产把代理 IP 卖给你 → 构成提供侵入计算机信息系统程序罪的帮助犯
- 你用这些代理发请求 → 你的行为可能被视为利用犯罪工具
你在买代理的时候,可能根本不知道来源。但"不知道"在法律上的抗辩空间很小——如果你以明显低于市场价的价格购买"住宅代理",法院可以推定你"应当知道"来源有问题。
法律分析
IP 轮换的法律定性
单纯使用多个 IP 发请求,本身不违法。这相当于你用多台电脑、在不同地点访问同一个网站。每台电脑的行为都是正常的。
但如果 IP 轮换的目的是规避平台明确设置的访问限制,情况就变了。比如平台封了你的 IP A,你自动切换到 IP B 继续抓——这是否构成"突破安全措施"?
目前没有明确的司法解释。但我的判断是:如果平台只是基于频率阈值自动封禁,切换 IP 继续抓,大概率不构成"侵入"。但如果平台明确声明了"禁止以任何方式绕过 IP 封禁",而你使用了更复杂的技术手段(比如伪造源 IP、利用 CDN 漏洞),那就危险了。
实战输出:白帽子分布式爬虫架构
"""
白帽子分布式爬虫架构
特点:合法代理源、诚实身份声明、自适应限速、完整日志
"""
import time
import random
import logging
from datetime import datetime
class WhiteHatCrawler:
"""
白帽子爬虫 - 法律合规优先
"""
def __init__(self, name, contact_url, contact_email):
self.name = name
self.contact_url = contact_url
self.contact_email = contact_email
self.session = requests.Session()
self.session.headers.update(self._get_honest_headers())
self.logger = self._setup_logger()
self.last_request_time = 0
self.min_interval = 2.0 # 最小请求间隔(秒)
def _get_honest_headers(self):
return {
'User-Agent': f'{self.name}/1.0 (+{self.contact_url}; {self.contact_email})',
'Accept': 'text/html,application/xhtml+xml,*/*;q=0.8',
'X-Crawler-Contact': self.contact_email,
}
def _setup_logger(self):
logger = logging.getLogger(self.name)
logger.setLevel(logging.INFO)
handler = logging.FileHandler(f'{self.name}_access.log')
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
def _adaptive_delay(self, response_time):
"""自适应限速:根据对方响应时间动态调整"""
base_delay = self.min_interval
# 如果对方响应慢,我们更应该慢
if response_time > 1.0:
base_delay += response_time
# 随机化,模拟人类
jitter = random.uniform(0, 1)
return base_delay + jitter
def fetch(self, url):
# 自适应延迟
elapsed = time.time() - self.last_request_time
if elapsed < self.min_interval:
time.sleep(self.min_interval - elapsed)
start = time.time()
try:
resp = self.session.get(url, timeout=15)
response_time = time.time() - start
self.last_request_time = time.time()
# 记录完整日志
self.logger.info(
f"URL={url} | Status={resp.status_code} | "
f"ResponseTime={response_time:.2f}s | "
f"ContentLength={len(resp.content)}"
)
# 检查是否需要进一步延迟
if resp.status_code == 429:
delay = self._adaptive_delay(response_time)
self.logger.warning(f"Rate limited, backing off for {delay:.1f}s")
time.sleep(delay)
return resp
except Exception as e:
self.logger.error(f"URL={url} | Error={str(e)}")
raise
def close(self):
self.session.close()
self.logger.info("Crawler session closed")
# 使用示例
crawler = WhiteHatCrawler(
name='测试网站ResearchBot',
contact_url='https://my-research-site.com/bot',
contact_email='bot-admin@my-research-site.com'
)
try:
resp = crawler.fetch('https://测试网站.cn')
print(f"Status: {resp.status_code}")
finally:
crawler.close()
这个架构的法律价值:
- 诚实身份:User-Agent 里声明了真实身份和联系方式
- 自适应限速:根据对方响应动态调整,不硬刚
- 完整日志:每次请求的时间、URL、状态码、响应时间全部记录
- 退避机制:遇到 429 自动退避,不强行突破
这些特征在法律上构成"善意使用"的证据——你是一个负责任的爬虫运营者,不是恶意攻击者。