2016 年 11 月 13 日
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.
...
# # 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. #
# ... #
Extremely bold
Back to the homepage
No longer bold
` 标签”,等等。Beautiful Soup 提供了重现解析器初始化过程的方法。 #### .next_element 和 .previous_element next_element 属性指向解析过程中下一个被解析的对象(字符串或 tag ),结果可能与 `.next_sibling` 相同,但通常是不一样的。 这是《爱丽丝》文档中最后一个 `` 标签,它的 `.next_sibling` 结果是一个字符串,因为当前的解析过程遇到了 `` 标签而中断了: ```python last_a_tag = soup.find("a", id="link3") last_a_tag # Tillie last_a_tag.next_sibling # '; and they lived at the bottom of a well.' ``` 但这个 `` 标签的 `.next_element` 属性结果是在 `` 标签被解析之后的解析内,不是 `` 标签后的句子部分,应该是字符串 “Tillie”: ```python last_a_tag.next_element # u'Tillie' ``` 这是因为在原始文档中,字符串 “Tillie” 在分号前出现,解析器先进入 `` 标签,然后是字符串 “Tillie” ,然后关闭 `` 标签,然后是分号和剩余部分。分号与 `` 标签在同一层级,但是字符串 “Tillie” 会被先解析。 `.previous_element` 属性刚好与 `.next_element` 相反,它指向当前被解析的对象的前一个解析对象: ```python last_a_tag.previous_element # u' and\n' last_a_tag.previous_element.next_element # Tillie ``` #### .next_elements 和 .previous_elements 通过 `.next_elements` 和 `.previous_elements` 的迭代器就可以向前或向后访问文档的解析内容,就好像文档正在被解析一样: ```python 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' #
` 标签: ```python soup.find_all(has_class_but_no_id) # [
Once upon a time there were...
` 标签没有 `` 标签,因为 `` 标签还定义了 “id” ,没有返回 `` 和 ``,因为 `` 和 `` 中没有定义 “class” 属性。 下面代码找到所有被文字包含的节点内容: ```python from bs4 import NavigableString def surrounded_by_strings(tag): return (isinstance(tag.next_element, NavigableString) and isinstance(tag.previous_element, NavigableString)) for tag in soup.find_all(surrounded_by_strings): print tag.name # p # a # a # a # p ``` 现在来了解一下搜索方法的细节。 #### find_all() `find_all( name , attrs , recursive , text , **kwargs )` `find_all()` 方法搜索当前 tag 的所有 tag 子节点,并判断是否符合过滤器的条件。这里有几个例子: ```python 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' ``` 有几个方法很相似,还有几个方法是新的,参数中的 text 和 id 是什么含义?为什么 `find_all("p", "title")` 返回的是 CSS Class 为 “title” 的 `
` 标签?我们来仔细看一下 `find_all()` 的参数: #### name 参数 name 参数可以查找所有名字为 name 的 tag ,字符串对象会被自动忽略掉。 简单的用法如下: ```python soup.find_all("title") # [
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.
` 标签,是目标叶子节点的间接父辈节点,所以也可以被找到。包含class值为 “title” 的 `
` 标签不是不是目标叶子节点的父辈节点,所以通过 `find_parents()` 方法搜索不到。 `find_parent()` 和 `find_parents()` 方法会让人联想到 `.parent` 和 `.parents` 属性。它们之间的联系非常紧密。搜索父辈节点的方法实际上就是对 `.parents` 属性的迭代搜索。 #### ind_next_siblings() 合 find_next_sibling() `find_next_siblings( name , attrs , recursive , text , **kwargs )` `find_next_sibling( name , attrs , recursive , text , **kwargs )` 这2个方法通过 `.next_siblings` 属性对当 tag 的所有后面解析的兄弟 tag 节点进行迭代,`find_next_siblings()` 方法返回所有符合条件的后面的兄弟节点,`find_next_sibling()` 只返回符合条件的后面的第一个 tag 节点。 ```python 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_previous() 和 find_previous() `find_all_previous( name , attrs , recursive , text , **kwargs )` `find_previous( name , attrs , recursive , text , **kwargs )` 这2个方法通过 `.previous_elements` 属性对当前节点前面的 tag 和字符串进行迭代,`find_all_previous()` 方法返回所有符合条件的节点,`find_previous()` 方法返回第一个符合条件的节点。 ```python first_link = soup.a first_link # Elsie first_link.find_all_previous("p") # [
Once upon a time there were three little sisters; ...
Hello
Howdy, y'all
Pip-pip, old fruit
Bonjour mes amis
I wish I was bold.