解析器的使用
发请求只是第一步。真正有价值的工作,是把拿到的 HTML 或 JSON 解析成你想要的数据。
所以这一节的重点,不是“再发一次请求”,而是学会:
- 从 HTML 中找节点
- 从节点中提取文字和属性
- 从 JSON 中取值
本节目标
- 理解为什么需要解析器
- 学会使用
lxml解析 HTML - 学会使用 XPath 选取节点
- 学会提取文本和属性
- 学会使用
json.loads()解析 JSON - 理解
jsonpath的适用场景
为什么需要解析器
假设你请求到了一个网页,返回内容可能是这样的:
<html>
<body>
<h1>Python 学习空间</h1>
<a href="https://example.com/detail">进入详情</a>
</body>
</html>你真正想要的也许只有:
- 标题文本
- 链接地址
这时候就不能只是把整页 HTML 打印出来,而是要学会“定位”和“提取”。
这就是解析器存在的意义。
HTML 和 JSON 的解析思路不同
如果返回的是 HTML
你通常要:
- 找到目标节点
- 提取节点文本
- 提取节点属性
如果返回的是 JSON
你通常要:
- 把字符串转成 Python 对象
- 再根据键名和层级取值
所以你先要学会判断:当前响应到底是什么类型。
lxml 是什么
lxml 是 Python 中非常常用的 HTML/XML 解析库。
它在爬虫中的价值主要体现在:
- 解析速度快
- 和 XPath 搭配方便
- 适合结构化提取数据
安装:
pip install lxml第一个 lxml 示例
from lxml import etree
html = """
<html>
<body>
<h1>Python 学习空间</h1>
<a href="https://example.com/detail">进入详情</a>
</body>
</html>
"""
tree = etree.HTML(html)
title = tree.xpath("//h1/text()")
link = tree.xpath("//a/@href")
print(title)
print(link)输出结果:
['Python 学习空间']
['https://example.com/detail']这里的重点有两个:
etree.HTML(html)把 HTML 字符串解析成树结构xpath()用来定位并提取目标内容
XPath 是什么
XPath 可以理解成:在 HTML 树结构里查找节点的一种表达方式。
你可以先把它类比成:
- 对 HTML 的“路径查询语言”
最常见的 XPath 用法
选中所有 h1
tree.xpath("//h1")取 h1 的文本
tree.xpath("//h1/text()")取链接的 href
tree.xpath("//a/@href")选中某个 class 的元素
tree.xpath('//div[@class="item"]')选中某个 id 的元素
tree.xpath('//div[@id="box"]')节点文本提取
例如:
<p>这是段落内容</p>提取方式:
tree.xpath("//p/text()")输出结果:
['这是段落内容']注意:XPath 返回的通常是列表,不一定是单个字符串。
属性提取
有很多有价值的数据并不在文本里,而是在属性中。
例如:
- 链接地址在
href - 图片地址在
src
HTML:
<img src="cat.jpg" alt="猫">提取图片地址:
tree.xpath("//img/@src")输出结果:
['cat.jpg']多个节点提取
例如:
<ul>
<li>Python</li>
<li>Linux</li>
<li>Django</li>
</ul>tree.xpath("//li/text()")输出结果:
['Python', 'Linux', 'Django']这在抓取列表页时非常常见。
一个完整 HTML 提取示例
from lxml import etree
html = """
<html>
<body>
<div class="course">
<h2>Python 基础</h2>
<a href="/course/python">查看详情</a>
</div>
<div class="course">
<h2>Django 开发</h2>
<a href="/course/django">查看详情</a>
</div>
</body>
</html>
"""
tree = etree.HTML(html)
titles = tree.xpath('//div[@class="course"]/h2/text()')
links = tree.xpath('//div[@class="course"]/a/@href')
print(titles)
print(links)输出结果:
['Python 基础', 'Django 开发']
['/course/python', '/course/django']这就是列表页提取的基础思路。
JSON 解析
如果响应不是 HTML,而是 JSON,就不需要 lxml,而是直接解析 JSON。
import json
text = '{"name": "小明", "age": 18, "city": "上海"}'
data = json.loads(text)
print(data["name"])
print(data["age"])输出结果:
小明
18json.loads() 的作用是:
- 把 JSON 字符串转换成 Python 对象
解析嵌套 JSON
import json
text = """
{
"code": 200,
"data": {
"user": {
"name": "小明",
"skills": ["Python", "Linux"]
}
}
}
"""
data = json.loads(text)
print(data["data"]["user"]["name"])
print(data["data"]["user"]["skills"][0])输出结果:
小明
Python这说明 JSON 解析本质上就是对 Python 字典和列表取值。
jsonpath 是什么
当 JSON 层级很深,或者你只想快速提取某些字段时,jsonpath 可能更方便。
你可以把它理解成:
- 专门针对 JSON 的路径提取工具
它和 XPath 的思路有点像,只不过 XPath 面向 HTML/XML,jsonpath 面向 JSON。
零基础阶段你先知道它的定位就够了,先把普通 JSON 取值练熟更重要。
怎么判断该用 HTML 解析还是 JSON 解析
这是爬虫中非常重要的判断能力。
如果返回内容长得像页面源码
通常用:
lxml- XPath
如果返回内容长得像:
{"code": 200, "data": [...]}通常用:
response.json()json.loads()
所以第一步永远是先看返回内容到底是什么。
常见错误
1. XPath 写错,但还以为网站没数据
有时候不是网站没数据,而是你没选中正确节点。
2. 以为 xpath() 返回的一定是字符串
实际上通常返回的是列表。
3. 对 HTML 用 JSON 解析
如果内容本身不是 JSON,就不要乱用 json.loads()。
4. 只会提文本,不会提属性
很多关键数据其实在:
hrefsrcdata-*
这些属性里。
练习题
练习 1
写一段 HTML,包含标题和链接,并用 lxml 提取标题文本和链接地址。
练习 2
写一个包含多个 li 的 HTML,提取所有列表项文本。
练习 3
写一个包含 img 标签的 HTML,提取图片的 src 属性。
练习 4
自己定义一个 JSON 字符串,解析后取出其中两个字段。
练习 5
找一个接口返回的 JSON,分析它的层级结构,并手动写出取值路径。
本节小结
解析器的核心价值,是把原始响应转换成你真正需要的数据。
你这一节最重要的收获应该是:
- 知道请求成功后下一步不是结束,而是解析
- 会用
lxml+ XPath 提取 HTML 中的文本和属性 - 会用
json.loads()解析 JSON - 知道什么时候该用 HTML 解析,什么时候该用 JSON 解析
只要这一层练熟,后面做列表页抓取、详情页抓取和接口解析时就会顺很多。