Beautiful Soup 4库--python2.x(学习日记)

来源:互联网 发布:知乎分享你刚编的故事 编辑:程序博客网 时间:2024/05/19 18:18

http://beautifulsoup.readthedocs.io/zh_CN/latest/(内容摘自官方文档(中文))

只是把 我做爬虫暂时要用到的方法类整理了下,具体的数据结构 和 不常用的没有看

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

一:简单用法

文档示例(html文档)

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 的对象

from bs4 import BeautifulSoupsoup = BeautifulSoup(html_doc)

按照标准的缩进格式的结构输出:

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="link2">#     Tillie#    </a>#    ; and they lived at the bottom of a well.#   </p>#   <p class="story">#    ...#   </p>#  </body># </html>

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

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>

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

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

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

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.## ...

二:主要解析器

Python标准库

Python的内置标准库执行速度适中文档容错能力强Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差

lxml HTML 解析器

速度快文档容错能力强需要安装C语言库

lxml XML 解析器

速度快唯一支持XML的解析器需要安装C语言库

html5lib

最好的容错性以浏览器的方式解析文档生成HTML5格式的文档速度慢不依赖外部扩展

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

三:使用beautifulsoup
将一段文档传入BeautifulSoup 的构造方法,就能得到一个文档的对象

from bs4 import BeautifulSoupsoup = BeautifulSoup(open("index.html"))soup = BeautifulSoup("<html>data</html>")

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

BeautifulSoup("Sacr&eacute; bleu!")<html><head></head><body>Sacré bleu!</body></html>

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

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

1.Tag对象

方法:’.name

soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')tag = soup.btype(tag)# <class 'bs4.element.Tag'>tag.name# u'b'tag.name = "blockquote"tag# <blockquote class="boldest">Extremely bold</blockquote>

属性:’.attrs

# tag的属性的操作方法与字典相同:# 可以被添加,删除或修改tag['class']# u'boldest'tag.attrs# {u'class': u'boldest'}ag['class'] = 'verybold'tag['id'] = 1tag# <blockquote class="verybold" id="1">Extremely bold</blockquote>del tag['class']del tag['id']tag# <blockquote>Extremely bold</blockquote>tag['class']# KeyError: 'class'print(tag.get('class'))# None

多值属性

HTML 4定义了一系列可以包含多个值的属性.在HTML5中移除了一些,却增加更多.最常见的多值的属性是 class (一个tag可以有多个CSS的class). 还有一些属性 rel , rev , accept-charset , headers , accesskey . 在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"]

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

id_soup = BeautifulSoup('<p id="my id"></p>')id_soup.p['id']# 'my id'

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

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

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

xml_soup = BeautifulSoup('<p class="body strikeout"></p>', 'xml')xml_soup.p['class']# u'body strikeout'

2.NavigableString对象

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

tag.string# u'Extremely bold'type(tag.string)# <class 'bs4.element.NavigableString'>

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

unicode_string = unicode(tag.string)unicode_string# u'Extremely bold'type(unicode_string)# <type 'unicode'>

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

tag.string.replace_with("No longer bold")tag# <blockquote>No longer bold</blockquote>

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

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

3.BeautifulSoup对象

BeautifulSoup 对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象,它支持 遍历文档树 和 搜索文档树 中描述的大部分的方法.

因为 BeautifulSoup 对象并不是真正的HTML或XML的tag,所以它没有name和attribute属性.但有时查看它的 .name 属性是很方便的,所以 BeautifulSoup 对象包含了一个值为 “[document]” 的特殊属性 .name

soup.name

4.Comment

Tag , NavigableString , BeautifulSoup 几乎覆盖了html和xml中的所有内容,但是还有一些特殊对象.容易让人担心的内容是文档的注释部分:

markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"soup = BeautifulSoup(markup)comment = soup.b.stringtype(comment)# <class 'bs4.element.Comment'>

Comment 对象是一个特殊类型的 NavigableString 对象:

comment# u'Hey, buddy. Want to buy a used parser'

但是当它出现在HTML文档中时, Comment 对象会使用特殊的格式输出:

print(soup.b.prettify())# <b>#  <!--Hey, buddy. Want to buy a used parser?--># </b>

Beautiful Soup中定义的其它类型都可能会出现在XML的文档中: CData , ProcessingInstruction , Declaration , Doctype .与 Comment 对象类似,这些类都是 NavigableString 的子类,只是添加了一些额外的方法的字符串独享.下面是用CDATA来替代注释的例子:

from bs4 import CDatacdata = CData("A CDATA block")comment.replace_with(cdata)print(soup.b.prettify())# <b>#  <![CDATA[A CDATA block]]># </b>

四:搜索
一.find_all() find_all( name , attrs , recursive , text , **kwargs )

find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件.这里有几个例子:

soup.find_all("title")# [<title>The Dormouse's story</title>]soup.find_all("p", "title")# [<p class="title"><b>The Dormouse's story</b></p>]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_all(id="link2")# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
#加入正则表达式import resoup.find(text=re.compile("sisters"))# u'Once upon a time there were three little sisters; and their names were\n'

有几个方法很相似,还有几个方法是新的,参数中的 text 和 id 是什么含义? 为什么 find_all(“p”, “title”) 返回的是CSS Class为”title”的

标签? 我们来仔细看一下 find_all() 的参数

1.name 参数
name 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉.

简单的用法如下:

soup.find_all("title")# [<title>The Dormouse's story</title>]

重申: 搜索 name 参数的值可以使用任一类型的 过滤器 ,字符串,正则表达式,列表,方法或是 True .

2.keyword 参数
如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索,如果包含一个名字为 id 的参数,Beautiful Soup会搜索每个tag的”id”属性.

soup.find_all(id='link2')# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

如果传入 href 参数,Beautiful Soup会搜索每个tag的”href”属性:

soup.find_all(href=re.compile("elsie"))# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

搜索指定名字的属性时可以使用的参数值包括 字符串 , 正则表达式 , 列表, True .

下面的例子在文档树中查找所有包含 id 属性的tag,无论 id 的值是什么:

s

oup.find_all(id=True)# [<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>]

使用多个指定名字的参数可以同时过滤tag的多个属性:

soup.find_all(href=re.compile("elsie"), id='link1')# [<a class="sister" href="http://example.com/elsie" id="link1">three</a>]

有些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": "value"})# [<div data-foo="value">foo!</div>]

按CSS搜索

按照CSS类名搜索tag的功能非常实用,但标识CSS类名的关键字 class 在Python中是保留字,使用 class 做参数会导致语法错误.从Beautiful Soup的4.1.1版本开始,可以通过 class_ 参数搜索有指定CSS类名的tag:

#class_  class_  class_重要的事情说三遍soup.find_all("a", class_="sister")# [<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>]

class_ 参数同样接受不同类型的 过滤器 ,字符串,正则表达式,方法或 True :

soup.find_all(class_=re.compile("itl"))# [<p class="title"><b>The Dormouse's story</b></p>]def has_six_characters(css_class):    return css_class is not None and len(css_class) == 6soup.find_all(class_=has_six_characters)# [<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>]

tag的 class 属性是 多值属性 .按照CSS类名搜索tag时,可以分别搜索tag中的每个CSS类名:

css_soup = BeautifulSoup('<p class="body strikeout"></p>')css_soup.find_all("p", class_="strikeout")# [<p class="body strikeout"></p>]css_soup.find_all("p", class_="body")# [<p class="body strikeout"></p>]

搜索 class 属性时也可以通过CSS值完全匹配:

css_soup.find_all("p", class_="body strikeout")# [<p class="body strikeout"></p>]

完全匹配 class 的值时,如果CSS类名的顺序与实际不符,将搜索不到结果:

soup.find_all("a", attrs={"class": "sister"})# [<a class="sister" href="http://example.com/elsie

3.text 参数
通过 text 参数可以搜搜文档中的字符串内容.与 name 参数的可选值一样, text 参数接受 字符串 , 正则表达式 , 列表, True . 看例子:

soup.find_all(text="Elsie")# [u'Elsie']soup.find_all(text=["Tillie", "Elsie", "Lacie"])# [u'Elsie', u'Lacie', u'Tillie']soup.find_all(text=re.compile("Dormouse"))[u"The Dormouse's story", u"The Dormouse's story"]def is_the_only_string_within_a_tag(s):    ""Return True if this string is the only child of its parent tag.""    return (s == s.parent.string)soup.find_all(text=is_the_only_string_within_a_tag)# [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...']

虽然 text 参数用于搜索字符串,还可以与其它参数混合使用来过滤tag.Beautiful Soup会找到 .string 方法与 text 参数值相符的tag.下面代码用来搜索内容里面包含“Elsie”的标签:

soup.find_all("a", text="Elsie")# [<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>]

4.limit 参数
find_all() 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果.

文档树中有3个tag符合搜索条件,但结果只返回了2个,因为我们限制了返回数量:

soup.find_all("a", limit=2)# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

5.recursive 参数
调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False .

一段简单的文档:

<html> <head>  <title>   The Dormouse's story  </title> </head>...

是否使用 recursive 参数的搜索结果:

soup.html.find_all("title")# [<title>The Dormouse's story</title>]soup.html.find_all("title", recursive=False)# []

二.像调用 find_all() 一样调用tag
find_all() 几乎是Beautiful Soup中最常用的搜索方法,所以我们定义了它的简写方法. BeautifulSoup 对象和 tag 对象可以被当作一个方法来使用,这个方法的执行结果与调用这个对象的 find_all() 方法相同,下面两行代码是等价的:

soup.find_all("a")soup("a")

这两行代码也是等价的:

soup.title.find_all(text=True)soup.title(text=True)

三:find() find( name , attrs , recursive , text , kwargs )

find_all() 方法将返回文档中符合条件的所有tag,尽管有时候我们只想得到一个结果.比如文档中只有一个标签,那么使用 find_all() 方法来查找标签就不太合适, 使用 find_all 方法并设置 limit=1 参数不如直接使用 find() 方法.下面两行代码是等价的:

soup.find_all('title', limit=1)# [<title>The Dormouse's story</title>]soup.find('title')# <title>The Dormouse's story</title>

唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果.

find_all() 方法没有找到目标是返回空列表, find() 方法找不到目标时,返回 None .

print(soup.find("nosuchtag"))# None

soup.head.title 是 tag的名字 方法的简写.这个简写的原理就是多次调用当前tag的 find() 方法:

soup.head.title# <title>The Dormouse's story</title>soup.find("head").find("title")# <title>The Dormouse's story</title>

~~~一万两千字,我看了得有两万~~~~妈呀我需要睡个小觉

0 0
原创粉丝点击