Python 爬虫合规与反爬实战:从 requests 到 Playwright

Python 爬虫合规与反爬实战:从 requests 到 Playwright

"写爬虫不难,难的是写得既抓得到数据、又睡得着觉。"

这两年我带过不少大学生做数据采集的小项目,几乎每个人第一版代码都是直接 requests.get 然后疯狂循环。结果不是被封 IP,就是收到律师函警告。这篇就把我从"野蛮抓取"到"合规可控"的完整经验拆给你,覆盖合规边界、技术选型、基础抓取、JS 渲染处理、登录态、反爬应对和落坑清单。


一、合规边界:先别急着写代码

我实测过,90% 的爬虫新手翻车不是因为技术不行,而是因为没搞清"能不能爬"。合规不是选修课,是写爬虫的第一行代码。

先看 robots.txt。 大多数网站根目录下都有这个文件,比如 https://example.com/robots.txt,它用 User-agentDisallow 告诉爬虫哪些路径禁止访问:

python 复制代码
import urllib.request

# 读取目标站点的 robots 协议,先看清楚人家允不允许
robot_url = "https://example.com/robots.txt"
with urllib.request.urlopen(robot_url, timeout=5) as resp:
    rules = resp.read().decode("utf-8")
    print(rules)  # 重点看 Disallow 行,命中的路径别碰

这几类数据,碰都别碰:

  • 个人信息:手机号、身份证、住址、账号,未经授权抓取涉嫌侵犯公民个人信息;
  • 受版权保护的内容:付费文章、付费课程、图库原图,批量搬运属于侵权;
  • 绕过登录权限才能拿到的内容:人家设了墙,你非要去翻,性质就变了。

礼貌抓取是底线。 单 IP 每秒几十次请求,对方服务器会直接把你当攻击处理,我一般把间隔设在 1~3 秒并错峰限流。国内相关法律红线(如《数据安全法》《个人信息保护法》)不是摆设,量级一大、涉及个人信息、或对对方业务造成实质影响,风险就上来了。动手前先问自己三个问题:对方允许吗?数据敏感吗?我的抓取速率礼貌吗?


二、技术选型:四把工具怎么挑

不同场景用不同武器,别一上来就堆 Playwright,重得要命。

方案 适用场景 代价
requests + BeautifulSoup 静态页面、接口返回 HTML 遇到 JS 渲染就抓瞎
httpx 需要异步、HTTP/2、更现代 API 生态比 requests 略小
Scrapy 大型、需要调度/去重/管道的工程 学习曲线陡,太重
Playwright JS 渲染、需要点击/登录/截图 启动慢、资源占用高

我的经验:能用 requests 解决的绝不开浏览器。只有页面数据靠 JS 动态塞进去、或者必须模拟点击登录时,才上 Playwright。


三、requests 基础抓取实战

先打牢基础。下面这段是我最常用的"稳一点"写法:

python 复制代码
import requests

# 用 Session 复用 TCP 连接,比每次 get 快很多
session = requests.Session()
# 伪装成正常浏览器,别用默认的 python-requests UA
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "Accept-Encoding": "gzip, deflate",  # 让服务器发压缩包,省流量
    "Accept-Language": "zh-CN,zh;q=0.9",
}

try:
    # 超时一定要设,不然一个卡死的请求能挂你一整晚
    resp = session.get("https://example.com/list", headers=headers, timeout=10)
    resp.raise_for_status()  # 4xx/5xx 直接抛异常,别静默吞掉
    print(resp.text[:200])
except requests.exceptions.RequestException as e:
    print("请求失败,重试或跳过:", e)

超时与重试 建议配合 urllib3Retry 或者自己写个简单退避循环,遇到 5xx 等几秒再试,别死磕。

编码与 gzip 坑 :requests 会自动解 gzip,但有时 resp.encoding 猜错导致乱码,手动指定更稳:resp.encoding = resp.apparent_encoding 或直接 resp.content.decode("utf-8")


四、碰到 JS 渲染页面怎么办:上 Playwright

页面源码里根本找不到数据,全靠前端 JS 拉接口填 DOM,requests 只能干瞪眼。这时候我用 Playwright 同步 API:

python 复制代码
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://example.com/spa", wait_until="networkidle")
    # 关键:等某个选择器出现,数据才真正渲染好
    page.wait_for_selector("div.goods-item", timeout=15000)
    items = page.query_selector_all("div.goods-item")
    for it in items:
        print(it.inner_text())
    # 截图存证,出了问题有据可查
    page.screenshot(path="evidence.png")
    browser.close()

我踩过这个坑:没写 wait_for_selector,截图是白屏,抓到的全是空。渲染类页面,等选择器比等固定时间靠谱得多


五、登录态的两种获取方式

很多数据要登录才能看。两种方式我都试过:

  • 方式 A:账号密码表单提交。session.post 带上表单字段。问题是现在很多站有验证码、加密参数、滑块,模拟登录极容易被风控。
  • 方式 B(我推荐):手动登录后复制 cookie 粘贴。 自己在浏览器登录,打开开发者工具把 Cookie 字符串拷出来,塞进请求头。稳、省事、不被风控针对。
python 复制代码
# 方式 B:把浏览器里复制的 cookie 直接用,最稳
headers = {
    "User-Agent": "Mozilla/5.0 ...",
    "Cookie": "sessionid=abc123; csrftoken=xyz; ...",  # 从浏览器 Network 面板复制
}
resp = requests.get("https://example.com/ucenter", headers=headers, timeout=10)

六、反爬手段与应对清单

我整理了一份实战应对表:

反爬手段 表现 应对
频控 403/429 降速、加随机延时、退避重试
IP 封禁 全部请求超时/拦截 代理池,但免费代理极不稳
字体反爬 数字/文字显示错乱 下载字体文件映射编码
CSS 偏移 文字顺序被错位 还原 DOM 真实顺序再取
验证码 弹滑块/图文 打码平台或人工,别硬刚
签名参数 XHR 带 token/sign 浏览器抓包分析算法

关于代理:免费代理池我实测过,十个里有八个连不上或速度个位数,还经常混进蜜罐 IP。真要规模抓取,上收费代理并按量付费,比免费池靠谱一万倍。


七、数据解析与存储

解析优先用 lxml(比 BeautifulSoup 快),存数据用 pandas 直接落 CSV,量大再入库:

python 复制代码
from lxml import html
import pandas as pd

tree = html.fromstring(resp.text)
rows = []
for li in tree.xpath('//ul[@class="list"]/li'):
    rows.append({
        "title": li.xpath("string(.//a)").strip(),
        "link": li.xpath(".//a/@href")[0],
    })
# 落地 CSV,小项目够用了
pd.DataFrame(rows).to_csv("data.csv", index=False, encoding="utf-8-sig")

入库(如 MySQL/SQLite)建议分批 executemany,别一条条插。


八、我踩过的高频坑

坑 1:中文乱码。 没设 encoding,CSV 用 Excel 打开全是乱码。解决:encoding="utf-8-sig",或 resp.encoding = "utf-8"

坑 2:相对 URL 不处理。 抓到的 /a/b 直接当链接用,拼接后 404。解决:from urllib.parse import urljoin; urljoin(base, href)

坑 3:页面结构和本地不一样。 本地跑得好好的,服务器上全空------大概率是 CDN 缓存了旧页面,或动了地域/登录态。先截图对比。

坑 4:并发爬太快被封。 上了多线程瞬间 429。并发数调小、加全局限速令牌桶。

坑 5:内存爆了。 一次性把所有数据塞列表再写。解决:边抓边写、分批落盘,或用生成器。


九、结尾:礼貌爬虫守则

爬虫这件事,技术只是工具,分寸才是门槛。我把日常执行的守则浓缩成一条:单 IP 请求间隔 ≥1 秒、只抓公开且不敏感的数据、尊重 robots 与对方服务器负载、出问题能立刻停。 今晚就把你正在跑的脚本加上限速和超时,再去翻一眼目标站的 robots.txt------这十分钟,比你要熬的无数个封 IP 的夜都值钱。

相关推荐
深蓝电商API1 小时前
MCP 与 AI Agent 如何改变爬虫开发模式?
爬虫·agent·mcp
E-iceblue1 小时前
Excel 列转行/行列转换全指南:从 4 种常见解法到 Python 批量自动化
python·excel·python库·spire.xls
言乐61 小时前
Python + NumPy 从零实现的 BP 神经网络(反向传播)脚本模型,包含前向传播、反向传播、训练和预测,并用 XOR 数据做示例
python·django·virtualenv·pygame·tornado
Ticnix2 小时前
多租户 RAG:让每个用户只检索到自己的知识库
后端·python·agent
ID34610744202 小时前
【课程设计】基于Spring Boot+Vue的游戏账号租赁系统的设计与实现-计算机毕设 附源码50345
javascript·vue.js·spring boot·python·node.js·php·课程设计
夏雪coding2 小时前
RAG 要不要上向量库:720 个 chunk 用 numpy 点积就够了
python·aigc·ai编程
Ticnix2 小时前
我删了 200 行 if-else,把决策逻辑全写进了 System Prompt
python·llm·agent
谢白羽2 小时前
在4×B300用SGLang部署DeepSeek-V4.1 Flash优化实录
笔记·python·llm·llama·sglang
Y3815326623 小时前
SERP 数据清洗实战:字段标准化、日期解析与去重键
开发语言·数据库·python·python数据库