很多新人把爬虫当比赛,看谁抓得快、抓得多。老工程师则更关心能不能长期稳定跑起来:半夜任务崩了没有报警、短时间内被封禁、数据大量重复或丢失,这些问题都会把项目变成“烫手山芋”。
本文基于真实工程经验,挑出五个影响可控性的关键点,做对比说明并给出实战级示例,便于你在评估和落地时快速决策。
为方便判断,每项我都会给出「优点 / 缺点 / 适合的人群」三类结论。比较维度如下:
下面示例使用了爬虫代理(域名/端口/用户名/密码为示例占位),代码偏向实用型,便于直接拿去试验。请在生产环境替换为你自己的凭据与策略。
固定代理上手快,但当目标站点对单一出口 IP 敏感时容易被封;动态代理池要多一步管理,但更稳健,适合中高频长时间运行的任务。
import requests
import random
import time
# ====== 代理配置(示例:亿牛云爬虫代理) ======
proxy_host = "proxy.16yun.cn" # 代理域名(示例)
proxy_port = "3100" # 代理端口(示例)
proxy_user = "16YUN" # 代理用户名(示例)
proxy_pass = "16IP" # 代理密码(示例)
# 固定代理(简单直接)
fixed_proxies = {
"http": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
"https": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"
}
# 简单的动态代理池(示例中用的是同一域名,实际可换不同线路/端口)
proxy_pool = [
f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
# 可以添加更多代理条目(不同口令/端口/线路)
]
def fetch_with_dynamic_proxy(url, timeout=10):
# 从代理池随机挑选一个代理进行请求
proxy = random.choice(proxy_pool)
proxies = {"http": proxy, "https": proxy}
resp = requests.get(url, proxies=proxies, timeout=timeout)
return resp.text
if __name__ == "__main__":
print(fetch_with_dynamic_proxy("https://httpbin.org/ip"))
小结:短期测试或低频脚本用固定代理;规模化、长期采集中优先动态代理池并配合健康检测、回收机制。
直接 sleep 固定秒数最容易实现,但遇到目标站点短期波动或风控时容易触发。自适应策略会根据失败率或目标响应调整节奏,更“听网站的话”。
import time
import random
def fixed_delay_request():
# 固定等待 2 秒
time.sleep(2)
def adaptive_delay_request(prev_error_rate):
# 简单自适应示例:错误率越高,等待越长
base = random.uniform(0.5, 1.5) # 随机抖动
delay = base * (1 + prev_error_rate)
time.sleep(delay)
小结:面对敏感站点优先用自适应调度;对内网或 API,固定间隔更简单也更可预测。
随机 UA 比较粗糙但能打发一部分检测;用浏览器自动化(Playwright/Selenium)获取完整指纹更接近真实访问,但代价是资源消耗更高。
import requests
import random
ua_list = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Safari/605.1.15",
# ... 可扩展更多 UA
]
def request_with_random_ua(url):
headers = {"User-Agent": random.choice(ua_list)}
r = requests.get(url, headers=headers, proxies=fixed_proxies, timeout=10)
return r.text
小结:电商、机票、招聘类站点对指纹敏感时考虑适配浏览器自动化;否则随机 UA 已能解决多数场景。
面对临时网络抖动,单层重试(比如重试三次)常够用。但当代理池、目标站点、解析逻辑都有可能失误时,分层策略(重试 → 换代理 → 延迟再试 → 记录失败入库)更安全。
import requests, time
def robust_get(url, max_try=3):
# 基础重试
for i in range(max_try):
try:
r = requests.get(url, proxies=fixed_proxies, timeout=10)
r.raise_for_status()
return r.text
except Exception as e:
print(f"第{i+1}次失败:{e}")
time.sleep(1 + i) # 退避等待
# 简单兜底:换代理再试(示例)
try:
proxy = random.choice(proxy_pool)
return requests.get(url, proxies={"http": proxy, "https": proxy}, timeout=15).text
except Exception as e:
print("最终失败,记录到失败队列以供人工复查。")
# 这里可做:写入数据库/消息队列/告警
return None
小结:短任务用单层重试;生产级任务设计多级兜底并保留失败记录用于追踪与人工复查。
任务量小、节点少时单机队列(Python 的 queue
)足够;需要横向扩展、容灾、任务持久化时用 Redis、RabbitMQ 或 Scrapy-Redis 等分布式队列更合适。
# 单机队列示例(同步场景)
from queue import Queue, Empty
task_q = Queue()
task_q.put("https://example.com/page1")
def worker():
while True:
try:
url = task_q.get(timeout=5)
except Empty:
break
# 处理 url
task_q.task_done()
小结:预测任务会增长或需要多机协同时,优先上分布式队列方案,并设计幂等与去重机制。
写爬虫不是博“分数”,而是做长期可维护的工程。很多看似微小的设计决定(例如失败如何记录、代理如何回收、任务如何去重)都会在实际运行中放大影响。希望上面对比和代码能帮助你在做技术选型时跑得更稳。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。