标签(空格分隔): Python Packages crawler
最近在研究python爬虫,整理了一些BeautifulSoup包的内容。
文档上篇整理了官方说明文档中的内容,简单介绍包的安装与调用、格式化后文档树的结构、遍历文档树以及搜索文档树的方式,最后会给出一个从豆瓣中抓取影单的例子。
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。
如果电脑中已经安装了pip包,那么直接在cmd窗口中输入:
pip install pip install beautifulsoup4
如果没有安装pip包,可以下载BS4的源码,然后通过setup.py来安装。即,在目录下右键打开cmd窗口,输入:
Python setup.py install
BS4的开发是在python2.7和python3.2的环境中开发的,因此本文中的命令在python2与python3中是通用的。BeautifulSoup发布时候打包成为Python2版本的代码,在Python3环境下安装时,会自动转换成Python3的代码,如果没有安装过程,那么代码就不会被转换。
如果代码抛出了 ImportError 的异常: “No module named HTMLParser”, 这是因为你在Python3版本中执行Python2版本的代码.
如果代码抛出了 ImportError 的异常: “No module named html.parser”, 这是因为你在Python2版本中执行Python3版本的代码.
解决以上问题最简单的办法就是重新安装2333
如果在ROOT_TAG_NAME = u’[document]’代码处遇到 SyntaxError “Invalid syntax”错误,需要将把BS4的Python代码版本从Python2转换到Python3. 可以重新安装BS4:
Python3 setup.py install
或者在bs4的目录中执行Python代码版本转换脚本:
2to3-3.2 -w bs4
BeautifulSoup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是lxml。lxml的同样可以使用pip进行安装。
另一个可供选择的解析其实纯Python实现的html5lib,它的结息方式与浏览器相同,安装方法与lxml相同。如果使用的是Anaconda的整体包,那么以上包应该都是包含在内的。
不同解析器之间的区别会在以后的文章中介绍。
一般情况下,推荐使用lxml解析器,其效率更高。
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc) #此处的html_doc是通过request 得到的网站响应
print(soup.prettify()) #可以得到一个整理规范的标准HTML文档
这段代码逻辑如下:首先导入BeautifulSoup包。然后通过构造方法调用一个文档对象。构造方法中可以传入一段字符串或者一个文件句柄。首先,文档被转换为Unicode格式,并且HTML的实力都被转换为Unicode编码。
然后BeautifulSoup会选择最合适的解析器来解析文档。同样,也可以手动指定解析器,格式如下:
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,"lxml")
print(soup.prettify())
得到的是一个规范化的HTML文档。
接下来将介绍这个HTML文档包含的元素类别和属性。
Beautiful Soup将复杂的HTMl文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为四种Tag、NavigableString、BeautifulSoup、Comment。
接下来分别介绍这四种对象。
Tag与HTML原生文档中的tag相同
soup = BeautifulSoup(' Extremely bold#
上述代码中,首先使用构造一个BeautifulSoup对象;然后通过soup.b选取第一个name为b的Tag;可以看到,tag的类型为Tag。
Tag有很多属性,在遍历文档树和搜索文档树中都有介绍
Tag的重要属性:name、attributes
每个Tag都有自己的名字,通过.name来获取:
tag.name
# u'b'
如果改变了Tag的Name,那么将影响HTML文档中所有该Tag的属性。
tag.name = "blockquote"
print(soup)
# Extremely bold
class = "boldest> Extremly bold boldb>
一个tag可能有多个属性,在上面给出的例子中,有一个”class”属性,值为”blodest”,对于.tag的操作类似于字典:
tag['class']
# u'blodest'
也可以直接用.attrs:
tag.attrs
# {u'class': u'boldest'}
Tag属性可以添加、删除或者修改,如同字典一样:
tag['class'] = 'verybold'
tag['id'] = 1
tag
# Extremely bold
del tag['class']
del tag['id']
tag
# Extremely bold
tag['class']
# KeyError: 'class'
print(tag.get('class'))
# None
HTML4定义了一系列可以包含多个值得属性。在HTML5中溢出了一些,却增加的更多,最常见的多值属性是class(一个tag可以由多个CSS的class)。还有一些属性rel,rev,accept-charset,headers,accesskey。
css_soup = BeautifulSoup('')
css_soup.p['class']
# ["body", "strikeout"]
css_soup.p.attrs
# {'class': ['body', 'strikeout']}
css_soup = BeautifulSoup('')
css_soup.p['class']
# ["body"]
如果某个属性看起来好像有多个值,但在任何版本的HTML中都没有被定义为为多值属性,那么BeautifulSoup会将这个属性作为字符串返回。
id_soup = BeautifulSoup('')
id_soup.p['id']
# 'my id'
将Tag转换为字符串时,多值属性会合并为一个值:
rel_soup = BeautifulSoup('Back to the homepage
')
rel_soup.a['rel']
# ['index']
rel_soup.a['rel'] = ['index', 'contents']
print(rel_soup.p)
# Back to the homepage
如果转换文档是XML格式(即使用XML解析markup,那么tag中不包含多值属性:
xml_soup = BeautifulSoup('', 'xml')
xml_soup.p['class']
# u'body strikeout'
在解析后的HTML文档中,字符串通常被包含在Tag内,BeautifulSoup通常用NavigableString类来包装Tag中的字符串:
tag.string
# u'Extremely bold'
type(tag.string)
#
这段代码中,在提取了Tag之后,调用tag的string属性获得该Tag下的字符串。
注意,如果提取的Tag并非叶节点,则无法使用.string方法获取该节点下的字符串:
soup = BeautifulSoup("""
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.
""", "lxml")
tag = soup.p
print(tag.string)
# None
一个NavigableString字符串与Python中的Unicode字符串相同,且支持包含在遍历文档树和搜索文档树中的一些特性。通过Unicode()方法可以直接将NavigableString对象转换为Unicode字符串
soup = BeautifulSoup("">Extremely bold")
tag = soup.b
unicode_string = unicode(tag.string)
unicode_string
# u'Extremely bold'
type(unicode_string)
#
tag中东包含的字符串不能被编辑,但是可以被替换成其他字符串,用replace_with()方法:
tag.string.replace_with("No longer bold")
tag
# No longer bold
NavigableString对象支持遍历文档树和搜索文档树中定义的大部分属性,但需要注意,一个字符串不能包含其他内容(tag能包含字符串或者是其他tag),字符串不支持.contents或者.string属性或find()方法。
如果想在BeautifulSoup之外使用NavigableString对象,需要调用unicode()方法,将该对象转换为普通的Unicode字符串,否则就算BeautifulSoup方法已经执行结束,该对象的输出也会带有对象的引用地址,会造成内存的浪费。
BS对象表示的是一个文档的全部内容,大部分时候,可以把它当作Tag对象,支持遍历文档树和搜索文档树中描述的大部分方法。
因为BeautifulSoup对象并不是真正的HTML或者XML的tag,所以他没有name和attribute属性。所以BeautifulSoup对象一般包含值为”[document]”的特殊属性.name。
soup.name
# u'[document]'
通常情况下,Tag,NavigableString,BeautifulSoup几乎覆盖了html和xml中的所有内容,但是还有一些特殊对象。如文档的注释部分:
markup = ""
soup = BeautifulSoup(markup)
comment = soup.b.string
type(comment)
#
print(soup.b.string)
# Hey, buddy. Want to buy a used parser?
comment对象是一个特殊类型的NavigableString对象,但当期出现在HTML文档中时,Comment对象会使用特殊的格式输出:
print(soup.b.prettify())
#
#
#
BS重定义的其他类型都可能出现在XNL文档中:CData、ProcessingInstruction,Declaration,Doctype。与Comment对象类似,这些类都是NavigableString的子类,只是添加了一些额外的方法的字符串独享。
from bs4 import CData
cdata = CData("A CDATA block")
comment.replace_with(cdata)
print(soup.b.prettify())
#
#
#
以下文为例子:
html_doc = """
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.
...
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc)
一个Tag可能包含多个字符串或者其他的Tag,这些都是这个Tag的子节点。BeautifulSoup提供了许多操作和遍历子节点的属性。
需要注意的是,BeautifulSoup中的字符串节点不支持这些属性,因为字符串没有子节点。
操作文档树最简单的方法就是告诉它你想获取的tag的name。如果想获取标签,只需要使用soup.name:
soup.head
# The Dormouse's story
soup.title
# The Dormouse's story
这是个获取tag的小窍门,可以在文档树的tag中多次调用此方法。如下所示:
soup.body.b
# The Dormouse's story
注意,该方法只能获得节点中第一个该子标签的节点。同样的如果对这类子标签的name属性进行修改,修改的也只是这一个子节点的name。
如果希望获得所有包含的标签,或是通过名字得到一个比tag更多的内容的时候,就需要Searching the tree中描述的方法,比如:find_all(),将在下一节具体介绍。
soup.find_all('a')
# [Elsie,
# Lacie,
# Tillie]
tag的.contents属性可以将tag的子节点以列表的方式输出:
head_tag = soup.head
head_tag
# The Dormouse's story
head_tag.contents
[The Dormouse's story ]
title_tag = head_tag.contents[0]
title_tag
# The Dormouse's story
title_tag.contents
# [u'The Dormouse's story']
如果tag内同时包含字符串和多个子节点,将得到以下形式的输出:
soup = BeautifulSoup("""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.
""", "lxml")
tag = soup.p
tag.contents
#[u'Once upon a time there were three little sisters; and their names were\n',
# Elsie,
# u',\n',
# Lacie,
# u' and\n',
# Tillie,
# u';\nand they lived at the bottom of a well.']
BeautifulSoup对象本身一定会包含子节点,也就是说标签也是BeautifulSoup对象的子节点:
len(soup.contents)
# 1
soup.contents[0].name
# u'html'
字符串没有.contents属性,因为字符串没有子节点:
text = title_tag.contents[0]
text.contents
# AttributeError: 'NavigableString' object has no attribute 'contents'
通过tag的.children生成器,可以对tag的子节点进行循环:
for child in title_tag.children:
print(child)
# The Dormouse's story
.contents和.children属性仅包含tag的直接子节点。例如,标签只有一个直接子节点
head_tag.contents
# [The Dormouse's story ]
但是标签也包含一个字符串子节点。这种情况下字符串属于标签的子孙节点,.descendats属性可以对所有tag的子孙节点进行递归:
for child in head_tag.descendants:
print(child)
# The Dormouse's story
# The Dormouse's story
上面的例子中,标签只有一个子节点,但是有2个子孙节点:
节点和的子节点,BeautifulSoup有一个直接子节点(节点),却有很多子孙节点:
len(list(soup.children))
# 1
len(list(soup.descendants))
# 25
如果tag只有一个NavigableString类型子节点,那么这个tag可以使用.string得到子节点:
title_tag.string
# u'The Dormouse's story'
如果一个tag仅有一个子节点,那么这个tag也可以使用.string方法,输出结果与当前唯一子节点.string结果相同:
head_tag.contents
# [The Dormouse's story ]
head_tag.string
# u'The Dormouse's story'
如果tag包含了多个子节点,tag就无法确定.string方法该调用哪个子节点的内容,此时.string的输出结果是None:
print(soup.html.string)
# None
当tag包含很多子节点时,无法用string直接输出string的内容,此时可以使用strings的迭代器。如之前的例子中,如果使用strings迭代输出:
soup = BeautifulSoup("""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.
""", "lxml")
strs = []
for string in soup.strings:
strs.append(string)
print(strs)
#[u'Once upon a time there were three little sisters; and their names were\n', u'Elsie', u',\n', u'Lacie', u' and\n', u'Tillie', u';\nand they lived at the bottom of a well.']
输出的字符串中可能包含了很多空格或者空行,使用.stripped_strings可以去除多余空白内容:
strs = []
for string in soup.stripped_strings:
strs.append(string)
print(strs)
[u'Once upon a time there were three little sisters; and their names were', u'Elsie', u',', u'Lacie', u'and', u'Tillie', u';\nand they lived at the bottom of a well.']
全部是空格的行会被忽略掉,段首和段末的空白会被删除。
继续分析文档树,每个tag或字符串都有父节点:被包含在某个tag中(在文档的树形结构中,根节点是BeautifulSoup对象)
通过.parent属性来获取某个元素的父节点。
title_tag = soup.title
title_tag
# The Dormouse's story
title_tag.parent
# The Dormouse's story
文档title的字符串也有父节点:标签
title_tag.string.parent
# The Dormouse's story
文档的顶曾节点比如的父节点是BeautifulSoup对象:
html_tag = soup.html
type(html_tag.parent)
#
BeautifulSoup对象的.parent是None:
print(soup.parent)
# None
通过元素的.parents属性可以递归得到元素的所有父辈节点,下面的例子使用了.parents方法遍历了标签到根节点的所有节点:
link = soup.a
link
# Elsie
for parent in link.parents:
if parent is None:
print(parent)
else:
print(parent.name)
# p
# body
# html
# [document]
# None
.parent和.parents的关系与.children和.descendants的关系类似。一个是获取所有获取一级关系下的全部节点,另一个是向该方向进行的迭代器。
看一段简单地例子:
sibling_soup = BeautifulSoup("text1text2 ")
print(sibling_soup.prettify())
#
#
#
#
# text1
#
#
# text2
#
#
#
#
因为标签和标签是同一层:他们是同一个元素的子节点,所以和可以被成为兄弟节点。一段文档以标准格式输出时,兄弟节点有相同的缩进级别,在代码中也可以使用这种关系。
在文档书中,使用上述两个方法可以查询兄弟节点:
sibling_soup.b.next_sibling
# text2
sibling_soup.c.previous_sibling
# text1
同级节点中的第一个没有.previous_sibling属性,同理,同级节点中最后一个没有.next_sibling属性。
考虑使用如下的文档
soup =
"""
Elsie
Lacie
Tillie
"""
link = soup.a
link.next_silbing
# # u',\n'
得到的结果并不是第二个标签,而是第一个标签和第二个标签之间的顿号和换行符号。
同级标签之中同样存在相同的迭代输出方法:
可以通过 .next_silbings和 .previous_silbings对其进行迭代输出:
for sibling in soup.a.next_siblings:
print(repr(sibling))
# u',\n'
# Lacie
# u' and\n'
# Tillie
# u'; and they lived at the bottom of a well.'
# None
for sibling in soup.find(id="link3").previous_siblings:
print(repr(sibling))
# ' and\n'
# Lacie
# u',\n'
# Elsie
# u'Once upon a time there were three little sisters; and their names were\n'
# None
首先参考一下文档:
<html><head><title>The Dormouse's storytitle>head>
<p class="title"><b>The Dormouse's storyb>p>
HTML解析器把这段字符串转换成一连串的事件: “打开标签”,”打开一个标签”,”打开一个标签”,”添加一段字符串”,”关闭标签”,”打开
标签”,等等。Beautiful Soup提供了重现解析器初始化过程的方法。
这两个属性分别只想解析过程中下一个和上一个被解析的对象(字符串或者tag),结果可能与.next_siblings相同,但通常是不一样的。
在本文的例子中,.next_sibling结果是一个字符串(或者说下一个同级标签中包含的内容)。
而标签的.next_element属性结果是在标签被解析之后的解析内容,不是标签后的句子部分。
.previous_element属性刚好与.next_silbing相反,它指向当前被解析的对象的前一个解析对象。
last_a_tag.previous_element
# u' and\n'
last_a_tag.previous_element.next_element
# Tillie
这两个方法是对应的关于elements的迭代器,通过它们就可以像前或者向后访问文档的解析内容,就好像文档正在被解析一样:
for element in last_a_tag.next_elements:
print(repr(element))
# u'Tillie'
# u';\nand they lived at the bottom of a well.'
# u'\n\n'
# ...
# u'...'
# u'\n'
# None
BeautifulSoup定义了很多搜索方法,这里着重介绍2个:
find()和find_all()。其他方法的参数和用法类似。
html_doc = """
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.
...
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc)
使用find_all()类似方法可以查找到想要查找的文档内容
介绍find_all方法前,首先介绍一下过滤器的类型,这些过滤器贯穿整个关于搜索的API。过滤器可以用在tag的name中,节点的属性中,字符串中或者他们的混合中。
最简单的过滤器是字符串。在搜索方法中传入一个字符串参数,BeautifulSoup会查找与字符串完整匹配的内容,下面的例子用于查找文档中所有的标签:
soup.find_all('b')
# [The Dormouse's story]
如果传入字节码参数,BeautifulSoup会当做UTF-8编码,可以传入一段Unicode编码来避免BeautifulSoup解析编码出错
如果传入正则表达式作为参数,BeautifulSoup会通过正则表达式的matcfh()来匹配内容。下面的例子中找出所有以b为开头的标签,这表明和标签都应该被找到:
import re
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
# body
# b
关于正则表达式,接下来将重新有一篇文章整体介绍。
如果传入的参数是列表,BeautifulSoup将会与列表中任一元素匹配的内容返回。下面代码找到文档中所有标签和标签:
soup.find_all(["a", "b"])
# [The Dormouse's story,
# Elsie,
# Lacie,
# Tillie]
True可以匹配任何值。
如果没有合适的过滤器,那么还可以定义一个方法,方法只接受一个元素参数,如果这个方法返回True表示当前元素匹配并且被找到,如果不是则返回False。
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
soup.find_all(has_class_but_no_id)
# [The Dormouse's story
,
# Once upon a time there were...
,
# ...
]
这里需要注意的是,上面提到了,可以把tag的属性当做一个字典,可以使用has_attr方法来判断是否具有属性。
find_all(name, attrs, recursive, text, **kwargs)
find_all()方法搜索当前tag的所有tag子节点。在这部分继续使用一下文本段,并先给出几个例子:
soup.find_all("title")
# [The Dormouse's story ]
soup.find_all("p", "title")
# [The Dormouse's story
]
soup.find_all("a")
# [Elsie,
# Lacie,
# Tillie]
soup.find_all(id="link2")
# [Lacie]
import re
soup.find(text=re.compile("sisters"))
# u'Once upon a time there were three little sisters; and their names were\n'
接下来,详细介绍一下各个参数的含义
name参数可以查找所有名字为name的tag,字符串对象会被自动忽略掉
简单的用法如下:
soup.find_all("title")
# [The Dormouse's story ]
如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当做置顶名字的tag属性来搜索,如果包含一个名字为”id”的参数,BeautifulSoup会搜索每个tag的”id”属性。
soup.find_all(id='link2')
# [Lacie]
如果传入href参数,BeautifulSoup会搜索每个tag的”href”属性:
soup.find_all(href=re.compile("elsie"))
# [Elsie]
搜索指定名字的属性时,可以使用参数值包括字符串、正则表达式、列表、True:
下面的例子在文档树中查找所有包含id属性的tag,无论id的值是什么:
soup.find_all(id=True)
# [Elsie,
# Lacie,
# Tillie]
使用多个指定名字的参数可以同时过滤tag的多个属性:
soup.find_all(href=re.compile("elsie"), id='link1')
# [three]
有些tag属性在搜索中不能使用,比如HTML5中的date-*属性:
data_soup = BeautifulSoup('foo!')
data_soup.find_all(data-foo="value")
# SyntaxError: keyword can't be an expression
当使用find_all()对全部整理文本进行搜索的时候,也可以使用字典定义多个参数:
data_soup.find_all(attrs={"data-foo": "value"})
# [foo!]
按照CSS类名搜索tag功能非常实用,但表示CSS类名搜索tag的功能非常实用,但识别CSS类名的关键字class在python中是保留字,因此BeautifulSoup的4.1.1版本开始,可以通过class_参数搜索指定CSS类名的tag:
soup.find_all("a", class_="sister")
# [Elsie,
# Lacie,
# Tillie]
class_参数同样接受不同类型的过滤器,字符串、正则表达式、方法或者True都可以在该参数下使用:
soup.find_all(class_=re.compile("itl"))
# [The Dormouse's story
]
def has_six_characters(css_class):
return css_class is not None and len(css_class) == 6
soup.find_all(class_=has_six_characters)
# [Elsie,
# Lacie,
# Tillie]
搜索class属性时多值属性,按照CSS类名搜索tag时,可以分别搜索tag中的每个CSS类名,也可以通过CSS值完全匹配:
css_soup = BeautifulSoup('')
css_soup.find_all("p", class_="strikeout")
# []
css_soup.find_all("p", class_="body")
# []
css_soup.find_all("p", class_="body strikeout")
# []
搜索class属性时,也可以通过CSS值完全匹配:
css_soup.find_all("p", class_="body strikeout")
# []
完全匹配class的值时,如果CSS类名的顺序与实际比附,将搜索不到结果:
soup.find_all("a", attrs={"class": "sister"})
# [Elsie,
# Lacie,
# Tillie]
通过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。
soup.find_all("a", text="Elsie")
# [Elsie]
find_all()方法返回全部的搜索结构,如果文档树很大那么搜索的记说会很慢,如果我们不需要全部结果,可以使用limit参数限制返回结果的数量。效果与SQL中的limit关键字类似,当搜索到的结果数量达到limit的限制时,就会停止搜索并返回结果
如下所示:
soup.find_all("a", limit=2)
# [Elsie,
# Lacie]
调用tag的find_all()方法时,BeautifulSoup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数recursive = False
find_all()几乎是BeautifulSoup中最常用的搜索方法,所以我们定了它的简写方法。BeautifulSoup对象和tag对象可以被当做一个方法来使用,这个方法的执行结果与调用这个对象的find_all方法相同,下面两行代码是等价的:
soup.find_all("a")
soup("a")
soup.title.find_all(text=True)
soup.title(text=True)
find(name, attrs, recursive, text, **kwargs)
find_all()方法将返回文档中所有符合条件的tag,尽管有时候我们只想得到一个结果,比如文档中只有一个标签,那么使用find_all()方法来查找标签就不太合适,使用find_all方法并设置limit=1参数不如直接使用find()方法。下面两行代码是等价的:
soup.find_all('title', limit=1)
# [The Dormouse's story ]
soup.find('title')
# The Dormouse's story
而区别在于,find_all()方法返回的结果列表,而find()方法将直接返回结果。
与大部分搜索文档树类型的函数与find、find_all()的性质类似。BeautifulSoup提供了与遍历文档树类似的方法对文档树进行搜索。主要包含以下几类:
find_parents(name, attrs, recursive, text, **kwargs)
find_parent(name, attrs, recursive, text, **kwargs)
对所有parent节点进行迭代。注意,find()、find_all()是对所有当前节点的子孙节点进行搜索,而这两个函数是对当前节点的父辈节点。
a_string = soup.find(text="Lacie")
a_string
# u'Lacie'
a_string.find_parents("a")
# [Lacie]
a_string.find_parent("p")
# 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.
a_string.find_parents("p", class="title")
# []
find_next_siblings(name, attrs, recursive, text, **kwargs)
find_next_sibling(name, attrs, recursive, text, **kwargs)
这两个方法对后面所有的兄弟节点进行搜索,搜索范围即为与next_silbings的迭代范围。
first_link = soup.a
first_link
# Elsie
first_link.find_next_siblings("a")
# [Lacie,
# Tillie]
first_story_paragraph = soup.find("p", "story")
first_story_paragraph.find_next_sibling("p")
# ...
find_all_next(name, attrs, recursive, text, **kwargs)
find_next(name, attrs, recursive, text, **kwargs)
这两个方法对后面的所有元素进行搜索,搜索方式即为next_elements()迭代得到的所有元素,同时包括节点和字符串,将所有满足条件的结果返回。
first_link = soup.a
first_link
# Elsie
first_link.find_all_next(text=True)
# [u'Elsie', u',\n', u'Lacie', u' and\n', u'Tillie',
# u';\nand they lived at the bottom of a well.', u'\n\n', u'...', u'\n']
first_link.find_next("p")
# ...
find_all_previous(name, attrs, recursive, text, **kwargs)
find_previous(name, attrs, recursive, text, **kwargs)