蜘蛛的修炼手册
小哲的公司要做竞品分析和舆情监测——但数据在别人的网站上。手动复制粘贴?3000 个页面会把人逼疯。周师傅说:学爬虫,但先学「规矩」——什么能爬、什么不能爬、怎么爬得又快又稳又不违法。这一本,从 HTTP 到分布式,把爬虫项目的知识点完整走一遍。
数据在金矿里
爬虫 = 用程序替代「手动复制粘贴」师傅!数据分析要竞品价格、行业新闻、用户评论——3000 个页面,我们组三个人手动复制粘贴了一周才弄了 200 条。老板问「能不能让程序自动抓」?
能——这就是爬虫(Web Crawler / Spider):写程序自动访问网页、提取数据。但开讲之前,先把规矩立了:
- ✅ 可以爬:公开数据、授权数据、自己网站的数据、学术研究(遵守规则)
- ⚠️ 慎爬:Robots 协议禁止的、需要登录的、个人隐私数据
- 🚫 严禁:突破登录/验证码防线、爬取个人信息用于非法用途、大规模抓取影响对方服务
一句话:爬虫技术本身是中性工具,怎么用决定它是「工具」还是「凶器」。这一本讲技术,也讲边界。
记住一句话:爬虫的本质,是「模拟浏览器的行为,自动化地获取公开数据」——你手动能看到的公开页面,程序也能;你手动需要登录才能看的,程序一样需要授权。走,第一站,从最底层的 HTTP 开始。
HTTP 基础:爬虫的地基
请求/响应 · 状态码 · Cookie/Session · HTTPS浏览器和服务器怎么说话?爬虫就是在「模拟这套对话」——所以 HTTP 是爬虫的第一课,也是理解「反爬」的前提。
HTTP 就两件事:请求(Request)——客户端说「我要什么」;响应(Response)——服务器给「你要的东西 + 状态码」。
- 请求方法:GET(取数据)、POST(提交数据)——爬虫 90% 用 GET。
- 请求头(Headers):User-Agent(我是谁)、Cookie(我的身份)、Referer(我从哪来)——反爬的「第一道检查点」。
- 状态码:200 成功、301/302 重定向、403 拒绝访问(被反爬了!)、404 不存在、429 请求太频繁(限流了!)、500 服务器错。
- 会话(Session/Cookie):服务器靠 Cookie 认人——登录后带着 Cookie 才能访问需要身份的页面。
HTTPS:加密传输(第三本密码学讲过的 TLS)——爬虫一样抓,因为是「客户端解密后」的数据。
GET /api/products?page=2 HTTP/1.1 ← 请求行:方法 + 路径 + 协议
Host: shop.example.com ← 请求头:目标主机
User-Agent: Mozilla/5.0 ... ← 我是谁(爬虫常伪装成浏览器)
Cookie: session=abc123; token=xyz ← 我的身份凭证
Referer: https://shop.example.com/list ← 我从哪个页面来的
HTTP/1.1 200 OK ← 状态行:成功
Content-Type: application/json ← 响应头:数据类型
{ "products": [{"name":"手机","price":2999}] } ← 响应体:数据!
【状态码速查(爬虫版)】
200 OK 抓到了!
301/302 重定向 自动跟随(requests 默认会)
403 禁止访问 被反爬拦了(第7站)
404 不存在 页面没了/URL 写错
429 请求过多 太快了!要限速(第7站)
500 服务器错误 对方挂了,稍后重试
【Cookie vs Session】
Cookie:客户端存的「小纸条」(身份凭证)
Session:服务端记的「账本」(你的状态)
登录后服务器发 Cookie → 爬虫带着它访问受限页面
【浏览器 DevTools 是爬虫的第一工具】
F12 → Network 面板:看每个请求的 Headers/参数/响应
→ 抓包是后面第 5 站的基础
HTTP 术语
- 请求 / 响应:客户端要什么 / 服务器给什么——一次对话。
- GET / POST:取数据 / 提交数据——两种基础方法。
- 请求头:User-Agent / Cookie / Referer——反爬的第一检查点。
- 状态码:200 / 403 / 429——爬虫的「体检报告」。
- Cookie / Session:身份凭证 / 服务端状态——登录态的钥匙。
- HTTPS:加密传输——不影响爬虫(解密后取数)。
- DevTools Network:浏览器抓包面板——爬虫的第一工具。
本站收获:HTTP = 请求(说我要什么)+ 响应(给我数据+状态码)+ Cookie(我是谁)。会看 DevTools 的 Network 面板,爬虫就入门一半。
请求库:Requests / HTTPX
requests · 会话保持 · 超时重试 · 代理Python 里发 HTTP 请求,requests 是事实标准;HTTPX 是支持异步的新一代。这一站,写爬虫的「手」。
爬虫的基本功:请求发得对 + 出错扛得住 + 频率控制好。Requests 三件套:
- 参数与头:params 拼查询参数、headers 带浏览器 UA、cookies 带身份。
- 会话保持:`requests.Session()` ——同一会话自动带 Cookie(登录后访问受限页)。
- 健壮性:超时必设(不设 = 卡死)、失败重试、状态码检查。
再加 代理(Proxy):换 IP 绕频率限制(合规场景:如访问海外公开数据)——但注意:绕验证码/暴力换 IP 对抗反爬属于灰色地带,合规场景慎用(第 9 站讲边界)。
import requests
# 会话保持(自动管理 Cookie)
s = requests.Session()
s.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0",
})
# 登录后拿 Cookie(示例:POST 表单)
s.post("https://example.com/login",
data={"user": "demo", "pass": "***"}, timeout=10)
# 带参请求列表页
resp = s.get("https://example.com/api/products",
params={"page": 2, "size": 50},
timeout=10)
print(resp.status_code) # 200
print(resp.json()) # JSON 直接解析
# 健壮性:超时 + 重试 + 状态码检查
def safe_get(url, retries=3):
for i in range(retries):
try:
r = s.get(url, timeout=10)
if r.status_code == 200:
return r
if r.status_code == 429: # 限流了!
time.sleep(5) # 尊重限速,等一会
except requests.Timeout:
pass
time.sleep(2 ** i) # 指数退避重试
return None
【HTTPX(新一代)】
import httpx
client = httpx.Client(headers={...})
async with httpx.AsyncClient() as ac: # 异步并发!
rs = await ac.get(url)
→ 高并发场景(第8站)比 requests 强
请求库术语
- requests.Session:会话保持——Cookie 自动管理。
- params / headers / cookies:查询参数 / 请求头 / 身份凭证。
- timeout:超时设置——不设 = 进程卡死。
- 指数退避重试:失败后 1s、2s、4s……重试——优雅重试。
- 429 处理:限流时尊重对方——等一等再抓。
- HTTPX:异步新一代——高并发抓取利器。
- 代理(Proxy):换出口 IP——合规场景谨慎使用。
本站收获:请求 = Session 保持身份 + params/headers 配全 + 超时重试保稳 + 429 限速尊重对方。会发请求,爬虫就有「手」了——下一步是「看懂网页」。
解析:从网页到数据
XPath · CSS 选择器 · BeautifulSoup · 正则抓下来的 HTML 是一堆标签字符串——怎么把「价格、标题、链接」提取成干净的数据?解析是爬虫的「眼睛」。
解析三选一,按场景挑:
- BeautifulSoup(bs4):好学好用,容错强——适合简单页面、快速上手。
- lxml + XPath:快、精准——`//div[@class='price']` 直接定位,复杂页面首选。
- 正则(re):终极兜底——结构化差/藏在 JS 字符串里时用。
核心思路:先找「定位锚点」(class/id/结构),再提取内容——和第八本数据清洗一个道理:先定位,再取值。
from bs4 import BeautifulSoup
from lxml import etree
import re
html = """
<div class="product">
<h3 class="title">无线耳机</h3>
<span class="price">¥299.00</span>
<a href="/p/123">详情</a>
</div>
"""
# ① BeautifulSoup:CSS 选择器
soup = BeautifulSoup(html, "html.parser")
title = soup.select_one("h3.title").text # 无线耳机
price = soup.select_one(".price").text # ¥299.00
# ② lxml + XPath:精准定位
tree = etree.HTML(html)
price2 = tree.xpath("//span[@class='price']/text()")[0]
# ③ 正则:兜底
price3 = re.search(r"¥([\d.]+)", html).group(1) # 299.00
【XPath 速查(爬虫必会)】
//div[@class='price'] 按 class 找
//ul/li[position()=2] 第二个 li
//a/@href 取属性(链接)
//h3//text() 取所有文本
【解析最佳实践】
优先用 class/id 定位(页面结构调整时也好维护)
优先 XPath/CSS(比正则稳),正则做兜底
页面结构变了 → 解析器报错 → 更新选择器(爬虫的日常)
【反爬注意】
有些网站用「字体反爬」(数字用特殊字体渲染,复制出来是乱码)
→ 了解即可,破解属于灰色地带——合规第一
解析术语
- BeautifulSoup:友好解析库——CSS 选择器 / find 全家。
- XPath:XML 路径语言——`//tag[@attr='v']` 精准定位。
- CSS 选择器:`.class` / `#id` / `tag`——前端同款语法。
- 正则:文本模式的终极兜底——结构化差时用。
- 定位锚点:class/id/结构——解析的「瞄准镜」。
- 页面结构变更:解析器失效——爬虫的「日常维护」。
- 字体反爬:数字乱码——了解即可,不教破解。
本站收获:解析 = XPath/CSS 精准定位 + bs4 快速上手 + 正则兜底。网页变数据的关键一步——「先找锚点,再取值」。
动态网页:Playwright
JS 渲染 · Playwright/Selenium · 等待策略 · 无头模式有些页面是「JS 渲染」的——requests 抓回来只有空壳,数据是浏览器执行 JS 后才出现的。这时候需要「真正的浏览器」上场。
两种网页:
- 静态渲染:HTML 里直接有数据——requests 就能抓(前两站)。
- 动态渲染:数据靠 JS 异步加载(Ajax/渲染框架)——requests 拿到空壳。
解法:用浏览器自动化——Playwright(微软出品,新一代主流)或 Selenium(老牌):让真实浏览器打开页面、执行 JS、等数据加载完,再取内容。关键技巧:等待策略(等元素出现再抓,别抢跑)、无头模式(headless,不开窗口省资源)。
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/trending",
timeout=30000) # 打开页面
# 等待数据加载完成(关键!别抢跑)
page.wait_for_selector(".item-card",
timeout=10000) # 等元素出现
# 提取数据
items = page.locator(".item-card").all()
for it in items[:5]:
title = it.locator(".title").inner_text()
print(title)
browser.close()
【Playwright vs Selenium】
Playwright:新、快、API 优雅、自动等待(推荐新项目)
Selenium:老牌、生态广(老项目/兼容性)
【等待策略(三大类)】
显式等待:等某个元素/条件出现(推荐,精准)
隐式等待:固定轮询等待(简单)
硬等待:time.sleep(最笨,别用!)
【反检测(了解)】
无头浏览器特征、webdriver 标记 → 有些站会检测
→ 规避检测属于灰色地带——合规场景用 Playwright 的持久化上下文即可
【适用场景(合规)】
公开动态页面、自己的系统自动化测试、登录态自己授权的采集
动态网页术语
- 静态 vs 动态渲染:数据在 HTML 里 vs 数据靠 JS 加载。
- Playwright / Selenium:浏览器自动化——动态页面的解法。
- 无头模式(headless):不开窗口跑浏览器——省资源。
- 等待策略:等元素出现再抓——显式等待是正道。
- XHR/Fetch:JS 发起的异步请求——动态数据的来源。
- 自动化测试同源:Playwright 也是前端测试工具——一举两得。
本站收获:动态页面 = 真实浏览器(Playwright)打开 + 显式等待 + 提取。requests 抓不到的,浏览器能——「能开浏览器的爬虫,才是完整的爬虫」。
API 抓取:更高效的路
抓包 · JSON 接口 · Token · 逆向基础很多「动态网页」背后的真相:页面只是壳,数据来自一个 JSON 接口——直接抓接口,比开浏览器快一百倍。这一站教你「找到接口」。
核心思路:浏览器能拿到数据,一定有个请求在拉数据——找到它,直接模拟它。
- 抓包:DevTools → Network → 筛选 XHR/Fetch → 找返回 JSON 的请求——这就是接口。
- 看参数:URL 里的查询参数、请求头里的 Token/签名——照抄。
- 直接请求:用 requests 模拟这个接口,JSON 直接解析——不用开浏览器!
进阶(了解层面):签名/加密参数(逆向)——有些接口参数是 JS 算出来的(如 sign=md5(...))。正规途径:看对方是否提供公开 API 文档——有文档就用文档,合规又省心。
【找接口三步】
① F12 → Network → 勾选 XHR
② 刷新页面 / 翻页 → 看 Network 里刷新的请求
③ 找到返回 JSON 的那个 → 复制 URL + Headers
【示例:找到了接口】
GET https://api.example.com/v1/news?page=2&size=20
Headers: x-token: eyJhbGciOiJIUzI1NiJ9... # Token
→ requests 直接调:
import requests
r = requests.get("https://api.example.com/v1/news",
params={"page": 2, "size": 20},
headers={"x-token": "eyJhbGci..."})
data = r.json() # 直接拿到结构化数据!
print(data["items"][0]["title"])
【比浏览器快在哪】
Playwright:每个页面开浏览器 ≈ 1-3 秒
直接抓 API:一个请求 ≈ 0.1 秒 → 快 10-30 倍!
【Token 获取(正规途径)】
公开 API → 申请开发者 Key(官方文档最香)
自己账号登录 → 自己授权范围内使用
→ 逆向破解签名 = 灰色地带,本手册不教
【接口友好的判断】
有公开 API 文档的网站 → 用官方 API(首选!)
没有文档但有稳定 JSON 接口 → 模拟请求(注意 Robots)
原来用 Playwright 抓新闻站:每个页面 2 秒,一天 1 万条要 6 小时。抓包发现网站有稳定的 JSON 接口(公开数据)→ 直接 requests 调接口 → 同样 1 万条只要 20 分钟,还不用开浏览器。**能走接口,绝不走浏览器**——这是爬虫的黄金法则。
API 抓取术语
- 抓包:DevTools Network 看请求——找数据的「水管」。
- XHR / Fetch:JS 发起的异步请求——动态数据的载体。
- JSON 接口:直接返回结构化数据的 URL——爬虫的最爱。
- Token / API Key:接口身份凭证——正规途径申请。
- 官方 API 文档:优先用官方接口——合规又省心。
- 逆向(了解):破解签名参数——灰色地带,不教。
- 黄金法则:能走接口,绝不走浏览器。
本站收获:API 抓取 = 抓包找接口 + 模拟请求直接拿 JSON。比开浏览器快 10-30 倍——「能走接口,绝不走浏览器」是爬虫效率第一法则。
清洗存储:数据落地
清洗 · 去重 · 入库 · 调度 · 增量抓取爬下来的数据是「毛坯」——脏、重复、格式乱。清洗去重后入库,才算真正「拥有」数据。这一站是第八本《数据治理》在爬虫场景的实战。
数据落地四步:
- 清洗:去空白、统一格式、类型转换(价格 "¥299.00" → 299.00)——第八本 Pandas 手艺直接复用。
- 去重:同一个商品抓了 3 遍——按「唯一键」(URL/title)去重,或用布隆过滤器(Bloom Filter)海量去重省内存。
- 入库:小数据 CSV/JSON;结构化数据 MySQL;海量/异构数据 MongoDB/ES(第十二本)。
- 调度与增量:定时任务(每天抓一次)、增量抓取(只抓新增/更新的)——别每次都全量重爬,浪费资源也不礼貌。
import pandas as pd
import pymysql
raw_items = [{"title": " 无线耳机 ", "price": "¥299.00", "url": "/p/123"},
{"title": "无线耳机", "price": "299.00", "url": "/p/123"}] # 重复!
# ① 清洗:去空格、统一格式
df = pd.DataFrame(raw_items)
df["title"] = df["title"].str.strip()
df["price"] = df["price"].str.replace("¥", "").astype(float)
# ② 去重:按 URL 唯一键
df = df.drop_duplicates(subset=["url"])
print(len(df)) # 1 条(重复的没了)
# ③ 入库 MySQL(唯一键防重复)
conn = pymysql.connect(host="localhost", user="root", password="***",
database="crawler")
cur = conn.cursor()
cur.executemany(
"INSERT IGNORE INTO products(title, price, url) VALUES(%s,%s,%s)",
df[["title", "price", "url"]].values.tolist())
# INSERT IGNORE:数据库层面再挡一道重复
conn.commit()
【增量抓取设计】
定时任务(cron/APScheduler):每天 02:00 跑
记录「上次抓取位置」→ 只抓新增/更新的
URL 去重集合(Redis SET / Bloom Filter)——别重复抓
【存储选型】
CSV/JSON :小数据、调试期
MySQL :结构化、要查询(主流)
MongoDB :JSON 原样存、字段不固定
ES :要全文搜索(第12本 ELK 衔接)
数据落地术语
- 清洗:去空格、统一格式、类型转换——第八本手艺。
- 去重(唯一键):按 URL/title 去重——爬虫必须做。
- Bloom Filter(布隆过滤器):海量去重的省内存神器。
- 入库选型:CSV / MySQL / MongoDB / ES——按需求。
- 增量抓取:只抓新增/更新的——别全量重爬。
- 调度:定时任务——爬虫系统的「闹钟」。
- INSERT IGNORE:数据库层防重复——双保险。
本站收获:数据落地 = 清洗(去脏)+ 去重(唯一键)+ 入库(选型)+ 增量(别浪费)。爬下来只是开始,洗干净存好才是「数据资产」。
反爬对抗:道高一尺
UA 检测 · IP 限制 · 验证码 · 频率控制你爬得开心,网站方可不开心——反爬机制层出不穷。这一站讲「常见的反爬是什么」,以及「合规的应对姿势」:尊重规则、优雅爬取。
先讲清楚立场:反爬的本质是网站保护自己资源的合理措施。这一站教的是「理解 + 合规应对」,不是「破解」。常见的反爬手段:
- UA/请求头检测:爬虫的 User-Agent 一眼假 → 应对:模拟正常浏览器 UA(合规伪装,模拟真人访问)。
- IP 频率限制:同一 IP 太快 → 应对:限速(放慢节奏,尊重对方)、合规代理。
- 验证码:识别机器人 → 应对:减少触发(慢一点)、或用官方 API(不破解!)。
- 登录墙:要登录才能看 → 应对:自己账号、自己授权范围。
最重要的「应对」其实是:判断值不值得爬——对方明显不想让你爬,就换个数据源或走官方渠道。
【优雅爬取五原则】
① 慢:单线程 + 随机延迟(2-5 秒),像真人
② 少:只抓需要的字段,不整站拖走
③ 有节制:设置每日总量上限
④ 看 Robots:先看 robots.txt(网站声明哪些不能爬)
⑤ 留身份:User-Agent 写明是采集器 + 联系方式(礼貌!)
【常见的反爬与「合规应对」对照】
反爬手段 合规应对
UA 检测 → 模拟真实浏览器 UA
IP 限频(403/429) → 限速 + 指数退避(尊重对方)
验证码 → 放慢触发;官方 API;换数据源
登录墙 → 自己的账号 + 自己授权范围
JS 加密 → 用 Playwright 正常渲染(非破解)
【限速示例(必须做)】
import time, random
for url in urls:
fetch(url)
time.sleep(random.uniform(2, 5)) # 随机延迟,像真人
【robots.txt 检查】
https://example.com/robots.txt
User-agent: * / Disallow: /private/ ← 别爬 /private/!
【红线(绝对不做)】
✗ 破解验证码绕过人机验证
✗ 暴力撞库/拖库
✗ 大规模抓取打瘫对方服务器(DDoS 级别)
✗ 爬取后商用侵权(第9站展开)
爬虫跑太快被 403 了。小哲的合规处理:① 检查 robots.txt(对方允许公开列表页)→ ② 把并发降到 1、加 3-5 秒随机延迟 → ③ UA 改成真实浏览器 → ④ 恢复抓取,且每日总量限制。对方没有再触发验证码——「慢而稳」才是长期主义。
反爬术语(理解层)
- 反爬机制:UA 检测 / IP 限频 / 验证码 / 登录墙 / JS 加密——网站的自卫手段。
- 合规应对:限速、随机延迟、真实 UA、尊重 Robots——模拟真人而非破解。
- robots.txt:网站声明「哪些别爬」的协议——先看它。
- 429 / 403:限流 / 拒绝——信号:你太快了或不该爬。
- 指数退避:被限后递增等待——优雅重试。
- 红线:破解验证码、撞库、打瘫服务器、商用侵权——绝对不做。
本站收获:反爬的合规应对 = 慢(限速)+ 少(只取所需)+ 尊重(Robots/官方 API)。记住:破解是捷径也是绝路——「优雅爬取」才能长期稳定。
分布式:Scrapy 规模化
Scrapy 框架 · Scrapy-Redis · 增量 · 布隆过滤页面从 3000 涨到 300 万——单机串行抓不动了。这一站上框架:Scrapy 是爬虫的「工业标准」,配 Redis 就能分布式。
Scrapy:Python 最成熟的爬虫框架——调度、下载、解析、管道、去重全内置,还自带异步并发。核心组件:
- Spiders:写解析逻辑的地方(URL 生成 + 数据提取)。
- Items / Pipelines:数据模型 / 清洗入库管道。
- Downloader Middleware:请求中间件——代理、UA 池、重试。
- 调度器 + 去重:请求队列 + URL 去重。
分布式:默认调度器在单机——换成 Scrapy-Redis:请求队列放 Redis,多台机器共享队列,谁有空谁抓——百万级页面的标配。去重用布隆过滤器(Bloom Filter)省内存。
crawler_project/
├── spiders/
│ └── news_spider.py # 解析逻辑
├── items.py # 数据模型
├── pipelines.py # 清洗 + 入库
├── middlewares.py # 代理/UA/重试
└── settings.py # 配置
# news_spider.py(简化)
class NewsSpider(scrapy.Spider):
name = "news"
start_urls = ["https://example.com/news"]
def parse(self, response):
for item in response.css(".news-item"):
yield {
"title": item.css(".title::text").get(),
"url": item.css("a::attr(href)").get(),
}
# 翻页
next_page = response.css("a.next::attr(href)").get()
if next_page:
yield response.follow(next_page, self.parse)
【分布式改造(Scrapy-Redis)】
settings.py:
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
REDIS_URL = "redis://crawler-redis:6379"
→ 请求队列和去重集合都放 Redis
→ 10 台机器跑同一个 spider:共享队列,谁空谁抓
【规模化要点】
并发与延迟平衡:CONCURRENT_REQUESTS 适中(别打瘫对方)
增量抓取:按时间标记,只抓新增
去重:Redis SET / Bloom Filter(亿级 URL 不爆内存)
监控:抓取量、失败率、入库量(第12本 ELK 衔接)
新闻全站 300 万页面:单机 Scrapy 要 20 天。改造:Scrapy-Redis + 5 台机器共享队列 → 4 天跑完,且每台机器限速 2 req/s 不打扰对方;布隆过滤器去重 URL,内存只占原来的 1/10。增量任务每天只抓新增——「规模化但不野蛮」。
Scrapy 术语
- Scrapy:爬虫工业标准框架——调度/下载/解析/管道全家。
- Spider / Item / Pipeline:解析逻辑 / 数据模型 / 清洗入库。
- Middleware:中间件——代理池 / UA 池 / 重试。
- Scrapy-Redis:队列和去重放 Redis——分布式爬虫标配。
- Bloom Filter:亿级 URL 去重的省内存方案。
- 增量抓取:只抓新增——长期任务的正确姿势。
- 并发节制:规模再大也要限速——别打瘫对方。
本站收获:规模化 = Scrapy 框架打底 + Redis 分布式共享队列 + 布隆过滤去重 + 增量抓取。爬得动 300 万页,但永远「节制」——规模和技术要匹配道德。
合规红线:爬虫的边界
Robots · 个保法 · 著作权 · 反不正当竞争爬虫圈有句老话:「技术无罪,用法有罪」。这一站是最重要的一站——不是教你怎么爬更多,而是教你怎么「不踩雷」。
合规四道线,从轻到重:
- ① Robots 协议:网站声明「哪些别爬」的君子协定——遵守它,是爬虫的基本礼貌(虽非法律强制,但影响后续判断)。
- ② 网站条款(ToS):注册时勾选的服务条款——写明「禁止抓取」的,爬了可能构成违约。
- ③ 法律底线:个保法(爬取个人信息需合法正当必要 + 告知同意)、著作权(内容版权属于作者/网站,商用要授权)、反不正当竞争(爬取后直接搬运竞争 → 可能违法)。
- ④ 刑法红线:非法获取计算机信息系统数据罪——突破安全措施、情节严重,是刑事犯罪。
自检三问:公开数据吗?对方允许吗?用途正当吗?——三问全过,才动手。
【动手前自检三问】
✅ 数据是公开的吗?(不需要登录/无安全措施)
✅ 对方允许吗?(robots.txt 允许 / ToS 没禁止 / 有官方 API 优先)
✅ 用途正当吗?(学习/研究/自有数据分析,非侵权商用)
【四道线(由轻到重)】
① Robots 协议:君子协定——先看再爬
② 服务条款:注册时勾选的契约——违约有责
③ 法律:个保法(个人信息)/ 著作权(内容版权)
/ 反不正当竞争(搬库竞争)
④ 刑法:非法获取计算机信息系统数据罪——突破防线+情节严重
【安全做法推荐(按优先级)】
1️⃣ 官方 API(有文档就用文档——最合规!)
2️⃣ 公开数据 + 慢速 + 尊重 Robots
3️⃣ 数据购买 / 合作授权(商业场景首选)
4️⃣ 自建数据 / 用户主动提供
【案例警示(了解)】
· 爬取并公开他人个人信息 → 个保法处罚
· 突破验证码/加密批量拖库 → 刑事风险
· 爬取竞争对手数据直接搬运 → 反不正当竞争诉讼
→ 教训:技术越强,越要懂边界
小哲公司要做竞品价格监控——正规做法:① 查目标网站 robots.txt 是否允许 + 是否有公开 API 或数据合作通道 → ② 优先走官方开放接口或商务合作 → ③ 只取价格等公开字段、低频更新(每日一次)、限速 → ④ 数据仅内部分析,不公开搬运。合规的爬虫,一样能拿到数据,只是「姿势不同」。
合规术语
- Robots 协议:网站声明的「禁爬清单」——君子协定。
- ToS(服务条款):注册契约——禁止抓取条款有约束力。
- 个保法:个人信息处理需合法正当必要——爬个人信息要谨慎。
- 著作权:内容版权——商用需授权。
- 反不正当竞争:搬运竞争数据——法律风险高。
- 刑法红线:非法获取计算机信息系统数据罪——突破安全措施即高危。
- 合规优先级:官方 API > 公开慢爬 > 数据合作 > 别爬。
本站收获:合规 = 自检三问(公开?允许?正当?)+ 四道线(Robots→ToS→法律→刑法)+ 优先官方 API。爬虫最强的能力不是技术,是「知道什么不该爬」。
项目实战:从零搭一个采集系统
架构 · Scrapy 实战 · 监控 · 学习路线知识点齐了,怎么落地成「能用的系统」?这一站,把前面九站串成一个完整的「新闻舆情采集系统」——爬虫项目的标准形态。
一个成熟的爬虫项目 = 六层架构:
- ① 任务调度:定时触发(每天 02:00)、增量任务。
- ② 抓取层:Scrapy 框架 + 限速 + 重试(公开数据)。
- ③ 解析层:XPath/正则提取 + 反爬应对(合规)。
- ④ 清洗层:去重 + 格式化(第八本手艺)。
- ⑤ 存储层:MySQL 结构化 + 去重索引。
- ⑥ 监控层:抓取量/失败率/入库量 + 告警(第十二本 ELK)。
学习路线:Requests 练手 → BeautifulSoup/XPath → Scrapy 框架 → 分布式 → 合规思维——一步一个脚印。
┌─ 调度 ─┐ ┌─ 抓取 ─┐ ┌─ 解析 ─┐ ┌─ 清洗 ─┐ ┌─ 存储 ─┐ ┌─ 监控 ─┐
│ APScheduler│ → │Scrapy │ → │XPath │ → │去重/格式│ → │MySQL │ → │ELK/告警│
│ 每天02:00 │ │限速重试 │ │提取 │ │ │ │唯一索引 │ │抓取量 │
└─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘
【最小可行版本(2 周)】
Week1:requests + XPath 抓一个站点 → 清洗入库
Week2:迁移到 Scrapy → 定时任务 → 监控告警
→ 先跑通再扩展(第十一本老教训)
【避坑清单(血泪)】
✗ 不设超时/重试(进程卡死一整夜)
✗ 不设限速(被 403/封 IP)
✗ 不去重(数据库重复爆炸)
✗ 不设增量(每天全量重爬,浪费+不礼貌)
✗ 不监控(爬挂了三天没人知道)
✗ 不查 robots(惹上官司的前奏)
【学习路线(3 个月)】
第1月:HTTP + Requests + 解析(XPath/bs4)
第2月:动态页面 Playwright + 接口抓取
第3月:Scrapy 框架 + 分布式 + 一个完整项目
+ 始终贯穿:合规思维(第9站三问)
2 周上线:Scrapy 抓 3 个新闻源(公开 RSS/列表页,限速 1 req/3s)→ XPath 提取标题/正文/时间 → 清洗去重入库 MySQL → 每天 02:00 增量抓取 → 抓取量和失败率进 ELK 看板。分析师每天早上看最新舆情,采集系统自动运行三个月零故障——「小而稳,胜过炫而崩」。
实战术语
- 六层架构:调度→抓取→解析→清洗→存储→监控——爬虫系统标准形态。
- 最小可行(MVP):先单站点跑通,再扩展。
- 限速 / 重试 / 超时:健壮性三件套——必设。
- 增量与去重:长期运行的两大基石。
- 监控告警:抓取量/失败率——爬虫也要「可观测」。
- 学习路线:Requests → 解析 → Playwright → Scrapy → 分布式。
- 合规贯穿:从第一天起带着边界意识写代码。
本站收获:实战 = 六层架构串全栈 + 超时重试限速保稳 + 增量去重保效率 + 监控保发现 + 合规保安全。爬虫项目做得好不好,一半看技术,一半看「克制」。
知识点速查 + 工具链
实战前最后一页爬虫知识点全景表
| 环节 | 核心知识点 | 一句话人话 |
|---|---|---|
| HTTP 基础 | 请求/响应、状态码、Cookie/Session、DevTools | 浏览器和服务器怎么说话 |
| 请求库 | requests、Session、超时重试、HTTPX | 爬虫的「手」 |
| 解析 | XPath、CSS 选择器、BeautifulSoup、正则 | 网页变数据的「眼睛」 |
| 动态页面 | Playwright、Selenium、等待策略、无头模式 | 开真浏览器抓 JS 渲染页 |
| API 抓取 | 抓包、JSON 接口、Token、官方 API | 能走接口绝不走浏览器 |
| 清洗存储 | 清洗、去重、MySQL/MongoDB、增量抓取 | 爬下来要洗要存 |
| 反爬应对 | 限速、随机延迟、真实 UA、尊重 Robots | 慢而稳,优雅爬取 |
| 分布式 | Scrapy、Scrapy-Redis、Bloom Filter | 百万页面的规模化 |
| 合规红线 | Robots、个保法、著作权、刑法红线 | 知道什么不该爬 |
| 项目实战 | 六层架构、MVP、监控告警 | 从代码到系统 |
工具链速查
| 用途 | 工具 |
|---|---|
| 抓包看请求 | 浏览器 DevTools Network / Fiddler / Charles |
| 请求库 | requests(同步)/ HTTPX(异步) |
| 解析 | BeautifulSoup + lxml(XPath)+ re |
| 浏览器自动化 | Playwright(新)/ Selenium(老) |
| 框架 | Scrapy(工业标准)+ Scrapy-Redis(分布式) |
| 存储 | MySQL / MongoDB / Redis(去重队列)/ CSV |
| 调度 | APScheduler / cron / Airflow(第九本老朋友) |
| 监控 | ELK(第十二本)/ 简单告警脚本 |
是「模拟浏览器的行为,自动化地获取公开数据」。
慢一点、少一点、尊重多一点,
能走官方 API 就不走弯路,
知道什么不该爬,比会爬什么更重要。