Python爬虫实战:我踩过的5个让项目翻车的坑

数据采集是后端工程师的必备技能,但爬虫项目翻车的概率极高——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渲染等待

爬虫的核心不是”能不能爬到”,而是”能不能持续稳定地爬”。上代理、控频率、守规则,数据才能真正为你所用。

⚠️ 声明:本文相关内容仅供参考,爬虫请遵守法律法规和网站协议。

发表评论

苏ICP备18039580号-2