维护中学习资料公开

Python 爬虫入门到可用:请求、解析、反爬与合规

从一次真实抓取需求出发,讲清 requests 请求构造、BeautifulSoup / CSS 选择器解析、分页与翻页、登录态维持、常见反爬的应对边界,以及采集时必须守住的合规底线。

更新于 2026年9月20日发布于 2026年9月20日AI资源库进阶
下载渠道
暂无
文件信息
— · MD + 示例代码
资料数量
1 项
访问方式
公开查看
Python 爬虫入门到可用:请求、解析、反爬与合规 封面
编程开发 · Python
收藏

学习信息

Python 爬虫:从能跑到能用

适合谁

  • 做电商需要看竞品价格、上新节奏、评价变化的人
  • 做内容需要批量收集素材、标题、评论的人
  • 已经会 Python 基础语法,想把「手动复制」变成「自动抓取」的人

先说清楚一件事:爬虫本身不违法,但怎么用有边界。这篇只讲公开页面的合理采集,以及遇到反爬时的正当处理方式。绕过登录鉴权抓取非公开数据、抓取后转售牟利、高频请求打垮对方服务器,这些都不在本文讨论范围内,也不建议任何人去做。

第一道门槛:请求头别偷懒

很多初学者写出的第一行代码就被拒,原因是默认请求头写着 python-requests,对方一眼识别。

import requests

HEADERS = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/126.0 Safari/537.36",
    "Accept-Language": "zh-CN,zh;q=0.9",
}

resp = requests.get("https://example.com/list", headers=HEADERS, timeout=15)
resp.raise_for_status()          # 非 2xx 直接抛错,别让程序带着烂数据往下跑
resp.encoding = resp.apparent_encoding   # 中文站经常自我标错编码
print(resp.status_code, len(resp.text))

timeout 一定要写。不写超时,遇到不响应的站点会把整个脚本卡死,跑批的时候最要命。

解析:优先 CSS 选择器,少写正则

网页结构用 BeautifulSoup 处理足够了,不要一上来就用正则匹配 HTML——标签嵌套一变,正则全废。

from bs4 import BeautifulSoup

soup = BeautifulSoup(resp.text, "lxml")

for item in soup.select("div.product-card"):
    title = item.select_one("h3.title")
    price = item.select_one("span.price")
    print({
        "title": title.get_text(strip=True) if title else "",
        "price": price.get_text(strip=True) if price else "",
        "url": item.get("href") or (item.select_one("a") or {}).get("href", ""),
    })

select_one 可能返回 None,一定要判空。真实网页里缺图、缺价的商品到处都是,不判空的脚本跑到第 300 条就崩。

翻页的三种形态

| 形态 | 特征 | 处理方式 | | --- | --- | --- | | URL 带页码 | ?page=2 | 循环拼 URL,直到返回空列表停止 | | 相对偏移 | ?offset=20 | 步长固定,累加 offset | | 滚动加载 / 无页码 | 点「加载更多」才出数据 | 抓 XHR 接口,或上 Playwright |

遇到第三种,优先打开浏览器开发者工具的 Network 面板,看 XHR 请求返回的是不是 JSON。能直接拿 JSON 就不要解析 HTML,省事且稳定得多。

# 接口型分页:直接拿结构化数据
params = {"page": 1, "pageSize": 20}
r = requests.get("https://example.com/api/items", params=params,
                 headers=HEADERS, timeout=15)
data = r.json()
items = data.get("data", {}).get("list", [])

反爬:先降速,再谈其他

被封的第一反应不应该是找代理池,而是先问自己:我是不是请求太快了?

1. 加间隔:time.sleep(random.uniform(1, 3)),别用固定值,太规律反而异常 2. 复用会话:session = requests.Session(),自动维持 Cookie,减少握手 3. 尊重 robots.txt:先看目标站根目录的 robots.txt,明确禁止的目录不要碰 4. 识别 vertebrates 验证码就停:弹出验证码说明对方已经注意到你,继续硬闯只会换来封 IP

import time, random, requests

session = requests.Session()
session.headers.update(HEADERS)

for page in range(1, 11):
    r = session.get(f"https://example.com/list?page={page}", timeout=15)
    # ... 处理逻辑
    time.sleep(random.uniform(1.2, 2.8))

什么时候该上浏览器自动化

页面数据必须执行 JS 才生成、或者接口参数被加了签名,这时候再考虑 Playwright / Selenium。代价是速度慢几十倍、内存占用高,能用接口解决就别上浏览器。

数据落地与断点续采

抓到的数据别只在内存里,随时写盘,中断了才能续。

import csv, os

FILE = "items.csv"
exists = os.path.exists(FILE)

with open(FILE, "a", newline="", encoding="utf-8-sig") as f:
    writer = csv.DictWriter(f, fieldnames=["title", "price", "url"])
    if not exists:
        writer.writeheader()
    writer.writerows(items)

用 utf-8-sig 是为了让 Excel 直接打开不乱码。断点续采的最简做法:先读已有 CSV 把主键读进集合,抓到重复就跳过。

合规红线(务必看完)

  • 只采集公开可见数据,绕过登录、破解接口鉴权、利用越权漏洞抓取内部数据,均可能构成违法
  • 不要采集个人信息,用户昵称、手机号、收货地址等一旦涉及法律风险陡增
  • 控制频率,以不影响对方正常运行为准;造成服务瘫痪可能构成破坏计算机信息系统罪
  • 不要搬运牟利,把抓来的内容原样发布售卖,涉及著作权侵权
  • 商业用途采集前,优先查看对方是否提供开放 API —— 能用官方 API 就用官方的

常见问题

返回 403 但浏览器能打开? 先补齐 Referer 和完整 UA;仍不行说明有风控,降低频率或换官方 API。

拿到的是乱码? 设置 resp.encoding = resp.apparent_encoding;gzip 未解压时检查响应头。

中文 CSV 乱码? 写入时用 encoding="utf-8-sig"。

下一步

  • 批量去重与增量更新:把主键存 SQLite,每次只写新增
  • 定时任务:Mac/Linux 用 crontab,Windows 用任务计划程序
  • 大规模采集:再去看 Scrapy 框架,先用原生 requests 把单站点跑通更重要

评论建议

欢迎反馈资料质量、链接状态或希望补充的内容,管理员会持续维护。

常见问题

下载链接失效怎么办?
请优先切换其他网盘渠道,并反馈失效链接。

会员能下载所有资料吗?
页面标注为会员专享的资料支持会员下载,具体以当前页面显示为准。

相关资源