Beautiful Soup 4 笔记
Beautiful Soup 4
摘自BS4.20文档
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库
安装
$ pip install beautifulsoup4
解析器
- python标准库
BeautifulSoup(markup, "html.parser")
不需安装,速度适中,容错能力强 - lxml HTML 解析器
BeautifulSoup(markup, "lxml")
速度快,容错强 - lxml XML 解析器,
BeautifulSoup(markup, ["lxml", "xml"])或者BeautifulSoup(markup, "xml")
唯一支持XML的解析器
$ apt-get install Python-lxml
$ easy_install lxml
$ pip install lxml
- html5lib
速度慢,最好的容错性,以浏览器的方式解析文档,生成HTML5格式的文档
$ pip install html5lib
快速上手
用到的html文本
<html><head><title>The Dormouse's story</title></head>
<body>
<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>
使用
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc) #构造对象
print(soup.prettify()) #这样会根据soup的解析按照标准缩进,可以根据这个判断soup是否正确解析了一些不太规范的文档
基本使用
soup.title
# <title>The Dormouse's story</title>
soup.title.name
# u'title'
soup.title.string
# u'The Dormouse's story'
soup.title.parent.name
# u'head'
soup.p
# <p class="title"><b>The Dormouse's story</b></p>
soup.p['class']
# u'title'
soup.a
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
soup.find_all('a')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
# <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
soup.find(id="link3")
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
从文档中获取所有文字内容:
print(soup.get_text())
查找
将一段文档传入BeautifulSoup 的构造方法,就能得到一个文档的对象, 可以传入一段字符串或一个文件句柄。
文档被转换成Unicode,并且HTML的实例都被转换成Unicode编码。
然后,Beautiful Soup选择最合适的解析器来解析这段文档,如果手动指定解析器那么Beautiful Soup会选择指定的解析器来解析文档。
对象种类
1-tag
Tag 对象与XML或HTML原生文档中的tag相同。
name
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
tag.name
# u'b' tag自己的名字
tag.name = "blockquote" #改变html文档
Attributes
一个tag可能有很多个属性. tag <b class="boldest"> 有一个 “class” 的属性,值为 “boldest” 。 tag的属性的操作方法与字典相同:
tag['class']
# u'boldest'
#直接”点”取属性, 比如: .attrs :
tag.attrs
# {u'class': u'boldest'} #获得所有的属性
多值属性
在Beautiful Soup中多值属性的返回类型是list:
css_soup = BeautifulSoup('<p class="body strikeout"></p>')
css_soup.p['class']
# ["body", "strikeout"]
css_soup = BeautifulSoup('<p class="body"></p>')
css_soup.p['class']
# ["body"]
如果转换的文档是XML格式,那么tag中不包含多值属性
xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')
xml_soup.p['class']
# u'body strikeout'
2 - NavigableString
Beautiful Soup用 NavigableString 类来包装tag中的字符串:
tag.string
# u'Extremely bold'
type(tag.string)
# <class 'bs4.element.NavigableString'>
```py
通过 unicode() 方法可以直接将 NavigableString 对象转换成Unicode字符串。
tag中包含的字符串不能编辑,但是可以被替换成其它的字符串,用 replace_with() 方法:
```py
tag.string.replace_with("No longer bold")
tag
# <blockquote>No longer bold</blockquote>
3-Comment
markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
soup = BeautifulSoup(markup)
comment = soup.b.string
#Comment 对象是一个特殊类型的 NavigableString 对象:
comment
# u'Hey, buddy. Want to buy a used parser'
遍历文档树
tag
.name
通过点取属性的方式只能获得当前名字的第一个tag:
#获取<body>标签中的第一个<b>标签:
soup.body.b
# <b>The Dormouse's story</b>
.contents 和 .children
.contents 属性可以将tag的子节点以列表的方式输出
head_tag
# <head><title>The Dormouse's story</title></head>
head_tag.contents
[<title>The Dormouse's story</title>]
通过tag的 .children 生成器,可以对tag的子节点进行循环:
for child in title_tag.children:
print(child)
.descendants
.contents 和 .children 属性仅包含tag的直接子节点.例如,<head>标签只有一个直接子节点<title>
head_tag.contents
# [<title>The Dormouse's story</title>]
但是<title>标签也包含一个子节点:字符串 “The Dormouse’s story”,这种情况下字符串 “The Dormouse’s story”也属于标签的子孙节点. .descendants 属性可以对所有tag的子孙节点进行递归循环
for child in head_tag.descendants:
print(child)
# <title>The Dormouse's story</title>
# The Dormouse's story
.strings 和 stripped_strings
输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容
.parent 和 .parents
获取某个元素的父节点,层节点比如<html>的父节点是 BeautifulSoup 对象
通过元素的 .parents 属性可以递归得到元素的所有父辈节
link = soup.a
link
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
for parent in link.parents:
if parent is None:
print(parent)
else:
print(parent.name)
# p
# body
# html
# [document]
# None
.next_sibling 和 .previous_sibling
使用 .next_sibling 和 .previous_sibling 属性来查询兄弟节点
.next_element 和 .previous_element
.next_element 属性指向解析过程中下一个被解析的对象(字符串或tag),结果可能与 .next_sibling 相同,但通常是不一样的.
last_a_tag = soup.find("a", id="link3")
last_a_tag
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
last_a_tag.next_sibling
# '; and they lived at the bottom of a well.'
last_a_tag.next_element
# u'Tillie'
搜索方法
其它方法的参数和用法类似
过滤器
- 字符串
soup.find_all('b') - 正则表达式
soup.find_all(re.compile("^b")) - 列表(或条件)
soup.find_all(["a", "b"]) - True(可以匹配任何值)
soup.find_all(True) - 方法
如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 ,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
find_all()
find_all( name , attrs , recursive , text , **kwargs )
- name 参数
name 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉。 - keyword 参数
如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索。
soup.find_all(href=re.compile("elsie"), id='link1')
有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性:
data_soup = BeautifulSoup('<div data-foo="value">foo!</div>')
data_soup.find_all(data-foo="value")
# SyntaxError: keyword can't be an expression
但是可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag:
data_soup.find_all(attrs={"data-foo": "v
- 按照css搜索
通过 class_ 参数搜索有指定CSS类名的tag。
soup.find_all(class_=re.compile("itl"))
- text 参数
通过 text 参数可以搜搜文档中的字符串内容。
soup.find_all(text=re.compile("Dormouse"))
除了搜索字符串,还可以与其它参数混合使用来过滤tag
soup.find_all("a", text="Elsie")
- limit 参数
限制返回结果的数量 - recursive 参数
调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False
注
BeautifulSoup 对象和 tag 对象可以被当作一个方法来使用,这个方法的执行结果与调用这个对象的 find_all() 方法相同
soup.find_all("a")
soup("a")
find()
find_parents() 和 find_parent()
find_next_siblings() 和 find_next_sibling()
find_previous_siblings() 和 find_previous_sibling()
css选择器
在 Tag 或 BeautifulSoup 对象的 .select() 方法中传入字符串参数,即可使用CSS选择器的语法找到tag。
通过tag标签逐层查找:
soup.select("body a")
找到某个tag标签下的直接子标签 :
soup.select("head > title")
通过CSS的类名查找:
soup.select(".sister")
通过tag的id查找:
soup.select("#link1")
soup.select("a#link2")
是否存在某个属性来查找:
soup.select('a[href]')
通过属性的值来查找:
soup.select('a[href="http://example.com/elsie"]')
找到兄弟节点标签:
soup.select("#link1 ~ .sister")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
soup.select("#link1 + .sister")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
soup.select("#link1 + .sister")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

浙公网安备 33010602011771号