PyQuery 是一个强大的 Python 库,它提供了类似 jQuery 的语法来解析和操作 HTML/XML 文档。
1. 安装 PyQuery
安装 PyQuery:
2. 基本用法
2.1 导入模块
1
| from pyquery import PyQuery as pq
|
2.2 创建 PyQuery 对象
有多种方式可以创建 PyQuery 对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| # 从字符串创建
html_string = """
<html>
<body>
<div id="container">
<p class="item">第一个段落</p>
<p class="item">第二个段落</p>
<a href="https://example.com">链接</a>
</div>
</body>
</html>
"""
doc = pq(html_string)
# 从 URL 创建(自动下载)
doc = pq(url='https://example.com')
# 从文件创建
doc = pq(filename='example.html')
# 从 lxml 元素创建
from lxml import etree
element = etree.fromstring('<div>测试</div>')
doc = pq(element)
|
3. 选择器
PyQuery 支持 CSS 选择器语法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 通过标签名选择
p_elements = doc('p')
# 通过类名选择
items = doc('.item')
# 通过 ID 选择
container = doc('#container')
# 通过属性选择
link = doc('a[href="https://example.com"]')
# 组合选择器
div_p = doc('div p') # div 下的所有 p 元素
|
4. 遍历和操作元素
4.1 遍历元素
1
2
3
4
5
6
7
8
9
10
11
12
| # 遍历每个元素
for item in doc('.item').items():
print(item.text())
# 获取第一个元素
first_item = doc('.item').eq(0)
# 获取最后一个元素
last_item = doc('.item').eq(-1)
# 切片
some_items = doc('.item')[1:3] # 获取第2和第3个元素
|
4.2 获取内容
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 获取文本内容
text = doc('.item').text() # 所有匹配元素的文本合并
text_list = [item.text() for item in doc('.item').items()] # 分别获取
# 获取 HTML 内容
html = doc('#container').html()
# 获取属性值
href = doc('a').attr('href')
# 获取多个属性
for a in doc('a').items():
print(a.attr('href'), a.attr('title'))
|
4.3 操作 DOM
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| # 添加元素
doc('#container').append('<p>新段落</p>')
doc('#container').prepend('<p>开头段落</p>')
# 添加类
doc('p').add_class('new-class')
# 移除类
doc('p').remove_class('item')
# 设置属性
doc('a').attr('target', '_blank')
# 设置文本
doc('p:first').text('修改后的文本')
# 设置 HTML
doc('#container').html('<div>新内容</div>')
# 移除元素
doc('p:last').remove()
# 替换元素
doc('p:first').replace_with('<span>替换内容</span>')
|
5. 筛选元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| # 过滤元素
active_items = doc('.item').filter('.active')
# 排除元素
non_active = doc('.item').not_('.active')
# 查找子元素
children = doc('#container').find('p')
# 查找直接子元素
direct_children = doc('#container').children()
# 查找父元素
parent = doc('.item').parent()
# 查找祖先元素
ancestors = doc('.item').parents()
# 查找兄弟元素
siblings = doc('.item:first').siblings()
|
6. 实际示例
示例 1:解析网页并提取数据
1
2
3
4
5
6
7
8
9
10
11
12
13
| from pyquery import PyQuery as pq
# 从 URL 加载
doc = pq(url='https://news.ycombinator.com')
# 提取所有新闻标题
news_items = doc('.athing')
for item in news_items.items():
title = item.find('.titleline a').text()
link = item.find('.titleline a').attr('href')
print(f"标题: {title}")
print(f"链接: {link}")
print("-" * 50)
|
示例 2:处理本地 HTML 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
| from pyquery import PyQuery as pq
# 从文件加载
doc = pq(filename='data.html')
# 提取表格数据
table_data = []
for row in doc('table tr').items():
columns = [col.text() for col in row('td').items()]
if columns: # 跳过表头(如果表头是 th 标签)
table_data.append(columns)
print(table_data)
|
示例 3:修改和生成 HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| from pyquery import PyQuery as pq
# 创建新的 HTML 文档
doc = pq('<html><body><div id="content"></div></body></html>')
# 添加内容
doc('#content').append('<h1>标题</h1>')
doc('#content').append('<p class="intro">介绍文本</p>')
doc('#content').append('<ul id="list"></ul>')
# 添加列表项
items = ['项目1', '项目2', '项目3']
for item in items:
doc('#list').append(f'<li>{item}</li>')
# 添加样式
doc('head').append('<style>body { font-family: Arial; }</style>')
# 输出结果
print(doc)
|
7. 高级技巧
7.1 处理编码问题
1
2
3
4
5
6
7
8
| # 指定编码
doc = pq(url='https://example.com', encoding='utf-8')
# 或者手动处理
import requests
response = requests.get('https://example.com')
response.encoding = 'utf-8'
doc = pq(response.text)
|
7.2 结合 requests 使用
1
2
3
4
5
6
7
8
9
10
11
12
| import requests
from pyquery import PyQuery as pq
# 使用 requests 获取更灵活的控制
response = requests.get('https://example.com', headers={'User-Agent': 'Mozilla/5.0'})
doc = pq(response.content) # 使用 content 避免编码问题
# 处理需要登录的页面
session = requests.Session()
session.post('https://example.com/login', data={'username': 'user', 'password': 'pass'})
response = session.get('https://example.com/dashboard')
doc = pq(response.text)
|
7.3 XPath 支持
虽然 PyQuery 主要使用 CSS 选择器,但也可以使用 XPath:
1
2
| # 使用 XPath
elements = doc.xpath('//div[@class="content"]/p')
|
8. 注意事项
- 性能考虑:对于大规模 HTML 解析,lxml 本身非常快,但 PyQuery 的便利性会带来一些开销。
- 错误处理:网络请求可能失败,需要适当的异常处理。
- 内存使用:处理非常大的文档时,注意内存使用情况。
- 依赖:PyQuery 依赖于 lxml,确保已正确安装。
9. 常见问题解决
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # 1. 处理缺失的元素
element = doc('.non-existent')
if element: # PyQuery 对象总是真值
print("元素存在")
else:
print("元素不存在")
# 更好的检查方式
if len(doc('.non-existent')) > 0:
print("元素存在")
# 2. 处理多层嵌套
# 使用 find() 而不是直接使用选择器
doc('#container').find('.item')
# 3. 保留原始文档
original_doc = pq(html_string)
modified_doc = original_doc.clone() # 创建副本进行修改
|
PyQuery 是解析和操作 HTML/XML 的强大工具,特别适合熟悉 jQuery 语法的开发者。通过结合 CSS 选择器的便利性和 Python 的强大功能,可以高效地处理各种网页解析任务。