Python解析库
目录
一、lxml库
二、BeautifulSoup库
三、PyQuery库
一、lxml库
教程:https://www.w3school.com.cn/xpath/index.asp
1.安装lxml库
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ lxml
2.解析规则
解析规则:XPath
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 从当前节点选取直接子节点 |
// | 从当前节点选取所有子孙节点 |
. | 选取当前节点 |
.. | 选取当前节点的父节点 |
@ | 选取属性 |
* | 通配符,选择所有元素节点与元素名 |
@* | 选取所有属性 |
[@attrib] | 选取具有给定属性的所有元素 |
[@attrib='value'] | 选取给定属性具有给定值的所有元素 |
[tag] | 选取所有具有指定元素的直接子节点 |
[tag='text'] | 选取所有具有指定元素并且文本内容是text节点 |
3.XPath运算符
运算符 | 描述 | 实例 | 返回值 |
---|---|---|---|
or | 或 | age=19 or age=20 | 如果age等于19或者等于20则返回true反正返回false |
and | 与 | age>19 and age<21 | 如果age等于20则返回true,否则返回false |
mod | 取余 | 5 mod 2 | 1 |
| | 取两个节点的集合 | //book | //cd | 返回所有拥有book和cd元素的节点集合 |
+ | 加 | 6+4 | 10 |
- | 减 | 6-4 | 2 |
* | 乘 | 6*4 | 24 |
div | 除法 | 8 div 4 | 2 |
= | 等于 | age=19 | True或False |
!= | 不等于 | age!=19 | True或False |
< | 小于 | age<19 | True或False |
<= | 小于或等于 | age<=19 | True或False |
> | 大于 | age>19 | True或False |
>= | 大于或等于 | age>=19 | True或False |
4.构建etree实例
(1)从文本构建
示例:
from lxml import etree
def load_text():
text = """
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">forth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</ul>
</div>
"""
html = etree.HTML(text)
result = etree.tostring(html)
print(result.decode("utf-8"))
经过处理后的html代码会被自动修复,如添加一些缺失的标签。
(2)从文件构建
示例:
from lxml import etree
def load_text():
html = etree.parse("./test.html", etree.HTMLParser())
print(type(html))
result = etree.tostring(html)
print(result.decode("utf-8"))
注意:etree.tostring()方法返回的数据为bytes类型,需要调用decode方法将其转换成sgr类型。
5.节点选取
(1)选中所有节点
- 选中所有节点
//*
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//*")
print(result)
- 选中所有的某一类节点
//标签
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//li")
print(result)
(2)选取子孙节点
①选取直接子节点
/标签
/child::标签
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//li/a")
print(result)
②选取后代节点
//标签
/descendant::标签
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//li//a")
print(result)
(3)选取祖先节点
①选取父节点
- 方法1
/..
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//a/..")
print(result)
- 方法2
/parent::
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//a/parent::*")
print(result)
②选取祖先节点
/ancestor::*
/ancestor::标签
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//li[1]/ancestor::*")
print(result)
(4)选取兄弟节点
# 获取该节点后的所有兄弟节点以及这些兄弟节点的所有子孙节点
result = html.xpath("//li[1]/following::*")
print(result)
# 获取该节点后的所有兄弟节点以及这些兄弟节点的所有子孙节点中的第一个节点
result = html.xpath("//li[1]/following::*[1]")
print(result)
# 获取该节点后的所有兄弟节点
result = html.xpath("//li[1]/following-sibling::*")
print(result)
(5)属性匹配
- 选取具有某属性的节点
[@属性]
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//li[@class]")
print(result)
选取拥有class属性的li标签。
- 选取具有某属性且其值符合要求的节点
[@属性=值]
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//li[@class='item-0']")
print(result)
选取拥有属性class='item-0'的li标签。
(6)属性多值匹配
[contains(@属性, 值)]
text = """
<li class="li li-first"><a href="link1.html">first item</a></li>
"""
html = etree.HTML(text)
result = html.xpath("//li[@class='li']/a/text()")
print(result)
result = html.xpath("//li[contains(@class, 'li')]/a/text()")
print(result)
(7)多属性匹配
[contains(@属性, 值) and @属性=值]
[contains(@属性, 值) or @属性=值]
text = """
<li class="li li-first" name='item'><a href="link1.html">first item</a></li>
"""
html = etree.HTML(text)
result = html.xpath("//li[contains(@class, 'li') and @name='item']/a/text()")
print(result)
(8)按顺序位置选取节点
# 选取第一个节点
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//li[1]/a/text()")
print(result)
# 选取最后一个节点
result = html.xpath("//li[last()]/a/text()")
print(result)
# 选取前两个节点
result = html.xpath("//li[position() < 3]/a/text()")
print(result)
# 选取倒数第三个节点
result = html.xpath("//li[last() - 2]/a/text()")
print(result)
6.属性获取
(1)获取节点属性
/@*
/@属性
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//a[@href='link4.html']/../@class")
print(result)
获取拥有属性href='link4.html的a标签的父亲节点的class属性的值。
(2)获取节点内容
/text()
html = etree.parse("./test.html", etree.HTMLParser())
result = html.xpath("//li[@class='item-0']/text()")
print(result)
获取拥有属性class='item-0'的li标签的文本内容。
二、BeautifulSoup库
文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/
1.安装BeautifulSoup库
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ beautifulsoup4
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ bs4
2.解析
(1)文档解析语法
soup = BeautifulSoup(待解析文档, 解析器)
(2)解析器
- 常用解析器
解析器 | 使用方法 | 性能 |
---|---|---|
Python标准库 | BeautifulSoup(html_doc,"html.parser") | 执行速度适中 文档容错能力强 |
lxml HTML 解析器 | BeautifulSoup(html_doc,"lxml") | 执行速度快 容错能力强 要求安装lxml扩展 |
lxml XML 解析器 | BeautifulSoup(html_doc,"xml") BeautifulSoup(markup,["lxml", "xml"]) |
支持解析xml 执行速度快 要求安装外部扩展 |
html5lib解析器 | BeautifulSoup(html_doc,"html5lib") | 以浏览器的方式解析文档,生成HTML5格式文档 执行速度慢 最好的容错性 要求安装html5lib扩展 |
- 解析器安装
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ lxml
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ html5lib
3.修复文档
soup = BeautifulSoup(html, "lxml")
print(soup.prettify())
4.节点选取
# 整个HTML文档
soup
# title节点的HTML文本
soup.title
# title节点的文本内容
soup.title.string
print(type(soup))
print(type(soup.title))
print(type(soup.title.string))
(1)按标签名
# 获取节点名称
print(soup.title.name)
# 获取属性值(字典类型)
print(soup.p.attrs)
print(soup.p.attrs['name'])
# 获取文本内容(str类型)
print(soup.p.string)
# 嵌套选择
print(soup.head.title)
# 关联选择
# contents属性:选取直接子节点
print(soup.p.contents)
(2)按节点关系
# 获取直接子节点(返回列表)
print(soup.p.contents)
# 获取直接子节点(返回生成器)
for i, child in enumerate(soup.p.children):
print(i, child)
# 获取所有子孙节点(返回生成器)
for i, child in enumerate(soup.p.descendants):
print(i, child)
获取直接父节点:parent
获取祖先节点:parents
获取兄弟节点:next_sibling(下一个兄弟节点) | previous_sibling(上一个兄弟节点)
next_siblings(后面的所有兄弟节点) | previous_siblings(前面的所有兄弟及诶单)
(3)find方法
- find_all()方法:返回符合条件的所有节点元素
# 通过name查找
print(soup.find_all(name="ul"))
print(type(soup.find_all(name="ul")[0]))
print(soup.find_all(name="ul")[0].find_all(name='li'))
# 通过属性查找
print(soup.find_all(attrs={'id': 'list'}))
print(soup.find_all(attrs={'id': 'list', 'name': 'elements'}))
print(soup.find_all(id='list2'))
print(soup.find_all(class_='list'))
# 通过文本查找节点
import re
print(soup.find_all(text=re.compile('^1+')))
print(type(soup.find_all(text=re.compile('^1+'))[0]))
- find():返回单个元素(即匹配的第一个元素)
find_parent() | find_parents()
find_next_sibling() | find_next_siblings()
find_previous_sibling() | find_previous_siblings()
find_next() | find_all_next():返回节点后 第一个|所有 符合条件的节点
find_previous() | find_all_previous():返回节点前 第一个|所有 符合条件的节点
(4)CSS选择器
soup.select("CSS选择器")
三、PyQuery库
1.安装PyQuery库
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ pyquery