单元 3 · 进阶爬取 — 预计 50 分钟
多级页面爬取
📍 本课路径
- 设计列表到详情的两级抓取
- 维护已抓取集合去重
- 合理并发提速
🎯 学习节奏:① 看目标 → ② 先思考再动手 → ③ 在运行器写代码 → ④ 失败时按提示重试 → ⑤ 通过后看思路
很多数据「列表页看概要、点进去才看全」。比如图书列表只显示书名,详情页才有作者、简介、评分。这就是两级爬取:先抓列表拿链接,再逐个进详情页抓细数据。
一、两级结构长这样
列表页 → 提取每条的详情链接 → 逐条请求详情页 → 解析细数据 → 合并
二、可运行:列表取链接 + 详情二次解析
下面模拟一个两级场景——先从列表抽链接和书名,再从「详情页」取作者,合并成完整记录:
from bs4 import BeautifulSoup
# 1) 列表页 HTML
list_html = """<ul class="list">
<li><a href="/book/1">Python 入门</a></li>
<li><a href="/book/2">爬虫实战</a></li>
</ul>"""
# TODO 1: 解析 list_html,提取每个 a 的 href 和文本,存入 items 列表
list_soup = BeautifulSoup(list_html, "lxml")
items = []
for a in list_soup.select("li a"):
items.append({"url": a.get("href"), "title": a.get_text(strip=True)})
# 2) 模拟详情页(真实场景用 requests.get(base + item["url"]))
detail_pages = {
"/book/1": "<div class='author'>张三</div>",
"/book/2": "<div class='author'>李四</div>",
}
# TODO 2: 遍历 items,根据 url 从 detail_pages 取详情 HTML,解析 .author 文本
for it in items:
d_soup = BeautifulSoup(detail_pages[it["url"]], "lxml")
it["author"] = d_soup.select_one(".author").get_text(strip=True)
# TODO 3: 打印完整记录
print("完整记录:")
for it in items:
print(it)三、用 set 去重
列表页之间常有重复条目(尤其翻页重叠)。用 set 存已抓过的链接,遇到重复就跳过:
links = ["/book/1", "/book/2", "/book/1", "/book/3", "/book/2"]
seen = set()
unique = []
# TODO: 遍历 links,若 link 不在 seen 中就加入 unique 并加入 seen
for link in links:
if link not in seen:
seen.add(link)
unique.append(link)
print("去重后:", unique)四、并发提速(进阶)
详情页一多,串行请求会很慢。可用线程池并发(本地运行):
from concurrent.futures import ThreadPoolExecutor
import requests
def fetch_detail(url):
return requests.get(url, timeout=5).text
with ThreadPoolExecutor(max_workers=5) as pool:
details = pool.map(fetch_detail, detail_urls)
并发不是越快越好——
max_workers别太大,配合time.sleep才礼貌。
五、小结
- 两级爬取:列表页抽链接 → 详情页抓细数据 → 合并。
- 先把链接和概要收集成列表,再统一进详情页,结构更清晰。
set去重:用「已见集合」跳过重复链接。- 量大用
ThreadPoolExecutor并发,但务必控制频率。 - 去 Level 3 靶站 实战列表 + 详情。
靶站实战:前往 /practice/level3-detail/ 动手练习本课内容。