python网络学习笔记——Beautiful Soup模块官方文档学习笔记

学习一个python新方向,就是学习相应库的使用。

此文章记录了Beautiful Soup模块的一些常用常量、参数、类及对应的属性和方法。对于新手不理解的概念、属性、方法进行适当的删减,聚焦于核心的内容。(模块的详细内容请查询官方Beautiful Soup文档

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

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

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

首先,文档被转换成Unicode,并且HTML的实例都被转换成Unicode编码。然后,Beautiful Soup选择最合适的解析器来解析这段文档,如果手动指定解析器那么Beautiful Soup会选择指定的解析器来解析文档。(如果不解释会打印说明文字)


对象

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

Tag对象
一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点。Beautiful Soup提供了许多操作和遍历子节点的属性。

>>>soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
>>>tag = soup.b
>>>type(tag)
>>><class 'bs4.element.Tag'>

属性:

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

Attributes: tag的属性。如tag <b class="boldest">

>>>tag[class]
>>>u’boldest’
也可以以字典的形式返回:
>>>tag.attrs
>>> {u'class': u'boldest'}

操作方法与字典一样,可删,可添,可改
html中会有多值属性,xml中没有多值属性。以列表字符串的返回。

contents:将tag的直接子节点(son)以列表的方式输出。

children:生成器,tag的所有直接(son)子节点迭代器。

descendants:可以对所有tag的子孙节点进行递归循环。

string: 如果tag只有一个 NavigableString 类型子节点,那么tag可以使用string 得到该子节点。
如果tag包含了多个子节点,tag就无法确定string 方法应该调用哪个子节点的内容, string 的输出结果是 None 。

strings: 如果tag中包含多个字符串,可以使用 strings 来循环获取(一个迭代器)。

stripped_strings:出的字符串中可能包含了很多空格或空行,使用stripped_strings 可以去除多余空白内容。

parent:父节点。

parents:递归得到所有的父辈节点。

next_sibling 和 previous_sibling:下一个或前一个兄弟节点,如果没有,则为None。

next_siblings 和 previous_siblings:前面和后面的所有兄弟节点,迭代器。

next_element 和 previous_element(迭代器):next_element 属性指向解析过程中下一个被解析的对象(字符串或tag),结果可能与 next_sibling 相同,但通常是不一样的。
previous_element 属性刚好与 next_element 相反,它指向当前被解析的对象的前一个解析对象。

next_elements和previous_elements 的迭代器可以向前或向后访问文档的解析内容。

NavigableString对象
Beautiful Soup用 NavigableString 类来包装tag中的字符串。
一个 NavigableString 字符串与Python中的Unicode字符串相同,通过 unicode() 方法可以直接将 NavigableString 对象转换成Unicode字符串。

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

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

(下面有该方法的介绍)

BeautifulSoup对象

BeautifulSoup对象表示的是一个文档的全部内容。大部分时候,可以把它当作 tag 对象。

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

>>>soup.name
>>>u'[document]'

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


过滤器

最简单的过滤器是字符串。在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容。
如果传入byte类型的参数,Beautiful Soup会当作UTF-8编码,可以传入一段Unicode 编码来避免Beautiful Soup解析编码出错。

正则表达式:如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 match() 来匹配内容。

列表:如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回。

True:可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点。

方法:如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False。
注:元素主要为tag。


方法

注:以下查找条件均为过滤器查找,符合即可匹配,而不是完全相等才匹配。如:
soup.find_all(“a”, class_=“sister”):会搜索所class值匹配“sister”的a标签,<a class=”my sister”> 也将匹配。

查找方法:
find_all(name,attrs,recursive,string,kwargs):
该方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件。

name: 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉,值可以为任一类型的过滤器,字符串、正则表达式、列表、方法或是true。

关键字参数:如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索。关键字参数的值可以为字符串、正则表达式、列表和True(过滤器)。使用多个指定名字的参数可以同时过滤tag的多个属性。

>>>soup.find_all(id='link2')

因为class在python是关键字,所以可以通过class_参数来搜索指定类名的tag:

>>>soup.ind_all("a", class_="sister")

attrs:参数定义一个字典参数来搜索包含特殊属性的tag。

>>>data_soup.find_all(attrs={"data-foo": "value"})

string参数:通过 string 参数可以搜搜文档中的字符串内容,string 参数接受字符串,正则表达式,列表,True。可以与name参数配合使用,如:

>>>soup.find_all("a", string="Elsie")#查找字符串匹配’Elsie’的a标签。

limit:最多查找的节点数量。find_all() 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢。如果我们不需要全部结果,可以使用limit参数限制返回结果的数量。当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果。(上面加粗find_all参数和官方文档是相同的,但官方文档有参数limit的作用说明,我猜应该是一个特定的关键字参数吧。可以跳转到官方文档看一下Beautiful Soup 4.4.0 文档。limit在下面的方法也适用。)

recursive:如果只想搜索tag的直接子节点,可以使用参数 recursive=False 。

find_all() 几乎是Beautiful Soup中最常用的搜索方法,所以定义了它的简写方法(下面两种方法是一样的):

>>>soup.find_all(“a”)
>>>soup(“a”)

find(name,attrs,recursive,string,kwargs ):
返回一个查找结果,其他与find_all()相似。

唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果。find_all() 方法没有找到目标是返回空列表, find() 方法找不到目标时,返回 None

soup.head.title 是find方法的简写。这个简写的原理就是多次调用当前tag的 find() 方法,类似于:

>>>soup.find("head")。find("title")

find_parents( name , attrs , recursive , string , kwargs )****和find_parent( name , attrs , recursive , string , kwargs ):
find_parents() 和 find_parent() 用来搜索当前节点的父辈节点,搜索方法与普通tag的搜索方法相同。

注:find_all() 和 find() 只搜索当前节点的所有子节点,孙子节点等。

find_next_siblings( name , attrs , recursive , string , kwargs )****和find_next_sibling( name , attrs , recursive , string , kwargs ):
这2个方法对tag的所有后面兄弟节点做解析,find_next_siblings() 方法返回所有符合条件的后面的兄弟节点, find_next_sibling() 只返回符合条件的后面的第一个tag节点。

find_previous_siblings( name , attrs , recursive , string , kwargs )****和find_previous_sibling( name , attrs , recursive , string , kwargs ):
这2个方法对tag的所有前面兄弟节点做解析,find_next_siblings() 方法返回所有符合条件的前面的兄弟节点, find_next_sibling() 只返回符合条件的前面的第一个tag节点。

find_all_next( name , attrs , recursive , string , kwargs )****和find_next( name , attrs , recursive , string , kwargs ):
这2个方法对当前tag的之后的tag和字符串进行查找, find_all_next()方法返回所有符合条件的节点, find_next() 方法返回第一个符合条件的节点。

find_all_previous( name , attrs , recursive , string , kwargs )****和find_previous( name , attrs , recursive , string , kwargs ):
这2个方法对当前tag的之前的tag和字符串进行查找, find_all_next()方法返回所有符合条件的节点, find_next() 方法返回第一个符合条件的节点。

select():
在 Tag 或 BeautifulSoup 对象的select()方法中传入字符串参数, 即可使用CSS选择器(可以来这里了解一下)的语法找到tag。对于熟悉CSS选择器语法的人来说这是个非常方便的方法。(我不熟悉,此方法具体的官方介绍在这里)

修改文档树方法:

除使用对象方法修改文档树,还可以通过上述 attrs 的字典操作进行修改。
对strting属性赋值就相当于用 当前的内容代替了原来的内容。如:

>>>markup = '<a href="http://example.m/">I linked to <i>example.com</i></a>'
>>>soup = BeautifulSoup(markup)
>>>tag = soup.a
>>>tag.string = "New link text."
>>>tag
>>><a href="http://example.com/">New link text.</a>  

注意: 如果当前的tag包含了其它tag,那么给它的string 属性赋值会覆盖掉原有的所有内容包括子tag。

append():
方法向tag中添加内容,就好像Python的列表的append() 方法。相当于向属性contents的列表调用append()。

>>>soup = BeautifulSoup("<a>Foo</a>")
>>>soup.a.append("Bar")
>>>soup
>>><html><head></head><body><a>FooBar</a></body></html>
>>>soup.a.contents
>>>[u'Foo', u'Bar']

修改标签字符串还可以新建一个NavigableString类,在使用append()添加。

>>>soup = BeautifulSoup("<b></b>")
>>>tag = soup.b
>>>new_string = NavigableString(" there")
>>>tag.append(new_string)
>>>tag
>>><b> there</b>
>>>tag.contents
>>>[u' there']	

BeautifulSoup.new_tag(): 模块函数
创建一个tag:

>>>new_tag = soup.new_tag("a", href="http://www.example.com")
>>> original_tag.append(new_tag)

insert():
Tag.insert() 与 Tag.append() 方法类似,区别是不会把新元素添加到父节点 contents 属性的最后,而是把元素插入到指定的位置。(相当于对节点的contents列表进行操作,该方法与列表中的insert方法类似。)

insert_before(): 在当前tag或文本节点前插入内容
insert_after(): 在当前tag或文本节点后插入内容

在文本中插入需要对string属性使用该方法:

>>>soup.a.string.insert_before(new_tag)   #在a节点文本中插入新节点
>>>soup.a.insert_after(new_tag)   #在a节点后插入新节点,即a.next_sibling是new_tag。

**clear():**清除当前tag的内容。

**extract():**将当前tag移除文档树,并作为方法结果返回。

**decompose():**将当前节点移除文档树并完全销毁。

**replace_with(new_tag):**移除文档树中的自身,并用新tag或文本节点替代。回被替代的tag或文本节点。

**wrap():**可以对指定的tag元素进行包装,并返回包装后的结果。

**unwrap():**移除tag内的所有tag标签,该方法常被用来进行标记的解包。

输出:

方法将Beautiful Soup的文档树格式化后以Unicode编码输出,每个XML/HTML标签都独占一行。BeautifulSoup 对象和它的tag节点都可以调用 prettify() 方法。 输出格式:
>>><html>
>>> <head>
>>> </head>
>>> <body>
>>>  <a href="http://example.com/">
>>>   I linked to
>>>   <i>
>>>    example.com
>>>   </i>
>>>  </a>
>>> </body>
>>></html>

如果只想得到结果字符串,不重视格式,那么可以对一个 BeautifulSoup 对象或 Tag 对象使用Python的 unicode() 或 str() 函数进行转化.str() 方法返回UTF-8编码的字符串,可以指定编码的设置。还可以调用 encode() 方法获得byte类型或调用 decode() 方法获得Unicode类型。
HTML中的特殊字符会转化为Unicode。如果是字符串格式,则无法显示HTML中的特殊字符。

get_text(separator):
获取到tag中包含的所有文版内容,包括子孙tag中的内容,并将结果作为Unicode字符串返回。如果只想得到tag中包含的文本内容,那么可以调用此方法。
可以通过参数指定文本中的分格符。

>>>markup = '<a href="http://example.com/">\nI linked to <i>example.com</i>\n</a>'
>>>soup = BeautifulSoup(markup)
>>>soup.get_text()
>>>u'\nI linked to example.com\n'
>>>soup.get_text("|")
>>>u'\nI linked to |example.com|\n'

编码

使用Beautiful Soup解析后,文档都被转换成了Unicode。Beautiful Soup用了 编码自动检测_ 子库来识别当前文档编码并转换成Unicode编码。BeautifulSoup 对象的original_encoding 属性记录了自动识别编码的结果。
编码自动检测_ 功能大部分时候都能猜对编码格式,但有时候也会出错。有时候即使猜测正确,也是在逐个字节的遍历整个文档后才猜对的,这样很慢。如果预先知道文档编码,可以设置编码参数来减少自动检查编码出错的概率并且提高文档解析速度。在创建 BeautifulSoup 对象的时候设置 from_encoding 参数。

通过Beautiful Soup输出文档时,不管输入文档是什么编码方式,输出编码均为UTF-8编码。
如果不想用UTF-8编码输出,可以将编码方式传入 prettify() 方法。也可以调用 BeautifulSoup 对象或任意节点的 encode() 方法,就像Python的字符串调用 encode() 方法一样。

复制

copy.copy() 方法可以复制任意 Tag 或 NavigableString 对象。复制后的对象跟与对象是相等的, 但指向不同的内存地址。

>>>soup.p == p_copy
>>>True
>>>soup.p is p_copy
>>>False

解析部分文档

如果仅仅因为想要查找文档中的标签而将整片文档进行解析,实在是浪费内存和时间。最快的方法是从一开始就把标签以外的东西都忽略掉。SoupStrainer 类可以定义文档的某段内容,这样搜索文档时就不必先解析整篇文档,只会解析在 SoupStrainer 中定义过的文档。创建一个 SoupStrainer 对象并作为 parse_only 参数给 BeautifulSoup 的构造方法即可。

SoupStrainer类:
接受与典型搜索方法相同的参数:name,attrs,recursive,string,**kwargs。创建方法与规则与查找方法相似,将实例作为 parse_only 参数给 BeautifulSoup 的构造方法即可解析部分文档。

代码诊断

如果想知道Beautiful Soup到底怎样处理一份文档,可以将文档传入 diagnose() 方法(Beautiful Soup 4.2.0中新增),Beautiful Soup会输出一份报告,说明不同的解析器会怎样处理这段文档,并标出当前的解析过程会使用哪种解析器。
diagnose() 方法的输出结果可能帮助你找到问题的原因,如果不行,还可以把结果复制出来以便寻求他人的帮助

异常

文档解析错误有两种。一种是崩溃,Beautiful Soup尝试解析一段文档结果却抛除了异常,通常是 HTMLParser。HTMLParseError 。还有一种异常情况,是Beautiful Soup解析后的文档树看起来与原来的内容相差很多。
这些错误几乎都不是Beautiful Soup的原因,这不会是因为Beautiful Soup得代码写的太优秀,而是因为Beautiful Soup没有包含任何文档解析代码。异常产生自被依赖的解析器,如果解析器不能很好的解析出当前的文档,那么最好的办法是换一个解析器。

如何提高效率

Beautiful Soup对文档的解析速度不会比它所依赖的解析器更快,如果对计算时间要求很高或者计算机的时间比程序员的时间更值钱,那么就应该直接使用 lxml 。
换句话说,还有提高Beautiful Soup效率的办法,使用lxml作为解析器。Beautiful Soup用lxml做解析器比用html5lib或Python内置解析器速度快很多。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值