XPath 是爬虫开发中最重要的数据解析工具之一。相比正则表达式,XPath 更直观易读;相比 BeautifulSoup,XPath 解析速度更快。
本文从零开始,带你掌握 XPath 的核心语法,并用豆瓣电影 Top250 作为实战案例。
一、XPath 是什么
XPath(XML Path Language)是一种在 XML/HTML 文档中查找信息的语言。它通过路径表达式来定位元素,类似于文件系统的目录结构。
<!-- HTML 文档结构就像一棵树 -->
<html>
<head><title>网页标题</title></head>
<body>
<div class="content">
<ul id="list">
<li class="item">数据1</li>
<li class="item">数据2</li>
</ul>
</div>
</body>
</html>
二、XPath 核心语法
1. 基本路径表达式
| 表达式 | 说明 | 示例 |
|---|---|---|
tagname | 选取所有该标签 | div 选所有 div |
/ | 从根节点选取 | /html/body/div |
// | 任意位置选取 | //li 选所有 li |
. | 当前节点 | |
.. | 父节点 | |
@ | 选取属性 | //a/@href 选所有链接 |
2. 谓语(条件过滤)
谓语用 [] 表示,用于精确定位:
# 基本用法
//div[1] # 第一个 div
//div[last()] # 最后一个 div
//div[position()<3] # 前两个 div
# 按属性筛选
//div[@class="title"] # class="title" 的 div
//a[@id="link1"] # id="link1" 的链接
# 按内容筛选
//a[contains(text(), "下一页")] # 包含"下一页"的链接
//span[starts-with(@class, "star")] # class 以 star 开头的 span
3. 常用函数
text() # 获取文本://h1/text()
@属性名 # 获取属性://img/@src
contains() # 包含://div[contains(@class, "item")]
starts-with() # 开头匹配://div[starts-with(@id, "post")]
normalize-space() # 去除空格://div[normalize-space()="内容"]
三、Python 中使用 XPath
安装 lxml 库:
pip install lxml
基本用法:
from lxml import etree
import requests
# 1. 获取网页
resp = requests.get("https://example.com")
resp.encoding = "utf-8"
# 2. 解析为 XPath 对象
tree = etree.HTML(resp.text)
# 3. 提取数据
titles = tree.xpath('//h1/text()')
links = tree.xpath('//a/@href')
images = tree.xpath('//img/@src')
print("标题:", titles)
print("链接:", links)
四、实战:爬取豆瓣电影 Top250
这个案例使用 XPath 抓取豆瓣电影 Top250 的排名、片名、评分和评价人数。
import requests
from lxml import etree
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
def crawl_douban_top250():
url = "https://movie.douban.com/top250"
resp = requests.get(url, headers=headers)
resp.encoding = "utf-8"
tree = etree.HTML(resp.text)
# 每条电影信息在 <li> 中
items = tree.xpath('//ol[@class="grid_view"]/li')
for item in items:
# 提取排名
rank = item.xpath('.//em/text()')[0]
# 提取片名
title = item.xpath('.//span[@class="title"]/text()')[0]
# 提取评分
rating = item.xpath('.//span[@class="rating_num"]/text()')[0]
# 提取评价人数(文本示例:"3294764人评价")
people = item.xpath('.//span[contains(text(), "人评价")]/text()')[0].strip()
print(f"{rank:>3}. {title} ⭐{rating} {people}")
resp.close()
crawl_douban_top250()
输出效果:
1. 肖申克的救赎 ⭐9.7 2890497人评价
2. 霸王别姬 ⭐9.6 2202234人评价
3. 泰坦尼克号 ⭐9.4 2222751人评价
...
五、进阶:处理分页数据
豆瓣 Top250 一共 10 页,每页 25 条。URL 规律是 ?start=0、?start=25 … ?start=225:
def crawl_all_pages():
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
all_movies = []
for page in range(10):
start = page * 25
url = f"https://movie.douban.com/top250?start={start}"
resp = requests.get(url, headers=headers)
resp.encoding = "utf-8"
tree = etree.HTML(resp.text)
items = tree.xpath('//ol[@class="grid_view"]/li')
for item in items:
movie = {
"rank": item.xpath('.//em/text()')[0],
"title": item.xpath('.//span[@class="title"]/text()')[0],
"rating": item.xpath('.//span[@class="rating_num"]/text()')[0],
"people": item.xpath('.//span[contains(text(), "人评价")]/text()')[0].strip()
}
all_movies.append(movie)
print(f"第 {page+1} 页完成,已爬取 {len(all_movies)} 条")
resp.close()
print(f"\n共爬取 {len(all_movies)} 部电影")
return all_movies
movies = crawl_all_pages()
六、XPath vs BeautifulSoup 对比
| 对比项 | XPath | BeautifulSoup |
|---|---|---|
| 解析速度 | 快(底层 C 语言) | 较慢(纯 Python) |
| 学习曲线 | 先陡后平 | 平缓 |
| 语法简洁度 | 表达式简洁 | 代码可读性好 |
| 适用场景 | 大规模爬虫 | 小型项目、快速开发 |
| 依赖库 | lxml | beautifulsoup4 |
七、踩坑提醒
-
XPath 索引从 1 开始(不是 0):
//div[1] # 第一个 div,不是第二个 -
class 属性注意空格:
# 错误://div[@class="item active"] # 正确://div[contains(@class, "item")] -
text() 和 /text() 的区别:
text()— 当前节点的文本//text()— 所有子节点的文本(递归)
-
页面动态加载:如果 XPath 提取不到数据,检查网页是不是动态加载的(需要 Selenium)
总结
XPath 是爬虫开发的必备技能,掌握核心语法后解析效率远高于其他方式。建议先用浏览器开发者工具(F12 → Elements → 右键 → Copy → Copy XPath)快速获取路径,再根据需要调整。
下篇文章预告:BeautifulSoup4 实战:爬取豆瓣电影 Top250(BS4 版本),对比两种解析方式的优劣。
如果对你有帮助,欢迎点赞、评论、关注【张老师技术栈】,持续分享 Java/Python/爬虫 实战干货。
&spm=1001.2101.3001.5002&articleId=161958716&d=1&t=3&u=f6b5b32e1da74156a35d7bf866006282)
5066

被折叠的 条评论
为什么被折叠?



