Beautiful Soup 4.4.0 文档

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.

这篇文档介绍了BeautifulSoup4中所有主要特性,并且有小例子.让我来向你展示它适合做什么,如何工作,怎样使用,如何达到你想要的效果,和处理异常情况.

文档中出现的例子在Python2.7和Python3.2中的执行结果相同

快速开始

下面的一段HTML代码将作为例子被多次用到.这是 爱丽丝梦游仙境的 的一段内容(以后内容中简称为 爱丽丝 的文档):

In [18]:
html_doc = """
<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>
"""

使用BeautifulSoup解析这段代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出:

In [19]:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')

print(soup.prettify())
<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 class="sister" href="http://example.com/elsie" id="link1">
    Elsie
   </a>
   ,
   <a class="sister" href="http://example.com/lacie" id="link2">
    Lacie
   </a>
   and
   <a class="sister" href="http://example.com/tillie" id="link3">
    Tillie
   </a>
   ;
and they lived at the bottom of a well.
  </p>
  <p class="story">
   ...
  </p>
 </body>
</html>

几个简单的浏览结构化数据的方法:

In [20]:
soup.title
Out[20]:
<title>The Dormouse's story</title>
In [21]:
soup.title.name
Out[21]:
'title'
In [22]:
soup.title.string
Out[22]:
"The Dormouse's story"
In [23]:
soup.title.parent.name
Out[23]:
'head'
In [24]:
soup.p
Out[24]:
<p class="title"><b>The Dormouse's story</b></p>
In [25]:
soup.p['class']
Out[25]:
['title']
In [26]:
soup.a
Out[26]:
<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
In [27]:
soup.find_all('a')
Out[27]:
[<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>]
In [28]:
soup.find(id="link3")
Out[28]:
<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>

从文档中找到所有标签的链接:

In [29]:
for link in soup.find_all('a'):
    print(link.get('href'))
http://example.com/elsie
http://example.com/lacie
http://example.com/tillie

从文档中获取所有文字内容:

In [30]:
print(soup.get_text())
The Dormouse's story

The Dormouse's story
Once upon a time there were three little sisters; and their names were
Elsie,
Lacie and
Tillie;
and they lived at the bottom of a well.
...

这是你想要的吗?别着急,还有更好用的

如果你用的是新版的Debain或ubuntu,那么可以通过系统的软件包管理来安装:

$ apt-get install Python-bs4

Beautiful Soup 4 通过PyPi发布,所以如果你无法使用系统包管理安装,那么也可以通过 easy_install 或 pip 来安装.包的名字是 beautifulsoup4 ,这个包兼容Python2和Python3.

$ easy_install beautifulsoup4

$ pip install beautifulsoup4

(在PyPi中还有一个名字是 BeautifulSoup 的包,但那可能不是你想要的,那是 Beautiful Soup3 的发布版本,因为很多项目还在使用BS3, 所以 BeautifulSoup 包依然有效.但是如果你在编写新项目,那么你应该安装的 beautifulsoup4 )

如果你没有安装 easy_install 或 pip ,那你也可以 下载BS4的源码 ,然后通过setup.py来安装.

$ Python setup.py install

如果上述安装方法都行不通,Beautiful Soup的发布协议允许你将BS4的代码打包在你的项目中,这样无须安装即可使用.

作者在Python2.7和Python3.2的版本下开发Beautiful Soup, 理论上Beautiful Soup应该在所有当前的Python版本中正常工作

安装完成后的问题

Beautiful Soup发布时打包成Python2版本的代码,在Python3环境下安装时,会自动转换成Python3的代码,如果没有一个安装的过程,那么代码就不会被转换.

如果代码抛出了 ImportError 的异常: “No module named HTMLParser”, 这是因为你在Python3版本中执行Python2版本的代码.

如果代码抛出了 ImportError 的异常: “No module named html.parser”, 这是因为你在Python2版本中执行Python3版本的代码.

如果遇到上述2种情况,最好的解决方法是重新安装BeautifulSoup4.

如果在ROOT_TAG_NAME = u’[document]’代码处遇到 SyntaxError “Invalid syntax”错误,需要将把BS4的Python代码版本从Python2转换到Python3. 可以重新安装BS4:

$ Python3 setup.py install

或在bs4的目录中执行Python代码版本转换脚本

$ 2to3-3.2 -w bs4

安装解析器

Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml .根据操作系统不同,可以选择下列方法来安装lxml:

$ apt-get install Python-lxml

$ easy_install lxml

$ pip install lxml

另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib:

$ apt-get install Python-html5lib

$ easy_install html5lib

$ pip install html5lib

下表列出了主要的解析器:

  解析器           使用方法                         
Python标准库      BeautifulSoup(markup, "html.parser")  

lxml HTML 解析器   BeautifulSoup(markup, "lxml")           

lxml XML 解析器   BeautifulSoup(markup, ["lxml-xml"])      

                 BeautifulSoup(markup, "xml")        

html5lib         BeautifulSoup(markup, "html5lib")        



推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定.

提示: 如果一段HTML或XML文档格式不正确的话,那么在不同的解析器中返回的结果可能是不一样的,查看 解析器之间的区别 了解更多细节

如何使用

将一段文档传入BeautifulSoup 的构造方法,就能得到一个文档的对象, 可以传入一段字符串或一个文件句柄.

from bs4 import BeautifulSoup

soup = BeautifulSoup(open("index.html"))

soup = BeautifulSoup("data")

首先,文档被转换成Unicode,并且HTML的实例都被转换成Unicode编码

In [32]:
BeautifulSoup("Sacr&eacute; bleu!")
Out[32]:
<html><body><p>Sacré bleu!</p></body></html>

然后,Beautiful Soup选择最合适的解析器来解析这段文档,如果手动指定解析器那么Beautiful Soup会选择指定的解析器来解析文档.

对象的种类

Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag , NavigableString , BeautifulSoup , Comment .

Tag

Tag 对象与XML或HTML原生文档中的tag相同:

In [33]:
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
type(tag)
Out[33]:
bs4.element.Tag

Tag有很多方法和属性,在 遍历文档树 和 搜索文档树 中有详细解释.现在介绍一下tag中最重要的属性: name和attributes

Name

每个tag都有自己的名字,通过 .name 来获取:

In [34]:
tag.name
Out[34]:
'b'

如果改变了tag的name,那将影响所有通过当前Beautiful Soup对象生成的HTML文档:

In [35]:
tag.name = "blockquote"
tag
Out[35]:
<blockquote class="boldest">Extremely bold</blockquote>

Attributes

一个tag可能有很多个属性. tag 有一个 “class” 的属性,值为 “boldest” . tag的属性的操作方法与字典相同:

In [36]:
tag['class']
Out[36]:
['boldest']

也可以直接”点”取属性, 比如: .attrs :

In [37]:
tag.attrs
Out[37]:
{'class': ['boldest']}

tag的属性可以被添加,删除或修改. 再说一次, tag的属性操作方法与字典一样

In [38]:
tag['class'] = 'verybold'
tag['id'] = 1
tag
Out[38]:
<blockquote class="verybold" id="1">Extremely bold</blockquote>
In [39]:
del tag['class']
del tag['id']
tag
Out[39]:
<blockquote>Extremely bold</blockquote>
In [42]:
tag['class']
# KeyError: 'class'
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-42-17596b4d070d> in <module>
----> 1 tag['class']

D:\ProgramData\Anaconda3\lib\site-packages\bs4\element.py in __getitem__(self, key)
   1069         """tag[key] returns the value of the 'key' attribute for the tag,
   1070         and throws an exception if it's not there."""
-> 1071         return self.attrs[key]
   1072 
   1073     def __iter__(self):

KeyError: 'class'
In [41]:
print(tag.get('class'))
None

多值属性

HTML 4定义了一系列可以包含多个值的属性.在HTML5中移除了一些,却增加更多.最常见的多值的属性是 class (一个tag可以有多个CSS的class). 还有一些属性 rel , rev , accept-charset , headers , accesskey . 在Beautiful Soup中多值属性的返回类型是list:

In [43]:
css_soup = BeautifulSoup('<p class="body strikeout"></p>')
css_soup.p['class']
Out[43]:
['body', 'strikeout']
In [44]:
css_soup = BeautifulSoup('<p class="body"></p>')
css_soup.p['class']
Out[44]:
['body']

如果某个属性看起来好像有多个值,但在任何版本的HTML定义中都没有被定义为多值属性,那么Beautiful Soup会将这个属性作为字符串返回

In [45]:
id_soup = BeautifulSoup('<p id="my id"></p>')
id_soup.p['id']
Out[45]:
'my id'

将tag转换成字符串时,多值属性会合并为一个值

In [46]:
rel_soup = BeautifulSoup('<p>Back to the <a rel="index">homepage</a></p>')
rel_soup.a['rel']
Out[46]:
['index']
In [47]:
rel_soup.a['rel'] = ['index', 'contents']
print(rel_soup.p)
<p>Back to the <a rel="index contents">homepage</a></p>

如果转换的文档是XML格式,那么tag中不包含多值属性

In [48]:
xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')
xml_soup.p['class']
Out[48]:
'body strikeout'

可以遍历的字符串

字符串常被包含在tag内.Beautiful Soup用 NavigableString 类来包装tag中的字符串:

In [49]:
tag.string
Out[49]:
'Extremely bold'
In [52]:
type(tag.string)
Out[52]:
bs4.element.NavigableString

一个 NavigableString 字符串与Python中的Unicode字符串相同,并且还支持包含在 遍历文档树 和 搜索文档树 中的一些特性. 通过 unicode() 方法可以直接将 NavigableString 对象转换成Unicode字符串:

In [58]:
#unicode_string = unicode(tag.string)
unicode_string
type(unicode_string)
Out[58]:
bs4.element.NavigableString

tag中包含的字符串不能编辑,但是可以被替换成其它的字符串,用 replace_with() 方法:

In [54]:
tag.string.replace_with("No longer bold")
tag
Out[54]:
<blockquote>No longer bold</blockquote>

NavigableString 对象支持 遍历文档树 和 搜索文档树 中定义的大部分属性, 并非全部.尤其是,一个字符串不能包含其它内容(tag能够包含字符串或是其它tag),字符串不支持 .contents 或 .string 属性或 find() 方法.

如果想在Beautiful Soup之外使用 NavigableString 对象,需要调用 unicode() 方法,将该对象转换成普通的Unicode字符串,否则就算Beautiful Soup已方法已经执行结束,该对象的输出也会带有对象的引用地址.这样会浪费内存.

In [ ]: