Python 爬虫解析库 parsel 教程
当我们写 Python 爬虫时,解析 HTML/XML 绕不开选择工具。如果觉得 BeautifulSoup 速度慢,Scrapy 自带 Selector 又不想搭框架麻烦?那 Scrapy 底层「抠出来」的轻量级独立库 parsel 绝对是你的菜!支持 XPath+CSS 混合写、内置正则、API 极简、性能炸场,从入门到落地 5分钟就能上手。
1. 快速了解 parsel
它不是新东西,是 Scrapy 官方拆分出来的核心解析库,完美继承了 Scrapy Selector 的所有优势,还不用装整个 Scrapy,是日常小爬虫、数据清洗 HTML 切片工具的首选。
核心优势再列一遍更直观:
- ✅ **双引擎解析:lxml 做底层,支持 XPath 1.0 和 CSS Selector (甚至支持 CSS→XPath 自动转换)
- ✅ **三提取模式:纯 XPath、纯 CSS、CSS+XPath 混合链、原生正则随意切
- ✅ **极简安全 API:
get()/getall()/get(default=) 替代了复杂的错误处理
- ✅ **兼容 Scrapy:代码直接迁移 Scrapy 里零改动直接用,练手→生产无缝衔接
2. 一键安装
只需要 pip 一条命令,自动拉取依赖的 lxml 库:
3. 从 0 到 1 跑通
3.1 构建选择器实例
拿到要解析的内容后,直接用 parsel.Selector(text=) 包装就行,默认解析 HTML 时会自动补全闭合标签、处理编码问题(lxml 做的脏活累活):
from parsel import Selector
# 模拟一段要解析的电商/新闻类 demo HTML
demo_html = """
<html>
<body>
<h1 id="main-title">Parsel 轻量级解析实战</h1>
<ul id="content-list">
<li class="content-item item-0">first item</li>
<li class="content-item item-1"><a href="link2.html">second item</a></li>
<li class="content-item item-0 active"><a href="link3.html"><span>third item</span></a></li>
<li class="content-item item-1 active"><a href="link4.html">fourth item</a></li>
<li class="content-item item-0">fifth item</li>
</ul>
<div data-id="12345" class="dynamic-tag">
<span>隐藏的产品ID是:</span>12345
</div>
</body>
</html>
"""
# 初始化 Selector
sel = Selector(text=demo_html)
3.2 先用最友好的 CSS Selector 定位
喜欢前端或者刚学爬虫的同学优先选 CSS 语法,简单直观,写法和前端样式完全一致。
# 定位所有带 active 类的 li
active_items = sel.css('.content-item.active')
# 只取第一个(注意 get() 是 parsel 独创的,替代了 Scrapy 旧的 extract_first()
print(active_items.get())
# 定位 ID 为 main-title 的标题,取文本
# ::text 是 parsel 对 CSS 的扩展,专门取节点文本
title = sel.css('#main-title::text').get()
print("标题是:", title)
3.3 进阶用 XPath 搞复杂操作
如果遇到多层嵌套、兄弟节点、祖先节点定位,或者 CSS 搞不定的,直接上 XPath 1.0,lxml 原生支持:
# 定位第三个内容列表里带 active 类的 li 下的 a 标签的 href
href_xpath = sel.xpath('//ul[@id="content-list"]/li[contains(@class, "active") and contains(@class, "item-0")]/a/@href').get()
print("XPath 提取的链接:", href_xpath)
# 取所有 li 的文本(不管嵌套多少层 span/a 用 //text()
all_raw_text = sel.xpath('//ul[@id="content-list"]//text()').getall()
print("所有原始文本列表:", all_raw_text)
4. 核心提取方法大揭秘
不管用 CSS 还是 XPath 定位,最后提取都是用这几个通用方法:
4.1 文本提取的细节
- CSS 要用扩展语法
::text 单独取当前节点文本,::attr(属性名) 取属性;
- XPath 用
/text() 取当前节点直接文本,//text() 取当前节点及所有子节点的文本拼接前的列表;
# 1. 取直接子节点纯文本(CSS
direct_text = sel.css('.dynamic-tag > span::text').get()
print("直接子文本:", direct_text)
# 2. 取所有子文本的列表,然后用 join 拼接(更干净
raw_list = sel.css('.dynamic-tag ::text').getall()
clean_text = ''.join(raw_list).strip()
print("拼接后的干净文本:", clean_text)
4.2 属性提取的对比
两种写法都很常用,看哪个顺手:
# CSS 写法
data_id_css = sel.css('.dynamic-tag::attr(data-id)').get()
# XPath 写法
data_id_xpath = sel.css('.dynamic-tag/@data-id').get()
# 这里甚至可以用混合链简化:CSS 定位后接 XPath 属性
data_id_mix = sel.css('.dynamic-tag').xpath('./@data-id').get()
print("三种方式结果一致:", data_id_css == data_id_xpath == data_id_mix)
5. 内置正则表达式直接提复杂文本
有时候文本或者属性里的内容太散,比如价格、手机号、邮箱,直接用正则就行,不用先提出来再处理:
# 5.1 用 .re(正则) 提取所有匹配结果,返回列表
all_item_nums = sel.css('.content-item').re(r'item-(\d)')
print("所有列表项编号:", all_item_nums)
# 5.2 用 .re_first(正则, default=xxx) 提取第一个匹配结果,安全无报错
first_active_num = sel.css('.content-item.active').re_first(r'item-(\d)', default='无匹配')
print("第一个激活项的编号:", first_active_num)
6. 几个实用的小技巧
6.1 链式调用(混合 CSS/XPath 更爽
先写简单直观的 CSS 定位大区域,再写精准的 XPath 处理小细节,效率和可读性拉满:
# 从内容列表里,取所有带 active 类的 li 的 href
hrefs = sel.css('#content-list li.active').xpath('.//a/@href').getall()
print("激活项的所有链接:", hrefs)
6.2 处理缺失值
.get(default=) 和 .re_first(default=) 绝对是爬虫避免 KeyError/IndexError 的神器,再也不用写 try-except 了:
# 假设我们要找一个不存在的 li 的 href
missing_href = sel.css('.content-item.missing::attr(href)').get(default='https://example.com')
print("安全的默认链接:", missing_href)
6.3 定位特定元素的兄弟/祖先节点
用 XPath 轴操作,复杂定位不再愁:
# 第一个 li 的**后面所有兄弟节点
following_li = sel.css('#content-list li:first-child').xpath('./following-sibling::li').getall()
print("第一个 li 后面的所有兄弟:", len(following_li))
# 带 span 的 a 标签的**父级 li
parent_li = sel.css('#content-list li span').xpath('./ancestor::li[1]').get()
print("带 span 的父级 li:", parent_li)
7. 与 Scrapy 无缝迁移
练手用 parsel,生产直接复制粘贴代码:
# 1. 练手代码(parsel
# from parsel import Selector
# sel = Selector(text=demo_html)
# hrefs = sel.css('#content-list li.active').xpath('.//a/@href').getall()
# 2. 生产代码(Scrapy
from scrapy.selector import Selector
# 假设在 Scrapy Spider 的 parse 方法里
def parse(self, response):
# response 自带 selector,甚至不用自己初始化!
hrefs = response.css('#content-list li.active').xpath('.//a/@href').getall()
for href in hrefs:
yield response.follow(href, callback=self.parse_detail)
8. 简单总结
parsel 是轻量级、高性能、灵活度拉满的 HTML/XML 解析工具,从入门到落地只需要掌握:
- 会写简单的 CSS 定位,必要时加 XPath 轴
- 记住
.get()/.get(default=)/.getall() 三个提取方法
- 内置正则直接提复杂内容
- 练手→生产无缝衔接 Scrapy
想深入了解的同学可以看官方文档:parsel 官方文档