BeautifulSoup官方文档介绍:BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库。使用BeautifulSoup更多方便,避免使用正则表达式容易出错,提高效率。
1.解析器
BeautifulSoup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml。以下为BeautifulSoup官方文档对支持的解析器优缺点对比。
解析器 | 使用方法 | 优势 | 劣势 |
---|---|---|---|
Python标准库 | BeautifulSoup(markup, "html.parser") | Python的内置标准库、执行速度适中 、文档容错能力强 | Python 2.7.3 or 3.2.2)前的版本中文容错能力差 |
LXML HTML 解析器 | BeautifulSoup(markup, "lxml") | 速度快、文档容错能力强 | 需要安装C语言库 |
LXML XML 解析器 | BeautifulSoup(markup, "xml") | 速度快、唯一支持XML的解析器 | 需要安装C语言库 |
html5lib | BeautifulSoup(markup, "html5lib") | 最好的容错性、以浏览器的方式解析文档、生成 HTML5 格式的文档 | 速度慢、不依赖外部扩展 |
推荐使用lxml解释器,效率更高。注意:不同的解析器返回不同的结果
2.基本使用
通过解析器,BeautifulSoup可以传入一段字符串或文件。
from bs4 import BeautifulSoup
>>> soup = BeautifulSoup("<html>data</html>")
>>> print(soup.html.string)
data
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag , NavigableString , BeautifulSoup , Comment。接下来使用以下文档进行说明。
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
soup = BeautifulSoup(html_doc, 'lxml')
print(soup.prettify())
-
tag
通俗来说tag就是HTML或XML文档的标签,例如上面文档的head、title、p等,如果想获取 <head> 标签,只要用 soup.head。
>>> soup.head
<head><title>The Dormouse's story</title></head>
>>> soup.body.b
<b>The Dormouse's story</b>
>>> soup.a
<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
可以看到a点只是返回第一个,如果需要历遍全部则需要用find_all('a')。
tag有多种属性,其中两个最重要的就是name和attributes。name一般返回标签本身(soup返回document),注意,tag属性操作方法和字典一样。
>>> soup.name
'[document]' #soup比较特殊,返回name为[doucument]
>>> soup.p.name
p
>>> soup.p.attrs
{'class': ['title']}
>>> soup.p['class'] #可以直接修改属性soup.p['class'] = 'a'
['title']
-
NavigableString
NavigableString就是tag标签内的内容,可以直接使用string获得内容,replace_with()进行替换。
>>> soup.p.string
"The Dormouse's story"
>>> soup.p.string.replace_with("no")
>>> soup.p.string
'no'
-
BeautifulSoup
BeautifulSoup表示一个文档的全部内容。 -
comment
Comment 对象是一个特殊类型的NavigableString对象,针对注释部分,输出不包括注释符号。
>>> markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
>>> soup = BeautifulSoup(markup)
>>> soup.b.string
'Hey, buddy. Want to buy a used parser?'
>>> type(soup.b.string)
bs4.element.Comment
3.节点选择
上面说到节点选择可以直接利用标签,如<head>标签用soup.head,也可通过name和attrs可以直接获取属性,操作和字典一样。以上是直接获取的方式,当想要获取标签的子节点、父节点、兄弟节点则需要通过另外的方法。
选择 | 方法 |
---|---|
直接节点 | .contents和.children(生成器) |
子孙节点 | .descendants(生成器) |
节点内容 | .strings和.stripped_strings(去除空格和空行) |
父节点 | .parent和.parents(到根节点) |
兄弟节点 | .next_element(s) 和 .previous_element(s) |
-
直接子节点.contents 和 .children,子孙节点.descendants
.contents输出方式为列表,可以通过列表索引获取某一元素。
>>> len(soup.head.contents)
1
>>> soup.head.contents
[<title>The Dormouse's story</title>]
>>> soup.head.contents[0]
<title>The Dormouse's story</title>
.children是一个llist生成器,可以对子节点进行历遍循环
>>> soup.body.children
<list_iterator at 0x19e8183a860>
>>> for child in soup.body.children:
>>> print(child)
.descendants是返回所有子孙节点,比较children和descendants的输出区别
>>> len(list(soup.body.descendants))
19
>>> len(list(soup.body.children))
6
>>> for child in soup.body.descendants:
>>> print(child)
-
节点内容.strings 和 stripped_strings
上面基本使用说到可以使用string获得节点内容,当含有多个字符串时可以用到.string循环;当字符串含有很多空格和空行,可以用到stripped_strings去除。
>>> for string in soup.stripped_strings:
>>> print(string)
-
父节点.parent和.parents
.parent是返回父节点,.parents是返回到根标签的所有节点,注意根节点<html>的父节点是BeautifulSoup 对象,BeautifulSoup 对象的父节点是None。
>>> soup.a.parent.name
'p'
>>> for parent in soup.a.parents:
>>> if parent is None:
>>> print(parent)
>>> else:
>>> print(parent.name)
p
body
html
[document]
-
兄弟节点.next_element和 .previous_element / .next_elements和 .previous_elements
.next_element 指向当前被解析的对象的下一个解析对象, .previous_elements当前被解析的对象的前一个解析对象。
4.搜索文档树
- find_all
find_all( name , attrs , recursive , text , **kwargs )
- 解释
- name参数可以传入标签名称、正则表达式、列表。
- text 参数接受 字符串 , 正则表达式 , 列表, True。
>>> soup.find_all('a', id="link2")
>>> soup.find_all(['a','b'])