数据采集是后端工程师的必备技能,但爬虫项目翻车的概率极高——IP被封、数据丢失、协议踩红线,每一项都可能让整个项目归零。整理5个我踩过的真实案例,附解决方案。
坑一:没上代理池,IP被封到怀疑人生
最常见的坑。单机直连请求,10分钟内IP就被目标网站标记,严重的直接拉入黑名单。
# ❌ 错误做法:单机直连,不封你封谁
import requests
resp = requests.get("https://target-site.com/api/data") # 裸奔
# ✅ 正确做法:代理池轮询
import requests, random
PROXY_POOL = [
"http://user:pass@proxy1.com:8080",
"http://user:pass@proxy2.com:8080",
"http://user:pass@proxy3.com:8080",
]
def fetch(url):
proxy = random.choice(PROXY_POOL)
resp = requests.get(url, proxies={"http": proxy, "https": proxy}, timeout=10)
return resp
# 更进一步:自动剔除失效代理
def get_working_proxy():
for p in PROXY_POOL:
try:
r = requests.get("http://httpbin.org/ip", proxies={"http": p}, timeout=3)
if r.status_code == 200:
return p
except:
continue
raise Exception("所有代理均失效")
坑二:忽略robots.txt,直接触发反爬
很多工程师不看robots.txt就直接上手,结果轻则被警告,重则收到律师函。
# ❌ 拿到URL就直接爬,不管规则
# ✅ 先检查robots.txt
from urllib import robotparser
def can_fetch(url, user_agent="*"):
rp = robotparser.RobotFileParser()
rp.set_url(f"https://target-site.com/robots.txt")
try:
rp.read()
return rp.can_fetch(user_agent, url)
except:
return True # 读取失败默认允许
url = "https://target-site.com/api/data"
if not can_fetch(url):
print("❌ 该URL不允许爬取,换方案")
else:
print("✅ 检查通过,开始采集")
坑三:请求频率没控制,被当DDoS攻击
为了速度拼命发请求,结果触发目标网站的防护机制,整个IP段被封。
# ❌ 并发拉满,一秒100个请求
# 等着被封吧
import concurrent.futures
with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor:
executor.map(fetch, urls) # IP直接没了
# ✅ 严格控频,推荐用 tenacity 做速率限制
from tenacity import retry, stop_after_attempt, wait_fixed, wait_random
import time, requests
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2) + wait_random(0, 1))
def polite_fetch(url):
time.sleep(1) # 每秒最多1个请求
return requests.get(url, timeout=10)
for url in urls:
polite_fetch(url) # 稳定、安全、不会触发防护
坑四:数据直接存数据库,脏数据污染一切
采到了就往数据库塞,没做去重也没做清洗,结果全是一场空。
# ❌ 直接入库,重复数据全进去
def save(data):
db.execute("INSERT INTO items VALUES (:data)", data)
# ✅ 去重写入:哈希唯一键 + 异常捕获
import hashlib
def save_with_dedup(data):
# 生成内容指纹
fingerprint = hashlib.sha256(
(str(data.get("url","") + data.get("title","")).encode())
).hexdigest()
try:
db.execute(
"INSERT INTO items (fingerprint, url, title, content, created_at) VALUES (?,?,?,?,?)",
fingerprint, data["url"], data["title"], data["content"], datetime.now()
)
print("✅ 新增记录")
except Exception as e:
if "UNIQUE constraint" in str(e):
print("⚠️ 重复数据,跳过")
else:
raise # 其他错误继续抛
坑五:没处理动态渲染页面,数据全空
用 requests 爬了一个JavaScript渲染的页面,结果解析出来是空的——因为数据根本不在HTML里。
# ❌ requests 只能拿静态HTML,动态内容拿不到
import requests
r = requests.get("https://app.example.com/list") # 返回的是空白壳
print(r.text) # <div id="app"></div> 什么都没有
# ✅ 换 Selenium / Playwright 渲染等待
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto("https://app.example.com/list")
# 等待数据渲染完成(关键!)
page.wait_for_selector(".data-item", timeout=10000)
# 提取完整HTML(包含动态内容)
content = page.content()
browser.close()
print(content)
避坑总结
| 坑点 | 风险等级 | 核心解法 |
|---|---|---|
| 无代理池 | 🔴 高 | 代理池轮询 + 失效剔除 |
| 忽略robots.txt | 🟡 中 | 先检查再爬,遵守协议 |
| 请求频率失控 | 🔴 高 | tenacity限速 + 单IP合理并发 |
| 数据不去重 | 🟡 中 | 哈希指纹 + 唯一约束 |
| 动态页面用requests | 🟡 中 | Playwright/Selenium渲染等待 |
爬虫的核心不是”能不能爬到”,而是”能不能持续稳定地爬”。上代理、控频率、守规则,数据才能真正为你所用。
⚠️ 声明:本文相关内容仅供参考,爬虫请遵守法律法规和网站协议。