news 2026/10/17 22:11:04

Python爬虫教程知识点总结

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python爬虫教程知识点总结

前言


学爬虫最怕的是「知识点是散的」:今天记住urlopen的用法,明天背会一个解析器的写法,结果遇到一个新站点还是不知道从哪儿下手。这篇总结的目的就是把散落的知识点挂到一张地图上,让你随时能回答「我现在卡在这一层的哪一步」。


有一件事要先纠正:不少教程把爬虫的知识点分成「基础篇」和「反爬篇」,好像学会反爬才算完整。这个划分是错的。爬虫的知识点只分四层——请求、解析、调度、存储;合规不是第五层,而是贯穿四层的前提。至于「反爬」,多数情况下它对应的正确结论是「对方不允许,那就不抓」,而不是「想个办法绕过去」。本文不涉及任何绕过登录墙、付费墙或风控的内容。


本文所有代码以 Python 3 为基准,只用标准库。Python 2.7 已于 2020 年 1 月 1 日停止维护,print语句、dict.iteritems()、xrange、urllib2这些老写法现在都不能用,文中会在对照表里一并点明。


一、知识地图




层次你要回答的问题常用标准库常见坑



请求东西怎么拿下来urllib.request没设 timeout、字节没解码

解析数据从哪儿抠html.parser嵌套结构提前收尾

调度下一步抓哪儿、抓多少collections.deque+set环状链接无限抓

存储数据怎么落盘json/csv编码没写、CSV 多空行

合规允不允许抓urllib.robotparser跳过检查直接抓



把这张表记住,比记二十个 API 有用:遇到任何问题,先定位它在哪一层。


二、请求层要点



  • urllib.request.urlopen(url, data=None, [timeout, ]*, context=None):data不为None时变成 POST,且必须是字节串。

  • urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None):headers等价于逐个add_header(key, val)。设 UA 的目的是表明身份,不是伪装。

  • 响应对象:status(整数)、headers(HTTPMessage,可.get())、read()(返回字节串)、url。它是上下文管理器,用with自动释放。

  • 字符集:resp.headers.get_content_charset(failobj=None),读不到再回退utf-8。

  • 压缩:自己加了Accept-Encoding: gzip,就要自己判断Content-Encoding并用gzip.decompress()。

  • 异常:urllib.error.URLError是网络错误基类,urllib.error.HTTPError是它的子类、代表错误状态码,同时是类文件对象,有code、reason。

  • 异常分类处理:404 放弃、403 停止、429 退避、网络错误退避重试。


三、解析层要点



  • html.parser.HTMLParser(*, convert_charrefs=True, scripting=False):事件式解析。convert_charrefs从 3.5 起默认True,会帮你把字符引用转成对应字符(script/style内的除外)。

  • 三个回调:handle_starttag(tag, attrs)、handle_data(data)、handle_endtag(tag);另外还有handle_startendtag(tag, attrs)、handle_comment(data)、handle_decl(decl)。

  • attrs是「(名字, 值) 二元组」的列表,不是字典。

  • feed(data)之后一定要close()。

  • 官方文档明确:它不检查结束标签是否与开始标签匹配,也不会为「被外层闭合隐式关闭」的元素调用结束回调。所以嵌套结构要自己用计数器处理。

  • 对结构复杂的页面,选择器式解析更省事,那属于第三方库,具体 API 以各库官方文档为准。


四、调度与并发要点



  • 队列用collections.deque(两端进出都是 O(1)),去重用set。

  • 终止条件要双重:既看有没有下一页,也设页数/条数硬上限。

  • 相对链接用urllib.parse.urljoin(base, href)绝对化;去掉片段用urldefrag()。

  • 爬虫是 I/O 密集任务。CPython 有全局解释器锁(GIL,Global Interpreter Lock),同进程内同一时刻只有一个线程执行字节码,但等待 I/O 时会释放 GIL,所以少量多线程有效;CPU 密集要用多进程或 C 扩展。Python 3.13 起有实验性自由线程(no-GIL)构建,但不是默认构建,不要说「Python 已经没有 GIL 了」。

  • 并发要配限速:并发上限保持很小 + 全局最小请求间隔。不要为了速度去压一个小站点。


五、存储与清洗要点



  • 文本文件一律显式encoding="utf-8"。

  • CSV 必须同时newline="",否则 Windows 上每行之间多一个空行(csv文档要求)。

  • json.dump(..., ensure_ascii=False)让中文以汉字写入而非\uXXXX转义。

  • 长文本拼接用"".join(parts),不要在循环里s = s + piece。

  • 边抓边追加写,别把几万条全堆在内存里。


六、合规清单(写在代码第一行)



  1. 读robots.txt:RobotFileParser的set_url→read→can_fetch,返回False就不抓。

  2. 读不到 robots.txt 时按「不允许」处理,稍后重试。

  3. UA 里写清程序名和联系方式。

  4. 每次请求之间time.sleep,并设总量上限。

  5. 需要登录、付费或 robots 明令禁止的内容,不抓、不绕。

  6. 遵守著作权与用户协议,不把抓来的内容原样再发布。


七、Python 2 与版本差异对照




老写法(Python 2)现行写法(Python 3)说明



print htmlprint(html)3 里print是函数

urllib2.urlopenurllib.request.urlopen模块在 3 里重组过

d.iteritems()d.items()3 里返回视图,iteritems已移除

xrange(n)range(n)3 的range本身就是惰性的

unicode/basestringstr3 里文本统一为str

3 / 2 == 13 / 2 == 1.5,整除写//除法语义变了



版本内部的变化也要知道:字典从 3.7 起保证插入顺序;dict.keys()返回视图而非列表;asyncio.get_event_loop()在 3.12 起没有运行中的事件循环时会发DeprecationWarning,3.14 起直接抛RuntimeError——新代码应当用asyncio.run()或asyncio.get_running_loop()。


实战:把知识点串成一个小脚本


# 适用于 Python 3.8+
import csv
import json
import time
import urllib.parse
import urllib.request
import urllib.robotparser
from html.parser import HTMLParser

UA = "tutorial-sampler/0.2 (contact: notes@example.org)"
DELAY = 1.0
URL = "https://quotes.toscrape.com/"


class TextSpanParser(HTMLParser):
"""收集所有 class 含 text 的 span 的文字。"""

def __init__(self):
super().__init__()
self._in = False
self._buf = []
self.texts = []

def handle_starttag(self, tag, attrs):
if tag == "span" and "text" in dict(attrs).get("class", "").split():
self._in = True
self._buf = []

def handle_data(self, data):
if self._in:
self._buf.append(data)

def handle_endtag(self, tag):
if tag == "span" and self._in:
self._in = False
self.texts.append("".join(self._buf).strip())


def fetch_text(url, timeout=15):
req = urllib.request.Request(url, headers={"User-Agent": UA})
with urllib.request.urlopen(req, timeout=timeout) as resp:
charset = resp.headers.get_content_charset() or "utf-8"
return resp.read().decode(charset, errors="replace")


def robots_allowed(url):
parts = urllib.parse.urlsplit(url)
robots_url = urllib.parse.urlunsplit(
(parts.scheme, parts.netloc, "/robots.txt", "", "")
)
parser = urllib.robotparser.RobotFileParser()
parser.set_url(robots_url)
try:
parser.read()
except Exception:
return False
return parser.can_fetch(UA, url)


def save(records):
with open("quotes.json", "w", encoding="utf-8") as f:
json.dump(records, f, ensure_ascii=False, indent=2)
with open("quotes.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerow(["index", "text"])
for i, rec in enumerate(records, 1):
writer.writerow([i, rec["text"]])


def main():
if not robots_allowed(URL):
print("robots.txt 不允许抓取,退出")
return

parser = TextSpanParser()
parser.feed(fetch_text(URL))
parser.close()

records = [{"text": t} for t in parser.texts if t]
save(records)
print("已保存", len(records), "条")
time.sleep(DELAY)


if __name__ == "__main__":
main()

四十几行代码,把请求、解析、限速、合规、存储全部串了一遍。把它当作模板:换掉 URL、换掉解析器、换掉落盘格式,就是另一个采集任务。


常见坑点


1. 知识点记住了,顺序记反了


❌ 先想怎么写并发和解析,最后才想起来看 robots.txt。 ✅ 顺序永远是:合规 → 请求 → 解析 → 调度 → 存储。


2. 把「绕过反爬」当必修课


❌ 认为学会验证码识别、指纹伪装才算入门。 ✅ 遇到需要登录/付费/robots 禁止的场景,正确结论是不抓。


3.convert_charrefs的默认值记错


❌ 以为默认是False,还自己手工处理字符引用。 ✅ 从 3.5 起默认True,大部分实体字符已经帮你转好了。


4. 把attrs当字典


❌attrs["class"]直接下标。 ✅dict(attrs).get("class", "")。


5. 忘了close()却怪解析器漏数据


❌ 只feed()就取值。 ✅feed()后补close()。


6. 只设「有没有下一页」这一个终止条件


❌ 跟着 next 链接走到天荒地老。 ✅ 再加一个页数/条数硬上限。


7. CSV 没写newline=""


❌open("out.csv", "w", encoding="utf-8")。 ✅open("out.csv", "w", encoding="utf-8", newline="")。


8. 把 GIL 说反


❌ 「多线程能让 CPU 密集的爬虫变快」。 ✅ 多线程对 I/O 密集有效(等 I/O 时释放 GIL),CPU 密集要用多进程。


总结




你记住的这句它对应哪一层



响应体是字节,要按 charset 解码请求

attrs是列表,feed后要close解析

队列 + 去重 + 硬上限调度

显式编码,CSV 加newline=""存储

先can_fetch,不允许就不抓合规

多线程治 I/O,多进程治 CPU并发



爬虫的知识点不多,难的是把它们组织成一张随时能查的地图。请求、解析、调度、存储四层,加上贯穿其中的合规前提,就是全部。真正拉开差距的不是 API 记得多,而是边界处理得好不好:异常怎么分类、循环怎么终止、字段取不到怎么办、什么时候该停手。最后再强调一次没有例外的规则——动手之前,先读目标站的 robots.txt。




版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 21:47:37

基于条件扩散模型的电动汽车充电负荷概率预测

电动汽车充电负荷概率预测,这两年突然从一个小众研究方向变成了配电规划、充电场站运营、需求响应调度等领域绕不开的话题。我最初接触这个题目,是某地区在做小区配电网扩容评估时,发现用传统点预测方法做的充电负荷估算,和实际夏…

作者头像 李华
网站建设 2026/10/16 21:43:48

UQLab rel2.0.0 可靠度分析实战:从 MATLAB 安装到 FORM/MC 配置

简介:UQLab是苏黎世联邦理工学院开发的开源不确定性量化框架,专为MATLAB环境设计,面向科研与工程领域需要处理参数不确定性的用户,覆盖蒙特卡罗模拟、敏感性分析、可靠性分析、代理模型及贝叶斯反演等完整流程,可用于参…

作者头像 李华
网站建设 2026/10/16 21:40:21

数据驱动电商销量增长:用户分层、关联推荐与定价挖掘实战

1. 数据驱动销量的底层逻辑与整体拆解先说一句大实话:很多电商商家对“大数据”的理解还停留在看生意参谋的后台报表层面,每天看看访客数、转化率、销售额,然后凭感觉调调直通车出价、改改主图,这根本不叫大数据挖掘,只…

作者头像 李华
网站建设 2026/10/16 21:32:50

PWN刷题复盘:从ret2libc到格式化字符串与tcache poisoning

BUUCTF-PWN刷题记录已经写到第15篇,这期不是流水账。我特意把最近做的三道题放在一起复盘:一道ret2libc栈题、一道格式化字符串写GOT题、一道tcache poisoning堆题。这三道题覆盖了PWN入门到进阶最常踩的知识点,尤其是动态链接程序怎么泄露地…

作者头像 李华
网站建设 2026/10/17 21:40:14

802.3-2022以太网标准深度解析:25G到100G物理层与10G修订

简介:IEEE Std 802.3-2022 是电气与电子工程师协会发布的以太网标准正式版本,由局域网与城域网标准委员会制定,面向网络设备研发、测试与运维人员,用于统一以太网物理层与介质访问控制层规范,覆盖百兆到四百吉比特的多…

作者头像 李华
网站建设 2026/10/16 21:18:54

AI语音识别如何为听障学生打造实时字幕系统?从技术链路到部署实践

老师讲到一个知识点,听障学生的眼睛要在老师、课本、手语翻译之间来回跳,很容易漏掉半句话。AI语音识别这几年真正的价值,不是替我们把视频自动生成字幕,而是把课堂里的口语实时变成字幕,让听障学生从“看口型、靠猜”…

作者头像 李华