📜  Beautiful Soup-通过标签导航

📅  最后修改于: 2020-11-09 14:29:56             🧑  作者: Mango


 

在本章中,我们将讨论有关“通过标签导航”的内容。

以下是我们的html文档-

>>> html_doc = """
Tutorials Point

The Biggest Online Tutorials Library, It's all Free

Top 5 most used Programming Languages are: Java, C, Python, JavaScript and C; as per online survey.

Programming Languages

""" >>> >>> from bs4 import BeautifulSoup >>> soup = BeautifulSoup(html_doc, 'html.parser') >>>

基于上述文档,我们将尝试从文档的一部分移至另一部分。

下降

在任何HTML文档中,元素的重要组成部分之一是标签,其中可能包含其他标签/字符串(标签的子元素)。 Beautiful Soup提供了不同的方式来导航和遍历标签的子对象。

使用标签名称导航

搜索分析树的最简单方法是按其名称搜索标签。如果您想要标签,请使用soup.head-

>>> soup.head
&t;title>Tutorials Point
>>> soup.title
Tutorials Point

在标签中获取特定标签(例如第一个标签)。

>>> soup.body.b
The Biggest Online Tutorials Library, It's all Free

使用标签名称作为属性将只给您该名称的第一个标签-

>>> soup.a
Java

要获取标签的所有属性,可以使用find_all()方法-

>>> soup.find_all("a")
[Java, C, Python, JavaScript, C]>>> soup.find_all("a")
[Java, C, Python, JavaScript, C]

.contents和.children

我们可以通过其.contents在列表中搜索标签的孩子-

>>> head_tag = soup.head
>>> head_tag
Tutorials Point
>>> Htag = soup.head
>>> Htag
Tutorials Point
>>>
>>> Htag.contents
[Tutorials Point
>>>
>>> Ttag = head_tag.contents[0]
>>> Ttag
Tutorials Point
>>> Ttag.contents
['Tutorials Point']

BeautifulSoup对象本身具有子级。在这种情况下,标记是BeautifulSoup对象的子代-

>>> len(soup.contents)
2
>>> soup.contents[1].name
'html'

字符串没有.contents,因为它不能包含任何内容-

>>> text = Ttag.contents[0]
>>> text.contents
self.__class__.__name__, attr))
AttributeError: 'NavigableString' object has no attribute 'contents'

而不是将它们获取为列表,而是使用.children生成器来访问标签的孩子-

>>> for child in Ttag.children:
print(child)
Tutorials Point

。子孙

.descendants属性允许您递归遍历标签的所有子元素-

它的直系子孙及其直系子孙的子孙,依此类推-

>>> for child in Htag.descendants:
print(child)
Tutorials Point
Tutorials Point

标记只有一个子代,但是它有两个后代:标记和<title>标记的子代。 beautifulsoup对象只有一个直接子代(<html>标记),但是它有很多后代-</p> <div class="hcb_wrap"> <pre class="prism line-numbers lang-java" data-lang="java"><code class="language-markup">>>> len(list(soup.children)) 2 >>> len(list(soup.descendants)) 33 </code></pre> </div> <h2>。字符串</h2> <p>如果标记只有一个孩子,并且该孩子是NavigableString,则该孩子可以作为。字符串-</p> <div class="hcb_wrap"> <pre class="prism line-numbers lang-java" data-lang="java"><code class="language-markup">>>> Ttag.string 'Tutorials Point' </code></pre> </div> <p>如果标签的唯一子对象是另一个标签,并且该标签具有。字符串,则认为父标签具有相同的标签。字符串作为其子-</p> <div class="hcb_wrap"> <pre class="prism line-numbers lang-java" data-lang="java"><code class="language-markup">>>> Htag.contents [<title>Tutorials Point] >>> >>> Htag.string 'Tutorials Point'

但是,如果标签包含多个内容,则不清楚是什么。字符串应该引用,所以。字符串定义为None-

>>> print(soup.html.string)
None

。字符串和stripped_strings

如果标记中包含多个内容,您仍然可以只查看字符串。使用 。字符串生成器-

>>> for string in soup.strings:
print(repr(string))
'\n'
'Tutorials Point'
'\n'
'\n'
"The Biggest Online Tutorials Library, It's all Free"
'\n'
'Top 5 most used Programming Languages are: \n'
'Java'
',\n'
'C'
',\n'
'Python'
',\n'
'JavaScript'
' and\n'
'C'
';\n \nas per online survey.'
'\n'
'Programming Languages'
'\n'

要删除多余的空格,请使用.stripped_strings生成器-

>>> for string in soup.stripped_strings:
print(repr(string))
'Tutorials Point'
"The Biggest Online Tutorials Library, It's all Free"
'Top 5 most used Programming Languages are:'
'Java'
','
'C'
','
'Python'
','
'JavaScript'
'and'
'C'
';\n \nas per online survey.'
'Programming Languages'

往上走

用“家族树”的比喻来说,每个标签和每个字符串都有一个父对象:包含它的标签:

。父母

要访问元素的父元素,请使用.parent属性。

>>> Ttag = soup.title
>>> Ttag
Tutorials Point
>>> Ttag.parent
title>Tutorials Point

在我们的html_doc中,标题字符串本身有一个父:包含它的标记-</p> <div class="hcb_wrap"> <pre class="prism line-numbers lang-java" data-lang="java"><code class="language-markup">>>> Ttag.string.parent <title>Tutorials Point

像这样的顶级标签的父对象是Beautifulsoup对象本身-

>>> htmltag = soup.html
>>> type(htmltag.parent)

Beautifulsoup对象的.parent定义为None-

>>> print(soup.parent)
None

。父母

要遍历所有父元素,请使用.parents属性。

>>> link = soup.a
>>> link
Java
>>>
>>> for parent in link.parents:
if parent is None:
print(parent)
else:
print(parent.name)
p
body
html
[document]

侧身走

以下是一个简单的文档-

在上述文档中,标记处于同一级别,并且它们都是同一标记的子代。 标记均为同级。

.next_sibling和.previous_sibling

使用.next_sibling和.previous_sibling在解析树的同一级别上的页面元素之间导航:

>>> sibling_soup.b.next_sibling
The Biggest Online Tutorials Library, It's all Free
>>>
>>> sibling_soup.c.previous_sibling
TutorialsPoint

标记具有.next_sibling但没有.previous_sibling,因为在树的同一级别上标记之前没有任何内容,标记的情况相同。

>>> print(sibling_soup.b.previous_sibling)
None
>>> print(sibling_soup.c.next_sibling)
None

这两个字符串不是兄弟姐妹,因为它们没有相同的父对象。

>>> sibling_soup.b.string
'TutorialsPoint'
>>>
>>> print(sibling_soup.b.string.next_sibling)
None

.next_siblings和.previous_siblings

要遍历标签的兄弟姐妹,请使用.next_siblings和.previous_siblings。

>>> for sibling in soup.a.next_siblings:
print(repr(sibling))
',\n'
C
',\n'
>a class="prog" href="https://www.tutorialspoint.com/python/index.htm" id="link3">Python
',\n'
JavaScript
' and\n'
C
';\n \nas per online survey.'
>>> for sibling in soup.find(id="link3").previous_siblings:
print(repr(sibling))
',\n'
C
',\n'
Java
'Top 5 most used Programming Languages are: \n'

来回走

现在让我们回到前面的“ html_doc”示例的前两行:

&t;html>Tutorials Point

The Biggest Online Tutorials Library, It's all Free

HTML解析器需要以上字符的字符串,并把它转换为一系列像“打开一个标签”,“打开一个标签”,事件“打开标签”,“添加一个字符串”, “关闭</ title>标签”,“关闭</ head>标签”,“打开<h4>标签”等等。 BeautifulSoup提供了不同的方法来重建文档的初始解析。</p> <h3>.next_element和.previous_element</h3> <p>标记或字符串的.next_element属性指向之后立即解析的内容。有时它看起来与.next_sibling类似,但是并不完全相同。以下是我们的“ html_doc”示例文档中的最后一个<a>标记。</p> <div class="hcb_wrap"> <pre class="prism line-numbers lang-java" data-lang="java"><code class="language-markup">>>> last_a_tag = soup.find("a", id="link5") >>> last_a_tag <a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm" id="link5">C</a> >>> last_a_tag.next_sibling ';\n \nas per online survey.' </code></pre> </div> <p>但是,该<a>标记的.next_element(紧接在<a>标记之后的内容)不是该句子的其余部分:它是单词“ C”:</p> <div class="hcb_wrap"> <pre class="prism line-numbers lang-java" data-lang="java"><code class="language-markup">>>> last_a_tag.next_element 'C' </code></pre> </div> <p>以上行为是因为在原始标记中,字母“ C”出现在该分号之前。解析器遇到一个<a>标记,然后是字母“ C”,然后是结束</a>标记,然后是分号和句子的其余部分。分号与<a>标记处于同一级别,但是首先遇到字母“ C”。</p> <p>.previous_element属性与.next_element完全相反。它指向此元素之前立即解析的任何元素。</p> <div class="hcb_wrap"> <pre class="prism line-numbers lang-java" data-lang="java"><code class="language-markup">>>> last_a_tag.previous_element ' and\n' >>> >>> last_a_tag.previous_element.next_element <a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm" id="link5">C</a> </code></pre> </div> <h3>.next_elements和.previous_elements</h3> <p>我们使用这些迭代器向前和向后移动到一个元素。</p> <div class="hcb_wrap"> <pre class="prism line-numbers lang-java" data-lang="java"><code class="language-markup">>>> for element in last_a_tag.next_e lements: print(repr(element)) 'C' ';\n \nas per online survey.' '\n' <p class="prog">Programming Languages</p> 'Programming Languages' '\n' </code></pre> </div> </div> </div> </div> </div> </div> </div> <footer> <div class="bg-white text-center pb-1"> <p class="text-body-tertiary pt-3 lh-lg text-opacity-50" id="footer-text">Copyright © 2020 - 2024 版权所有 <br> <a href="https://beian.miit.gov.cn/" target="_blank" class="text-opacity-50 text-body-tertiary mt-1 mb-1">蜀ICP备20006366号-1</a> <br> Made with ❤️ in Chengdu </p> </div> </footer> <!-- 引入Bootstrap JavaScript库 --> <script src="https://unpkg.com/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script> <!-- 引入Meilisearch搜索相关的JavaScript库 --> <script src="https://cdn.jsdelivr.net/npm/@meilisearch/instant-meilisearch/dist/instant-meilisearch.umd.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4"></script> <script src="https://imangodoc.com/static/javascript/meili_custom.js"></script> <!-- 引入prismjs代码高亮相关的JavaScript库 --> <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/toolbar/prism-toolbar.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script> </body> </html>