共计 4532 个字符,预计需要花费 12 分钟才能阅读完成。
python 简单易懂的 lxml 读取 HTML 节点及常用操作方法
1. 初始化和基本概念
lxml
是一个强大的 pyth 库,用于处理 XML 和 HTML 文档。- 它提供了类似 BeautifulSoup 的功能,但性能更高。
- 在使用
lxml
时,通常会先解析 HTML 或 XML 文档,得到一个 ElementTree 对象。
pip install lxml
2. 解析 HTML 文档
-
使用
lxml.html.fromstring(html)
来从字符串中创建一个 ElementTree 对象。 -
示例:
from lxml import html html_content = '
Hello world!
' tree = html.fromstring(html_content)或者使用 etree.HTML(rhtml_content)来创建 ElementTree 对象:
from lxml import etree
html_content = 'Hello world!
'
tree = etree.HTML(html_content)
3. XPath 选择器
-
XPath 是一种用于在 XML 文档中查找信息的语言。
-
lxml
支持 XPath 选择器,可以用来定位文档中的元素。 -
示例:
paragraphs = tree.xpath('//p')
4. 遍历节点
5. 获取节点属性
-
使用
.attrib
属性来获取节点的所有属性。 -
示例:
class_name = node.attrib.get('class', '')
在使用 lxml
处理 HTML 或 XML 文档时,获取节点的属性和属性值是非常常见的需求。下面详细解释如何获取标签的全部属性以及如何分别获取单个属性和属性值。
1. 获取标签的全部属性
在 lxml
中,你可以通过访问节点的 attrib
属性来获取所有属性。attrib
是一个字典,键是属性名,值是属性值。
示例代码:
from lxml import html
html_content = '''
Hello, world!
'''
tree = html.fromstring(html_content)
div_node = tree.xpath('//div')[0]
all_attributes = div_node.attrib
print("All attributes:", all_attributes)
2. 分别获取单个属性和属性值
如果你只需要获取某个特定属性的值,可以直接通过键访问字典中的值。如果属性不存在,则可以使用 get
方法提供一个默认值。
示例代码:
id_attribute = div_node.attrib.get('id', 'default-id')
print("ID attribute:", id_attribute)
class_attribute = div_node.attrib.get('class', 'default-class')
print("Class attribute:", class_attribute)
3. 获取属性值
如果属性名已知,可以直接通过键访问字典中的值。如果属性名未知或需要处理多个属性,可以遍历 attrib
字典来获取所有属性及其值。
示例代码:
for attr_name, attr_value in div_node.attrib.items():
print(f"Attribute: {attr_name}, Value: {attr_value}")
4. 处理特殊情况
在某些情况下,属性可能包含空格分隔的多个值(例如 class
属性),这时你可以使用 split
方法来分割字符串。
示例代码:
class_values = div_node.attrib.get('class', '').split()
print("Class values:", class_values)
5. 综合示例
下面是一个综合示例,展示了如何获取节点的所有属性、单个属性以及如何处理特殊情况下的属性值。
from lxml import html
html_content = '''
Hello, world!
'''
tree = html.fromstring(html_content)
div_node = tree.xpath('//div')[0]
all_attributes = div_node.attrib
print("All attributes:", all_attributes)
id_attribute = div_node.attrib.get('id', 'default-id')
print("ID attribute:", id_attribute)
class_attribute = div_node.attrib.get('class', 'default-class')
print("Class attribute:", class_attribute)
for attr_name, attr_value in div_node.attrib.items():
print(f"Attribute: {attr_name}, Value: {attr_value}")
class_values = div_node.attrib.get('class', '').split()
print("Class values:", class_values)
6. 获取节点文本
或者如果下面还有子节点的话,最好是用:
link_name = ''.join(child.itertext()).strip().replace('n', '').strip()
link_name = re.sub(r's+', '', link_name ).strip()
7. 获取节点路径
1. 获取最末尾节点路径
last_element = path.split('/')[-1] if '/' in path else path
8. 检查节点类型(标签名)
9. 子节点操作
-
使用
.getchildren()
来获取节点的所有子节点,node.getparent()获取节点的所有父节点。 -
示例:
children = node.getchildren()
10. 提取属性值
11. 节点转换为字符串 HTML
-
使用
etree.tostring(node)
来将节点转换为字符串形式。 -
示例:
node_html = etree.tostring(node, pretty_print=True, encoding='unicode')
12. 计算文本密度
-
文本密度是指文本相对于其他非文本内容(如图片、链接)的比例。
-
通过计算节点中的文本长度与节点总长度的比例来估算文本密度。
-
示例:
text_density = len(node.text_content()) / len(etree.tostring(node))
13. 处理列表页面
-
在处理列表页面时,有时候需要检查是否有特定的类名来进行对应操作,如
'list'
。 -
示例:
if 'list' in a_element[0].get('class', '').lower(): pass
扩展
构建包含属性的 XPath 路径
流程:
1. 获取子节点的 XPath 路径
首先,我们遍历一个节点的所有子节点,并获取每个子节点的 XPath 路径。
for child in node.getchildren():
xpath_path = '/' + node.getroottree().getpath(child)
2. 获取子节点的所有属性
对于每个子节点,我们获取其所有属性:
attributes = child.attrib
3. 构建包含属性的 XPath 路径
接下来,我们根据子节点的属性构建一个完整的 XPath 路径。如果子节点有属性,我们会在 XPath 路径后面加上属性条件。
3.1 属性存在时
如果子节点有属性,我们构建一个包含所有属性的 XPath 路径:
if attributes:
xpath_with_attributes = xpath_path + "["
for i, (key, value) in enumerate(attributes.items()):
xpath_with_attributes += f"@{key}='{value}'"
if i len(attributes) - 1:
xpath_with_attributes += "and"
xpath_with_attributes += "]"
attributes.items()
返回一个迭代器,其中包含了属性的键值对。enumerate(attributes.items())
为每个属性分配一个索引。f"@{key}='{value}'"
构建一个 XPath 条件,表示属性key
的值为value
。- 如果不是最后一个属性,则添加
"and"
以连接多个条件。 - 最后添加
"]"
来结束 XPath 条件。
3.2 属性不存在时
如果子节点没有属性,我们直接使用原始的 XPath 路径:
else:
xpath_with_attributes = xpath_path
综合示例
下面是一个完整的示例代码,展示了如何遍历节点的子节点并构建包含属性的 XPath 路径:
from lxml import html
html_content = '''
Hello, world!
Example Link
'''
tree = html.fromstring(html_content)
root_node = tree.xpath('//div[@id="container"]')[0]
for child in root_node.getchildren():
xpath_path = '/' + root_node.getroottree().getpath(child)
attributes = child.attrib
if attributes:
xpath_with_attributes = xpath_path + "["
for i, (key, value) in enumerate(attributes.items()):
xpath_with_attributes += f"@{key}='{value}'"
if i len(attributes) - 1:
xpath_with_attributes += "and"
xpath_with_attributes += "]"
else:
xpath_with_attributes = xpath_path
print(f"XPath Path: {xpath_path}")
print(f"XPath with Attributes: {xpath_with_attributes}")
print("Attributes:", attributes)
print("")
详细解释
-
获取子节点的 XPath 路径:
node.getchildren()
返回节点的所有子节点。node.getroottree().getpath(child)
获取子节点的 XPath 路径。- 我们在路径前加上
/
来确保路径格式正确。
-
获取子节点的所有属性:
child.attrib
返回子节点的所有属性及其值。
-
构建包含属性的 XPath 路径:
- 如果子节点有属性,我们构建一个包含所有属性的 XPath 路径。
- 使用
enumerate
来为每个属性分配一个索引,以便在多个属性之间添加and
。 - 如果子节点没有属性,我们直接使用原始的 XPath 路径。
原文地址: python 简单易懂的 lxml 读取 HTML 节点及常用操作方法