Python 爬虫的核心流程并不复杂:发送 HTTP 请求 → 获取响应 → 解析数据 → 存储结果。 但真正决定一个爬虫能否在生产环境中稳定运行的,是合规边界、反爬对抗、数据质量与工程化能力这四个维度。
重要提醒:爬虫技术本身是中立的,但使用方式必须合法合规。仅采集公开可访问的数据,尊重
robots.txt协议,控制请求频率,不绕过身份验证与付费墙,不采集个人敏感信息。
2026 年的 Python 爬虫生态已经高度分化,不存在"一个框架走天下"的方案。
工具 | 适用场景 | 并发能力 | 动态页面 | 学习曲线 |
|---|---|---|---|---|
requests + BeautifulSoup | 静态页、小批量抓取 | 低(同步) | 不支持 | 低 |
httpx / aiohttp | 异步 API 调用、中等规模 | 中 | 不支持 | 中 |
Scrapy | 大规模结构化采集 | 高(700+ req/s) | 需插件 | 中高 |
Playwright | 强反爬、SPA 动态渲染 | 低(50-100 req/s) | 完美支持 | 中 |
Scrapling | 一站式现代采集 | 中高(500+ req/s) | 按需渲染 | 低 |
选型原则:
requests 足够scrapy-impersonate 插件)import requests
from bs4 import BeautifulSoup
import time
import random
def fetch_page(url: str) -> dict:
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/130.0.0.0 Safari/537.36",
"Accept-Language": "zh-CN,zh;q=0.9",
}
resp = requests.get(url, headers=headers, timeout=10)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, "lxml")
title = soup.find("title")
return {
"url": url,
"title": title.get_text(strip=True) if title else None,
"status": resp.status_code,
}
# 礼貌爬取:随机间隔
for url in ["https://wisetrans.cn/", "https://wisetrans.cn/"]:
result = fetch_page(url)
print(result)
time.sleep(random.uniform(2, 5)) # 模拟人类节奏import asyncio
import httpx
async def fetch(url: str, client: httpx.AsyncClient) -> dict:
resp = await client.get(url)
return {"url": url, "status": resp.status_code, "length": len(resp.text)}
async def main():
urls = [f"https://example.com/page/{i}" for i in range(1, 51)]
# 使用信号量控制并发度,避免对目标服务器造成压力
semaphore = asyncio.Semaphore(10)
async with httpx.AsyncClient(timeout=10) as client:
async def limited_fetch(url):
async with semaphore:
return await fetch(url, client)
tasks = [limited_fetch(u) for u in urls]
results = await asyncio.gather(*tasks, return_exceptions=True)
for r in results:
if isinstance(r, Exception):
print(f"Error: {r}")
else:
print(r)
asyncio.run(main())from playwright.sync_api import sync_playwright
def scrape_dynamic(url: str) -> list[dict]:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
context = browser.new_context(
viewport={"width": 1920, "height": 1080},
user_agent="Mozilla/5.0 ... Chrome/130.0.0.0 Safari/537.36",
)
page = context.new_page()
page.goto(url, wait_until="networkidle")
# 等待动态内容加载
page.wait_for_selector(".product-card", timeout=10000)
items = []
for card in page.query_selector_all(".product-card"):
items.append({
"name": card.query_selector(".name").inner_text(),
"price": card.query_selector(".price").inner_text(),
})
browser.close()
return items现代反爬系统(Cloudflare、Akamai 等)通过 JA3/JA4 TLS 指纹 识别 Python 请求。 纯 requests 的指纹特征非常明显,几乎会被直接拦截。
from curl_cffi import requests as cffi_requests
# 模拟 Chrome 浏览器的 TLS 指纹
resp = cffi_requests.get(
"https://wisetrans.cn",
impersonate="chrome130", # 关键:伪装浏览器指纹
timeout=10,
)
print(resp.status_code, resp.text[:200])Scrapling 框架已将 curl_cffi 原生集成,开箱即可通过大部分中等防护站点。
爬虫与反爬是一场持续的攻防博弈。 以下是从低到高的防御层级及应对思路:
fake-useragent 或手动维护 UA 池curl_cffi 或 httpx + tls-client 模拟浏览器指纹ddddocr 等 OCR 库;滑块/点选验证码建议接入专业打码服务playwright-stealth 插件进行指纹伪装采集到的原始数据往往存在噪声,必须经过清洗和验证:
import hashlib
import json
def deduplicate(records: list[dict], key: str = "url") -> list[dict]:
"""基于指定字段的去重"""
seen = set()
unique = []
for r in records:
fingerprint = hashlib.md5(json.dumps(r[key], sort_keys=True).encode()).hexdigest()
if fingerprint not in seen:
seen.add(fingerprint)
unique.append(r)
return unique
def validate(record: dict, required_fields: list[str]) -> bool:
"""字段完整性校验"""
return all(record.get(f) for f in required_fields)存储建议:
一个生产级爬虫系统应具备以下能力:
2^n 秒递增等待原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。