beautiful soup 4.0(bs4)遍历文档树(2)

1、概述

在使用爬虫程序对爬取的文档进行处理时,经常要做的一个操作就是遍历文档树。文档以树形结构进行组织,所以遍历文档的操作又叫遍历文档树。beautiful soup本身提供了很多遍历文档树的方法,本文主要讨论遍历文档树的方法。

2、遍历文档树

2.1 准备工作

本文将使用公众号的文章作为遍历的对象,所以首先需要先把整个文档抓取下来,并将多余的元素去除掉,只保留文档的主体部分以保证文档分析的准确性,请参照如下代码:

from bs4 import BeautifulSoup
import requests
bk_url = 'https://mp.weixin.qq.com/s?src=11&timestamp=1536542507&ver=1113&signature=bx7vKGc*P*VXdS7ymgZqblP666yq31soLbvKx1ehonqJAojCMT9aUq5y8Sv8CKTWd4C87pCCSw*kts5k4KaNUmdXuZkEMoVP59DPzKxQZhZlE6UCV3f3iw5qe5XvnJxs&new=1'
headers = {"User-Agent" : "User-Agent:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"}
r = requests.get(bk_url,headers=headers)
r.encoding = 'utf-8'
soup =  BeautifulSoup(r.text,'html.parser')

2.2 获取子节点

在遍历文档树时一个经常性的操作就是获取子节点,我们可以使用下面几种方法来获取子节点。

2.2.1 使用节点名称获取子节点

可以使用节点名字直接获取相关节点,请参照如下代码

from bs4 import BeautifulSoup
import requests
bk_url = 'https://mp.weixin.qq.com/s?src=11&timestamp=1536542507&ver=1113&signature=bx7vKGc*P*VXdS7ymgZqblP666yq31soLbvKx1ehonqJAojCMT9aUq5y8Sv8CKTWd4C87pCCSw*kts5k4KaNUmdXuZkEMoVP59DPzKxQZhZlE6UCV3f3iw5qe5XvnJxs&new=1'
headers = {"User-Agent" : "User-Agent:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"}
r = requests.get(bk_url,headers=headers)
r.encoding = 'utf-8'
soup =  BeautifulSoup(r.text,'html.parser')
body = soup.body
print(body)

2.2.2 .contents 和 .children

1、元素的 .contents 属性可以将tag的子节点以列表的方式输出,请参照如下代码:

head = soup.head
head.contents

注意:字符串没有 .contents 属性,因为字符串没有子节点

2、通过tag的 .children 生成器,可以对tag的子节点进行循环,请参照如下代码:

for child in head.children:
    print(child)

2.2.3 .descendants

children与contents属性只能获取元素的直接子节点,但子节点的子节点是无法获取到的。如果需要获取某一个元素的所有子孙节点可以使用.descendants方法。

请参照如下代码:

for child in head.descendants:
    print(child.name)

输出效果如下图所示:

2.2.4 .string

如果元素只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点,请参照如下代码:

print(head.title.string)

输出结果如下图所示:

如果一个元素仅有一个子节点,那么这个tag也可以使用 .string 方法,输出结果与当前唯一子节点的 .string 结果相同。如果tag包含了多个子节点,tag就无法确定 .string 方法应该调用哪个子节点的内容, .string 的输出结果是 None ,请参照如下代码:

print(head.string)

输出结果如下图所示:

2.2.5 .strings 和 stripped_strings

如果元素中包含多个字符串 ,可以使用 .strings 来循环获取,请参照如下代码:

for child_str in head.strings:
    print(child_str)

输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容,全部是空格的行会被忽略掉,段首和段末的空白会被删除。请参照如下代码:

for child_str in head.stripped_strings:
    print(child_str)

2.2.6 父节点

1) parent获取直接的父节点,请参考如下代码:

print(head.parent)

2) .parents 通过元素的 .parents 属性可以递归得到元素的所有父辈节点,下面的例子使用了 .parents 方法遍历了<a>标签到根节点的所有节点。

link = soup.a
link
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
for parent in link.parents:
    if parent is None:
        print(parent)
    else:
        print(parent.name)
# p
# body
# html
# [document]
# None

2.2.7 兄弟节点

下面的例子以下面的html为基础进行操作

sibling_soup = BeautifulSoup("<a><b>text1</b><c>text2</c></b></a>")
print(sibling_soup.prettify())
# <html>
#  <body>
#   <a>
#    <b>
#     text1
#    </b>
#    <c>
#     text2
#    </c>
#   </a>
#  </body>
# </html>

1) .next_sibling 和 .previous_sibling

在文档树中,使用 .next_sibling 和 .previous_sibling 属性来查询兄弟节点:

请参照如下代码:

sibling_soup.b.next_sibling
# <c>text2</c>

sibling_soup.c.previous_sibling
# <b>text1</b>

2).next_siblings 和 .previous_siblings

通过 .next_siblings 和 .previous_siblings 属性可以对当前节点的兄弟节点迭代输出:

请参照如下代码:

for sibling in soup.a.next_siblings:
    print(repr(sibling))
    # u',\n'
    # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
    # u' and\n'
    # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
    # 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'
    # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
    # u',\n'
    # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
    # u'Once upon a time there were three little sisters; and their names were\n'
    # None

猜你喜欢

转载自blog.csdn.net/amao1998/article/details/82588679