Python 爬虫练习:搭建礼貌的抓取流水线
爬虫是一条流水线,不是一次请求。这些练习把抓取、解析、提取和存储分开,让每个阶段都能在不访问真实网站的情况下测试。
从保存的页面开始
开发时下载一次,把 HTML 保存下来,然后反复解析这个样本。这样调试时不受网络波动影响,也方便测试缺失属性、重复链接等边界情况。
from html.parser import HTMLParser
class Links(HTMLParser):
def __init__(self):
super().__init__()
self.links = []
def handle_starttag(self, tag, attrs):
href = dict(attrs).get("href")
if tag == "a" and href:
self.links.append(href)
p = Links()
p.feed('<a href="/a">A</a><a href="/a">A</a><a href="/b">B</a>')
print(p.links)可以反复运行的样本
单独构造请求
把请求构造放在一个函数里。真正发送时设置描述清楚的 User-Agent 和超时。本站的浏览器运行器不会发送网络请求,所以这些示例只到 Request 对象为止。
from urllib.request import Request
request = Request(
"https://example.com/docs",
headers={"User-Agent": "LearningBot/1.0"},
)
print(request.full_url)
print(request.get_header("User-agent"))这个示例不联网
按状态码分支
不要把 404 页面当成目标页面解析。用一个小函数把状态判断集中起来,重试策略也就有了唯一的位置。
def outcome(status):
if 200 <= status < 300:
return "parse"
if 300 <= status < 400:
return "follow redirect"
if status == 429:
return "back off"
return "stop"
print(outcome(200))
print(outcome(429))一个小的状态策略
保存紧凑的记录
只提取任务需要的字段,其余内容留在原页面。结构化结果可以用字典列表保存,并按稳定键(例如绝对 URL)去重。写入文件或数据库前,结果应当便于检查。
rows = [
{"url": "/a", "title": "A"},
{"url": "/a", "title": "A"},
{"url": "/b", "title": "B"},
]
unique = list({row["url"]: row for row in rows}.values())
print(unique)每个 URL 一条记录
抓取前先读规则
robots.txt 只是起点,不是全部协议。阅读站点条款,表明客户端身份,限制请求频率;没有合法依据时不要收集个人数据。站点明确拒绝时就停止。
robots = "User-agent: *\nDisallow: /private\nCrawl-delay: 2"
rules = {}
for line in robots.splitlines():
if ":" in line:
key, value = line.split(":", 1)
rules[key.strip().lower()] = value.strip()
print(rules["disallow"])
print(rules["crawl-delay"])最小但必要的检查
你的练习清单
- 保存一份真实页面,用样本测试解析器。
- 构造请求时使用可识别的 User-Agent 和超时。
- 分别决定 2xx、3xx、4xx 和 5xx 响应的处理方式。
- 只保存任务需要的字段,并用稳定 URL 作为键。
- 扩大抓取前先阅读 robots.txt 和站点条款。
常见问题
浏览器运行器能抓真实网站吗?
不能。课程运行器用于本地 Python 示例,不会发送任意网络请求。真实抓取应在受控的 Python 环境运行。
应该用 requests 还是 urllib?
两者都可以。urllib 属于标准库;requests 是常用的第三方封装。解析和合规规则相同。
网站阻止我时怎么办?
停止。不要绕过登录、验证码、付费墙或访问控制。应寻找 API 或申请许可。
练习爬虫流水线
12 道题,覆盖请求、HTML 解析、去重和礼貌抓取限制。
继续阅读: