Python 爬虫解析库 parsel 教程
如果你在写 Python 爬虫时,觉得 BeautifulSoup 解析速度不够快,又不想为了一个高效的 Selector 去搭建 Scrapy 框架,那么今天介绍的这个库就是你的「救星」——parsel。
它从 Scrapy 中抽离出来,继承了强大的选择器能力,同时保持了极简和轻量,让你在几分钟内就能上手,写出清晰、高效的解析代码。
1. 什么是 parsel?
parsel 并不是一个新项目,它是 Scrapy 官方拆分出来的核心解析库,原本就是 Scrapy 框架里的 Selector。
它拥有 Scrapy Selector 的全部优势,同时可以独立安装、独立使用,非常适合:
- 写小型爬虫
- 数据清洗
- 不想引入整个 Scrapy 但又要高性能解析的场景
parsel 的核心亮点:
- ✅ 双引擎解析:底层基于 lxml,支持 XPath 1.0 和 CSS Selector(甚至支持 CSS→XPath 自动转换)
- ✅ 三种提取模式:纯 CSS、纯 XPath、CSS 与 XPath 混合链式调用,想怎么切就怎么切
- ✅ 极简且安全的 API:
get()、getall()、get(default=…) 替代了过去繁琐的错误处理
- ✅ 内置正则支持:不用先把内容取出来再单独做正则,直接在选择器上调用
.re() 或 .re_first()
- ✅ 与 Scrapy 无缝对接:练手代码可以直接搬到 Scrapy 的
parse 方法里,零改动
2. 安装
只需要一条 pip 命令,parsel 会自动安装依赖的 lxml:
安装完成后,就可以在任何 Python 脚本中使用了。
3. 快速上手
我们通过一段模拟的 HTML 内容,演示 parsel 最常用的提取方式。
3.1 创建 Selector 对象
拿到 HTML 文本后,用 parsel.Selector(text=…) 包装即可。parsel 底层会借助 lxml 自动处理闭合标签、编码等问题。
from parsel import Selector
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>
"""
sel = Selector(text=demo_html)
3.2 用 CSS 选择器提取
如果你有前端基础,CSS 选择器是最友好的方式,写法和你平时写样式几乎一样。
# 选中所有带 active 类的 li
active_items = sel.css('.content-item.active')
# 取第一个匹配结果(get() 是 parsel 独有的便捷方法)
print(active_items.get())
# 提取标题文本 ::text 是 parsel 对 CSS 的扩展,专门用来获取节点内的文本
title = sel.css('#main-title::text').get()
print("标题是:", title)
3.3 用 XPath 提取
遇到复杂的嵌套关系、需要定位兄弟节点或祖先节点时,XPath 会更加灵活。
# 获取 class 包含 active 且包含 item-0 的 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 内部的文本(无论嵌套多少层)
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() 获取当前节点及所有子孙节点的文本片段(返回列表)。
# CSS 获取直接子节点的文本
direct_text = sel.css('.dynamic-tag > span::text').get()
print("直接子文本:", direct_text)
# 获取所有内部文本(列表),然后拼接成一个干净字符串
raw_list = sel.css('.dynamic-tag ::text').getall()
clean_text = ''.join(raw_list).strip()
print("拼接后的干净文本:", clean_text)
4.2 提取属性的多种写法
parsel 支持多种风格提取属性,你可以按自己的习惯选择。
# CSS 写法
data_id_css = sel.css('.dynamic-tag::attr(data-id)').get()
# XPath 写法
data_id_xpath = sel.xpath('//div[@class="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. 内置正则,一步提取复杂内容
当你想从文本或属性里提取手机号、价格、编号等特定格式的内容时,可以直接在选择器上调用 .re() 或 .re_first(),不用再自己写一堆后处理逻辑。
# 提取所有 li 中 item- 后面的数字
all_item_nums = sel.css('.content-item').re(r'item-(\d)')
print("所有列表项编号:", all_item_nums)
# 提取第一个 active li 中 item- 后面的数字,未匹配时返回默认值
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 处理内部细节,代码既好读又高效。
# 在 #content-list 里面找到所有带 active 类的 li,再取内部 a 标签的 href
hrefs = sel.css('#content-list li.active').xpath('.//a/@href').getall()
print("激活项的所有链接:", hrefs)
6.2 安全处理缺失值
parsel 的 .get(default=…) 和 .re_first(default=…) 可以让你彻底告别 try-except 的麻烦,即使元素不存在也不会中断爬虫程序。
# 查找一个不存在的 li 的 href,返回预设的默认链接
missing_href = sel.css('.content-item.missing::attr(href)').get(
default='https://example.com'
)
print("安全的默认链接:", missing_href)
6.3 XPath 轴操作:定位兄弟/祖先节点
复杂页面中经常需要找「隔壁的兄弟」或「父级容器」,XPath 轴可以轻松搞定。
# 第一个 li 后面所有的兄弟 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 和 Scrapy 的 Selector 接口完全一致,练手时写的解析代码可以直接复制到 Scrapy 的爬虫里使用。
# 练手时的 parsel 代码
# from parsel import Selector
# sel = Selector(text=demo_html)
# hrefs = sel.css('#content-list li.active').xpath('.//a/@href').getall()
# 在 Scrapy 的 Spider 里(response 自带 selector,无需手动创建)
def parse(self, response):
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() 三个提取方法;
- 善用内置正则
.re()、.re_first() 提取复杂内容;
- 练习代码直接迁移到 Scrapy,无缝衔接正式项目。
如果想了解更多细节,可以查阅官方文档:parsel 官方文档。