Beautiful Soup 简明教程
Beautiful Soup - Overview
在当今世界,我们拥有大量免费的非结构化数据/信息(主要是 Web 数据)。有时,这些免费提供的数据很容易阅读,有时则不然。无论您如何获取数据,网络抓取都是将非结构化数据转换为更易于阅读和分析的结构化数据的非常有用的工具。换句话说,网络抓取是收集、组织和分析大量数据的途径。因此,我们首先了解什么是网络抓取。
Introduction to Beautiful Soup
Beautiful Soup 是一个以爱丽丝漫游仙境中路易斯·卡罗尔同名诗命名的 Python 库。Beautiful Soup 是一个 Python 包,顾名思义,它会解析不必要的数据并通过修复不良 HTML 来帮助整理和设置杂乱的 Web 数据,并以易于遍历的 XML 结构呈现给我们。
简而言之,Beautiful Soup 是一个 Python 包,它允许我们从 HTML 和 XML 文档中提取数据。
HTML tree Structure
在我们了解 Beautiful Soup 提供的功能之前,让我们首先了解 HTML 树结构。
文档树中的根元素是 html,它可以有父元素、子元素和兄弟元素,并由它在树结构中的位置决定。要在 HTML 元素、属性和文本之间移动,您必须在树结构中的节点之间移动。
让我们假设网页如下所示 −
它转换成一个 html 文档,如下所示 −
<html>
<head>
<title>TutorialsPoint</title>
</head>
<body>
<h1>Tutorialspoint Online Library</h1>
<p><b>It's all Free</b></p>
</body>
</html>
它仅仅表示,对于上述 html 文档,我们具有如下 HTML 树结构 −
Beautiful Soup - web-scraping
抓取只是从(各种方法)中提取、复制和筛选数据的过程。
当我们从网络上抓取或提取数据或提要(例如来自网页或网站)时,这被称为网络抓取。
因此,网络抓取(也称为网络数据提取或网络获取)是从网络中提取数据的过程。简而言之,网络抓取为开发人员提供了一种从互联网收集和分析数据的方法。
Beautiful Soup - Installation
Beautiful Soup 是一个让从网页中抓取信息变得容易的库。它位于 HTML 或 XML 解析器之上,为解析树的迭代、搜索和修改提供了 Pythonic 惯用语。
BeautifulSoup 软件包不是 Python 标准库的一部分,因此必须安装它。在安装最新版本之前,让我们按照 Python 推荐的方法创建一个虚拟环境。
虚拟环境允许我们为特定项目创建 Python 的隔离工作副本,而不会影响外部设置。
我们将使用 Python 标准库中的 venv 模块来创建虚拟环境。PIP 默认包含在 Python 3.4 及更高版本中。
在 Windows 中使用以下命令创建虚拟环境
C:\uses\user\>python -m venv myenv
在 Ubuntu Linux 中,在创建虚拟环境之前更新 APT 存储库并根据需要安装 venv
mvl@GNVBGL3:~ $ sudo apt update && sudo apt upgrade -y
mvl@GNVBGL3:~ $ sudo apt install python3-venv
然后使用以下命令创建一个虚拟环境
mvl@GNVBGL3:~ $ sudo python3 -m venv myenv
你需要激活虚拟环境。在 Windows 中使用该命令
C:\uses\user\>cd myenv
C:\uses\user\myenv>scripts\activate
(myenv) C:\Users\users\user\myenv>
在 Ubuntu Linux 中,使用以下命令激活虚拟环境
mvl@GNVBGL3:~$ cd myenv
mvl@GNVBGL3:~/myenv$ source bin/activate
(myenv) mvl@GNVBGL3:~/myenv$
虚拟环境的名称显示在括号中。现在它已激活,我们现在可以在其中安装 BeautifulSoup。
(myenv) mvl@GNVBGL3:~/myenv$ pip3 install beautifulsoup4
Collecting beautifulsoup4
Downloading beautifulsoup4-4.12.2-py3-none-any.whl (142 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
143.0/143.0 KB 325.2 kB/s eta 0:00:00
Collecting soupsieve>1.2
Downloading soupsieve-2.4.1-py3-none-any.whl (36 kB)
Installing collected packages: soupsieve, beautifulsoup4
Successfully installed beautifulsoup4-4.12.2 soupsieve-2.4.1
请注意,Beautifulsoup4 的最新版本为 4.12.2,并且需要 Python 3.8 或更高版本。
如果没有安装 easy_install 或 pip,则可以下载 Beautiful Soup 4 源归档并使用 setup.py 安装它。
(myenv) mvl@GNVBGL3:~/myenv$ python setup.py install
要检查 Beautifulsoup 是否已正确安装,请在 Python 终端中输入以下命令 -
>>> import bs4
>>> bs4.__version__
'4.12.2'
如果安装不成功,你将收到 ModuleNotFoundError。
你还需要安装 requests 库。它是一个用于 Python 的 HTTP 库。
pip3 install requests
Installing a Parser
默认情况下,Beautiful Soup 支持 Python 标准库中包含的 HTML 解析器,但它还支持许多外部第三方 Python 解析器,如 lxml 解析器或 html5lib 解析器。
要安装 lxml 或 html5lib 解析器,请使用命令:
pip3 install lxml
pip3 install html5lib
这些解析器具有各自的优点和缺点,如下所示 -
Parser: Python’s html.parser
Usage - BeautifulSoup(markup, "html.parser")
Advantages
-
Batteries included
-
Decent speed
-
易于处理(自 Python 3.2 起)
Disadvantages
-
没有 lxml 快,不如 html5lib 宽松。
Parser: lxml’s HTML parser
Usage − BeautifulSoup(markup, "lxml")
Advantages
-
Very fast
-
Lenient
Disadvantages
.
Beautiful Soup - Souping the Page
是时候在其中一个 html 页面(采用网页 - https://www.tutorialspoint.com/index.htm ,您可以选择任何其他您想要的网页)中测试我们的 Beautiful Soup 程序包,并从中提取一些信息了。
在以下代码中,我们尝试从网页中提取标题 -
Example
from bs4 import BeautifulSoup
import requests
url = "https://www.tutorialspoint.com/index.htm"
req = requests.get(url)
soup = BeautifulSoup(req.content, "html.parser")
print(soup.title)
Output
<title>Online Courses and eBooks Library<title>
一项常见任务是从网页中提取所有 URL。为此,我们只需要添加以下代码行 -
for link in soup.find_all('a'):
print(link.get('href'))
Output
下面显示了上述循环的部分输出 -
https://www.tutorialspoint.com/index.htm
https://www.tutorialspoint.com/codingground.htm
https://www.tutorialspoint.com/about/about_careers.htm
https://www.tutorialspoint.com/whiteboard.htm
https://www.tutorialspoint.com/online_dev_tools.htm
https://www.tutorialspoint.com/business/index.asp
https://www.tutorialspoint.com/market/teach_with_us.jsp
https://www.facebook.com/tutorialspointindia
https://www.instagram.com/tutorialspoint_/
https://twitter.com/tutorialspoint
https://www.youtube.com/channel/UCVLbzhxVTiTLiVKeGV7WEBg
https://www.tutorialspoint.com/categories/development
https://www.tutorialspoint.com/categories/it_and_software
https://www.tutorialspoint.com/categories/data_science_and_ai_ml
https://www.tutorialspoint.com/categories/cyber_security
https://www.tutorialspoint.com/categories/marketing
https://www.tutorialspoint.com/categories/office_productivity
https://www.tutorialspoint.com/categories/business
https://www.tutorialspoint.com/categories/lifestyle
https://www.tutorialspoint.com/latest/prime-packs
https://www.tutorialspoint.com/market/index.asp
https://www.tutorialspoint.com/latest/ebooks
…
…
要分析存储在当前工作目录中的网页,请获取指向 html 文件的文件对象,并将其用作 Beautiful Soup() 构造函数的参数。
Example
from bs4 import BeautifulSoup
with open("index.html") as fp:
soup = BeautifulSoup(fp, 'html.parser')
print(soup)
Output
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1 style="text-align:center;">Hello World</h1>
</body>
</html>
您还可以按如下方式使用包含 HTML 脚本的字符串作为构造函数的参数 -
from bs4 import BeautifulSoup
html = '''
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1 style="text-align:center;">Hello World</h1>
</body>
</html>
'''
soup = BeautifulSoup(html, 'html.parser')
print(soup)
Beautiful Soup 使用可用的最佳解析器解析文档。如果没有另行指定,它将使用 HTML 解析器。
Beautiful Soup - Kinds of objects
当我们将 HTML 文档或字符串传递给 beautifulsoup 构造函数时,beautifulsoup 基本上将复杂的 HTML 页面转换成不同的 Python 对象。下面我们将讨论 bs4 包中定义的四种主要对象。
-
Tag
-
NavigableString
-
BeautifulSoup
-
Comments
Tag Object
HTML 标签用于定义各种类型的内容。BeautifulSoup 中的标签对象对应于实际页面或文档中的 HTML 或 XML 标签。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup('<b class="boldest">TutorialsPoint</b>', 'lxml')
tag = soup.html
print (type(tag))
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup('<b class="boldest">TutorialsPoint</b>', 'lxml')
tag = soup.html
print (tag.name)
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup('<b class="boldest">TutorialsPoint</b>', 'lxml')
tag = soup.html
tag.name = "strong"
print (tag)
Attributes (tag.attrs)
标签对象可以具有任意数量的属性。在上面的示例中,标签 <b class="boldest"> 有一个属性 'class',其值为 "boldest”。任何不是标签的内容基本上都是一种属性,并且必须包含一个值。attrs 返回属性及其值的字典。您也可以通过访问键来访问属性。
在下面的示例中,Beautifulsoup() 构造函数的字符串自变量包含 HTML 输入标签。输入标签的属性由 “attr” 返回。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup('<input type="text" name="name" value="Raju">', 'lxml')
tag = soup.input
print (tag.attrs)
Output
{'type': 'text', 'name': 'name', 'value': 'Raju'}
我们可以使用字典操作符或方法对标签的属性进行任何类型的修改(添加/删除/修改)。
在下面的示例中,更新了值标签。更新后的 HTML 字符串显示了更改。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup('<input type="text" name="name" value="Raju">', 'lxml')
tag = soup.input
print (tag.attrs)
tag['value']='Ravi'
print (soup)
Output
<html><body><input name="name" type="text" value="Ravi"/></body></html>
我们添加了一个新的 id 标签,并删除了 value 标签。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup('<input type="text" name="name" value="Raju">', 'lxml')
tag = soup.input
tag['id']='nm'
del tag['value']
print (soup)
Multi-valued attributes
一些 HTML5 属性可以有多个值。最常用的类属性可以有多个 CSS 值。其他内容包括“rel”、“rev”、“headers”、“accesskey”和“accept-charset”。beautiful soup 中的多值属性显示为列表。
Example
from bs4 import BeautifulSoup
css_soup = BeautifulSoup('<p class="body"></p>', 'lxml')
print ("css_soup.p['class']:", css_soup.p['class'])
css_soup = BeautifulSoup('<p class="body bold"></p>', 'lxml')
print ("css_soup.p['class']:", css_soup.p['class'])
Output
css_soup.p['class']: ['body']
css_soup.p['class']: ['body', 'bold']
但是,如果任何属性包含多个值,但它不是任何 HTML 标准版本的多值属性,则 beautiful soup 会将该属性保留下来——
NavigableString object
通常情况下,一个字符串会放在特定类型的起始标签和结束标签中。浏览器的 HTML 引擎在渲染元素时,会将预期效果应用到字符串。例如,在 <b>Hello World</b> 中,您会在 <b> 和 </b> 标签中间找到一个字符串,以便以粗体渲染它。
NavigableString 对象表示标签的内容。它是 bs4.element.NavigableString 类的对象。要访问内容,请将 “.string” 与标签一起使用。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup("<h2 id='message'>Hello, Tutorialspoint!</h2>", 'html.parser')
print (soup.string)
print (type(soup.string))
Output
Hello, Tutorialspoint!
<class 'bs4.element.NavigableString'>
NavigableString 对象类似于 Python Unicode 字符串。它的一些功能支持导航树和搜索树。可以使用 str() 函数将 NavigableString 转换为 Unicode 字符串。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup("<h2 id='message'>Hello, Tutorialspoint!</h2>",'html.parser')
tag = soup.h2
string = str(tag.string)
print (string)
Output
Hello, Tutorialspoint!
正如 Python 字符串一样(不可变),NavigableString 也不能就地修改。但是,使用 replace_with() 可以将标记的内部字符串替换为另一个字符串。
BeautifulSoup object
BeautifulSoup 对象表示整个已解析对象。但是,它可以被认为类似于 Tag 对象。它是我们在尝试抓取网络资源时创建的对象。因为它类似于 Tag 对象,所以它支持解析和搜索文档树所需的功能。
Example
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
print (soup)
print (soup.name)
print ('type:',type(soup))
Output
<html>
<head>
<title>TutorialsPoint</title>
</head>
<body>
<h2>Departmentwise Employees</h2>
<ul>
<li>Accounts</li>
<ul>
<li>Anand</li>
<li>Mahesh</li>
</ul>
<li>HR</li>
<ul>
<li>Rani</li>
<li>Ankita</li>
</ul>
</ul>
</body>
</html>
[document]
type: <class 'bs4.BeautifulSoup'>
BeautifulSoup 对象的 name 属性始终返回 [document]。
如果将 BeautifulSoup 对象作为参数传递给特定函数(例如 replace_with()),则可以合并两个已解析的文档。
Comment object
在 HTML 和 XML 文档中,任何写在 <!-- 和 -→ 之间的内容都被视为注释。BeautifulSoup 可以将此类注释文本检测为 Comment 对象。
Example
from bs4 import BeautifulSoup
markup = "<b><!--This is a comment text in HTML--></b>"
soup = BeautifulSoup(markup, 'html.parser')
comment = soup.b.string
print (comment, type(comment))
Beautiful Soup - Inspect Data Source
为了使用 BeautifulSoup 和 Python 抓取网页,对于任何网页抓取项目,您的第一步应该是探索您想要抓取的网站。因此,在开始提取与您相关的信息之前,请先访问网站了解网站结构。
让我们访问 TutorialsPoint 的 Python 教程主页。在您的浏览器中打开 https://www.tutorialspoint.com/python3/index.htm 。
使用开发人员工具可以帮助您了解网站的结构。所有现代浏览器都安装了开发人员工具。
如果使用 Chrome 浏览器,请通过右上角菜单按钮 (⋮) 打开开发者工具,然后选择更多工具 → 开发者工具。
借助开发者工具,你可以浏览网站的文档对象模型 (DOM),以更好地了解其来源。在开发者工具中选择“元素”选项卡。你将看到具有可单击 HTML 元素的结构。
“教程”页面在左边的侧边栏显示目录表。右键单击任意一章并选择“检查”选项。
对于“元素”选项卡,找到与 TOC 列表相对应的标记,如下所示 −
右键单击 HTML 元素,复制 HTML 元素,并将其粘贴到任意编辑器中。
<ul>..</ul> 元素的 HTML 脚本现已获取。
<ul class="toc chapters">
<li class="heading">Python 3 Basic Tutorial</li>
<li class="current-chapter"><a href="/python3/index.htm">Python 3 - Home</a></li>
<li><a href="/python3/python3_whatisnew.htm">What is New in Python 3</a></li>
<li><a href="/python3/python_overview.htm">Python 3 - Overview</a></li>
<li><a href="/python3/python_environment.htm">Python 3 - Environment Setup</a></li>
<li><a href="/python3/python_basic_syntax.htm">Python 3 - Basic Syntax</a></li>
<li><a href="/python3/python_variable_types.htm">Python 3 - Variable Types</a></li>
<li><a href="/python3/python_basic_operators.htm">Python 3 - Basic Operators</a></li>
<li><a href="/python3/python_decision_making.htm">Python 3 - Decision Making</a></li>
<li><a href="/python3/python_loops.htm">Python 3 - Loops</a></li>
<li><a href="/python3/python_numbers.htm">Python 3 - Numbers</a></li>
<li><a href="/python3/python_strings.htm">Python 3 - Strings</a></li>
<li><a href="/python3/python_lists.htm">Python 3 - Lists</a></li>
<li><a href="/python3/python_tuples.htm">Python 3 - Tuples</a></li>
<li><a href="/python3/python_dictionary.htm">Python 3 - Dictionary</a></li>
<li><a href="/python3/python_date_time.htm">Python 3 - Date & Time</a></li>
<li><a href="/python3/python_functions.htm">Python 3 - Functions</a></li>
<li><a href="/python3/python_modules.htm">Python 3 - Modules</a></li>
<li><a href="/python3/python_files_io.htm">Python 3 - Files I/O</a></li>
<li><a href="/python3/python_exceptions.htm">Python 3 - Exceptions</a></li>
</ul>
我们现在可以将该脚本加载到 BeautifulSoup 对象中来分析文档树。
Beautiful Soup - Scrape HTML Content
从网站中提取数据的过程称为网络抓取。网页可能包含 URL、电子邮件地址、图像或任何其他内容,我们可以将其存储在文件中或数据库中。手动搜索网站是一个繁琐的过程。有各种网络抓取工具可以实现该过程的自动化。
有时通过使用“robots.txt”文件禁止网络抓取。一些热门的网站提供了 API,以结构化方式访问其数据。不道德的网络抓取可能会导致你的 IP 被封禁。
Python 被广泛用于网络抓取。Python 标准库具有 urllib 包,该包可用于从 HTML 页面中提取数据。由于 urllib 模块已与标准库捆绑在一起,因此不需要安装它。
urllib 包是 Python 编程语言的 HTTP 客户端。当我们想要打开和读取 URL 时,urllib.request 模块非常有用。urllib 包中的其他模块有 −
-
urllib.error 定义了 urllib.request 命令引发的异常和错误。
-
urllib.parse 用于解析 URL。
-
urllib.robotparser 用于解析 robots.txt 文件。
使用 urllib 模块中的 urlopen() 函数从网站读取网页的内容。
import urllib.request
response = urllib.request.urlopen('http://python.org/')
html = response.read()
你也可以为此目的使用 requests 库。使用之前你需要安装它。
pip3 安装 requests
在以下代码中,抓取了 http://www.tutorialspoint.com 的主页 −
from bs4 import BeautifulSoup
import requests
url = "https://www.tutorialspoint.com/index.htm"
req = requests.get(url)
然后用 Beautiful Soup 解析由以上两种方法获得的内容。
Beautiful Soup - Navigating by Tags
任何 HTML 文档片断中最重要的元素之一是标记,它可能包含其他标记/字符串(标记的子标记)。Beautiful Soup 提供了浏览和迭代标记子标记的不同方式。
搜索解析树最简单的方法是按名称搜索标记。
soup.head
soup.head 函数返回 HTML 页面 <head> .. </head> 元素中的内容。
Consider the following HTML page to be scraped:
<html>
<head>
<title>TutorialsPoint</title>
<script>
document.write("Welcome to TutorialsPoint");
</script>
</head>
<body>
<h1>Tutorialspoint Online Library</h1>
<p><b>It's all Free</b></p>
</body>
</html>
以下代码提取 <head> 元素的内容
soup.body
同样,要返回 HTML 页面的正文部分的内容,请使用 soup.body
Example
from bs4 import BeautifulSoup
with open("index.html") as fp:
soup = BeautifulSoup(fp, 'html.parser')
print (soup.body)
Output
<body>
<h1>Tutorialspoint Online Library</h1>
<p><b>It's all Free</b></p>
</body>
您还可以在 <body> 标记中提取特定标记(例如第一个 <h1> 标记)。
soup.p
我们的 HTML 文件包含一个 <p> 标记。我们可以提取此标记的内容
Tag.contents
一个标记对象可以有一个或多个页面元素。标记对象的 contents 属性返回包含在其内所有元素的列表。
让我们在 index.html 文件的 <head> 标记中查找元素。
Tag.children
HTML 脚本中标记的结构是分层的。元素嵌套在另一个元素内部。例如,顶级 <HTML> 标记包含 <HEAD> 和 <BODY> 标记,每个标记可能又包含其他标记。
标记对象具有 children 属性,该属性返回包含所包含的页面元素的列表迭代器对象。
为了演示 children 属性,我们将使用以下 HTML 脚本 (index.html)。在 <body> 部分中,有两个 <ul> 列表元素,一个嵌套在另一个中。换句话说,正文标记具有顶级列表元素,并且每个列表元素在其下方具有另一个列表。
<html>
<head>
<title>TutorialsPoint</title>
</head>
<body>
<h2>Departmentwise Employees</h2>
<ul>
<li>Accounts</li>
<ul>
<li>Anand</li>
<li>Mahesh</li>
</ul>
<li>HR</li>
<ul>
<li>Rani</li>
<li>Ankita</li>
</ul>
</ul>
</body>
</html>
以下 Python 代码给出了顶级 <ul> 标记的所有子元素的列表。
Example
from bs4 import BeautifulSoup
with open("index.html") as fp:
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.ul
print (list(tag.children))
Tag.find_all()
此方法返回与提供的参数标记相匹配的所有标记的内容的结果集。
让我们考虑这个 HTML 页面 (index.html) 来做如下说明 −
<html>
<body>
<h1>Tutorialspoint Online Library</h1>
<p><b>It's all Free</b></p>
<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>
<a class="prog" href="https://www.tutorialspoint.com/cprogramming/index.htm" id="link2">C</a>
<a class="prog" href="https://www.tutorialspoint.com/python/index.htm" id="link3">Python</a>
<a class="prog" href="https://www.tutorialspoint.com/javascript/javascript_overview.htm" id="link4">JavaScript</a>
<a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm" id="link5">C</a>
</body>
</html>
以下代码列出了所有带有 <a> 标记的元素
Example
from bs4 import BeautifulSoup
with open("index.html") as fp:
soup = BeautifulSoup(fp, 'html.parser')
result = soup.find_all("a")
print (result)
Output
[
<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>,
<a class="prog" href="https://www.tutorialspoint.com/cprogramming/index.htm" id="link2">C</a>,
<a class="prog" href="https://www.tutorialspoint.com/python/index.htm" id="link3">Python</a>,
<a class="prog" href="https://www.tutorialspoint.com/javascript/javascript_overview.htm" id="link4">JavaScript</a>,
<a class="prog" href="https://www.tutorialspoint.com/ruby/index.htm" id="link5">C</a>
]
Beautiful Soup - Find Elements by ID
在 HTML 文档中,通常每个元素都分配了一个唯一的 ID。这使得元素的值可以通过前端代码(如 JavaScript function)来提取。
使用 BeautifulSoup,你可以通过给定的元素的 ID 来查找它的内容。可以通过以下两种方法来实现这一点——find() 和 find_all(),以及 select()。
Using find() method
BeautifulSoup 对象的 find() 方法搜索满足给定条件(作为参数)的第一个元素。
让我们为了这个目的使用以下 HTML 脚本(作为 index.html):
<html>
<head>
<title>TutorialsPoint</title>
</head>
<body>
<form>
<input type = 'text' id = 'nm' name = 'name'>
<input type = 'text' id = 'age' name = 'age'>
<input type = 'text' id = 'marks' name = 'marks'>
</form>
</body>
</html>
下面的 Python 代码找到了 id 为 nm 的元素:
Using find_all()
find_all() 方法也接受一个过滤器参数。它返回所有具有给定 id 的元素的列表。在某些 HTML 文档中,通常具有特定 id 的单个元素。因此,使用 find() 来搜索给定的 id 比使用 find_all() 更可取。
Beautiful Soup - Find Elements by Class
CSS(层叠样式表)是设计 HTML 元素外观的工具。CSS 规则控制 HTML 元素的不同方面,如大小、颜色、对齐方式等。应用样式比定义 HTML 元素属性更有效。您可以将样式规则应用于每个 HTML 元素。CSS 类用于将类似的样式应用于 HTML 元素组以获得统一的网页外观,而不是逐个应用样式到每个元素。在 BeautifulSoup 中,可以找到使用 CSS 类设置样式的标签。在本章中,我们将使用以下方法搜索指定 CSS 类的元素:
-
find_all() and find() methods
-
select() and select_one() methods
Class in CSS
CSS 中的一个类是一组属性,用于指定与外观相关的不同特征,例如字体类型、大小和颜色、背景颜色、对齐方式等。声明类时,类的名称前面加点(.)。
.class {
css declarations;
}
CSS 类可以在内联中定义,也可以在需要包含在 HTML 脚本中的单独 css 文件中定义。CSS 类的典型示例如下:
.blue-text {
color: blue;
font-weight: bold;
}
您可以借助以下 BeautifulSoup 方法搜索已定义为特定类样式的 HTML 元素。
出于本章的目的,我们将使用以下 HTML 页面:
<html>
<head>
<title>TutorialsPoint</title>
</head>
<body>
<h2 class="heading">Departmentwise Employees</h2>
<ul>
<li class="mainmenu">Accounts</li>
<ul>
<li class="submenu">Anand</li>
<li class="submenu">Mahesh</li>
</ul>
<li class="mainmenu">HR</li>
<ul>
<li class="submenu">Rani</li>
<li class="submenu">Ankita</li>
</ul>
</ul>
</body>
</html>
Using find() and find_all()
要搜索标签中使用的特定 CSS 类的元素,请按如下使用 Tag 对象的 attrs 属性:
Example
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
obj = soup.find_all(attrs={"class": "mainmenu"})
print (obj)
Output
[<li class="mainmenu">Accounts</li>, <li class="mainmenu">HR</li>]
此结果是具有 mainmenu 类的所有元素的列表
要获取 attrs 属性中提到的任何 CSS 类中元素的列表,请将 find_all() 语句更改为:
obj = soup.find_all(attrs={"class": ["mainmenu", "submenu"]})
这会生成一个列表,其中包含上述任何 CSS 类的所有元素。
[
<li class="mainmenu">Accounts</li>,
<li class="submenu">Anand</li>,
<li class="submenu">Mahesh</li>,
<li class="mainmenu">HR</li>,
<li class="submenu">Rani</li>,
<li class="submenu">Ankita</li>
]
Beautiful Soup - Find Elements by Attribute
find() 和 find_all() 方法都用于根据传递给这些方法的参数找到文档中一个或所有标签。你可以将 attrs 参数传递给这些函数。attrs 的值必须是具有一个或多个标签属性及其值的字典。
为了检查这些方法的行为,我们将使用以下 HTML 文档 (index.html)
<html>
<head>
<title>TutorialsPoint</title>
</head>
<body>
<form>
<input type = 'text' id = 'nm' name = 'name'>
<input type = 'text' id = 'age' name = 'age'>
<input type = 'text' id = 'marks' name = 'marks'>
</form>
</body>
</html>
Using find_all()
下面的程序返回一个具有 input type="text" 属性的所有标签的列表。
Beautiful Soup - Searching the Tree
在本章中,我们将讨论 Beautiful Soup 中用于在不同方向上浏览 HTML 文档树的不同方法 - 上下、左右以及来回。
本章所有示例中,都将使用以下 HTML 字符串 −
html = """
<html><head><title>TutorialsPoint</title></head>
<body>
<p class="title"><b>Online Tutorials Library</b></p>
<p class="story">TutorialsPoint has an excellent collection of tutorials on:
<a href="https://tutorialspoint.com/Python" class="lang" id="link1">Python</a>,
<a href="https://tutorialspoint.com/Java" class="lang" id="link2">Java</a> and
<a href="https://tutorialspoint.com/PHP" class="lang" id="link3">PHP</a>;
Enhance your Programming skills.</p>
<p class="tutorial">...</p>
"""
所需标记的名称可用于导航解析树。例如,soup.head 会为您提取 <head> 元素 −
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
print (soup.head.prettify())
Going down
一个标记可能包含字符串或包含在其内部的其他标记。Tag 对象的 .contents 属性会返回属于它的所有子元素的列表。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.head
print (list(tag.children))
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.body
print (list(tag.children))
Output
['\n', <p class="title"><b>Online Tutorials Library</b></p>, '\n',
<p class="story">TutorialsPoint has an excellent collection of tutorials on:
<a class="lang" href="https://tutorialspoint.com/Python" id="link1">Python</a>,
<a class="lang" href="https://tutorialspoint.com/Java" id="link2">Java</a> and
<a class="lang" href="https://tutorialspoint.com/PHP" id="link3">PHP</a>;
Enhance your Programming skills.</p>, '\n', <p class="tutorial">...</p>, '\n']
不必将其获取为列表,也可以使用 .children 生成器对标记的子元素进行迭代 −
Output
<p class="title"><b>Online Tutorials Library</b></p>
<p class="story">TutorialsPoint has an excellent collection of tutorials on:
<a class="lang" href="https://tutorialspoint.com/Python" id="link1">Python</a>,
<a class="lang" href="https://tutorialspoint.com/Java" id="link2">Java</a> and
<a class="lang" href="https://tutorialspoint.com/PHP" id="link3">PHP</a>;
Enhance your Programming skills.</p>
<p class="tutorial">...</p>
.descendents
BeautifulSoup对象位于所有标记层次结构的顶部。因此其 .descendents 属性包括 HTML 字符串中的所有元素。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
print (soup.descendants)
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.head
for element in tag.descendants:
print (element)
Output
<title>TutorialsPoint</title>
TutorialsPoint
head 标记包含一个 title 标记,该标记又包含一个 NavigableString 对象 TutorialsPoint。<head>标记只有一个子元素,但具有两个后代:<title>标记和<title>标记的子元素。不过,BeautifulSoup 对象仅有一个直接子元素(<html>标记),但具有许多后代。
Going Up
就像使用子元素和后代属性导航文档的下游信息一样,BeautifulSoup 提供了 .parent和 .parent 属性来导航标记的上游信息
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.title
print (tag.parent)
Output
<head><title>TutorialsPoint</title></head>
由于 title 标记包含一个字符串(NavigableString),因此字符串的父级就是 title 标记自身。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.title
string = tag.string
print (string.parent)
.parents
可以使用 .parents 遍历元素的所有父元素。此示例使用 .parents 从位于文档深处的 <a> 标记遍历到文档的顶部。在以下代码中,我们跟踪示例 HTML 字符串中第一个 <a> 的父元素。
Sideways
显示在相同缩进级别的 HTML 标记称为兄弟标记。考虑以下 HTML 代码段
<p>
<b>
Hello
</b>
<i>
Python
</i>
</p>
在外部 <p> 标记中,我们具有处于同一缩进级别的 <b> 和 <i> 标记,因此它们称为兄弟标记。BeautifulSoup 使得在相同级别的标记之间导航成为可能。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p><b>Hello</b><i>Python</i></p>", 'html.parser')
tag1 = soup.b
print ("next:",tag1.next_sibling)
tag2 = soup.i
print ("previous:",tag2.previous_sibling)
Output
next: <i>Python</i>
previous: <b>Hello</b>
由于 <b> 标记左侧没有兄弟标记,并且 <i> 标记右侧没有兄弟标记,因此在两种情况下都返回 Nobe。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p><b>Hello</b><i>Python</i></p>", 'html.parser')
tag1 = soup.b
print ("next:",tag1.previous_sibling)
tag2 = soup.i
print ("previous:",tag2.next_sibling)
.next_siblings and .previous_siblings
如果某个标记的右侧或左侧有两个或多个兄弟标记,则可以使用 .next_siblings 和 .previous_siblings 属性分别导航它们。它们都返回生成器对象,因此可以使用 for 循环进行迭代。
让我们为此目的使用以下 HTML 片段:
<p>
<b>
Excellent
</b>
<i>
Python
</i>
<u>
Tutorial
</u>
</p>
使用以下代码来遍历后面的和前面的兄弟标签。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p><b>Excellent</b><i>Python</i><u>Tutorial</u></p>", 'html.parser')
tag1 = soup.b
print ("next siblings:")
for tag in tag1.next_siblings:
print (tag)
print ("previous siblings:")
tag2 = soup.u
for tag in tag2.previous_siblings:
print (tag)
Back and forth
在Beautiful Soup中,next_element属性返回解析树中的下一个字符串或标记。另一方面,previous_element属性返回解析树中前面的字符串或标记。有时,next_element和previous_element属性的返回值与next_sibling和previous_sibling属性类似。
Example
html = """
<html><head><title>TutorialsPoint</title></head>
<body>
<p class="title"><b>Online Tutorials Library</b></p>
<p class="story">TutorialsPoint has an excellent collection of tutorials on:
<a href="https://tutorialspoint.com/Python" class="lang" id="link1">Python</a>,
<a href="https://tutorialspoint.com/Java" class="lang" id="link2">Java</a> and
<a href="https://tutorialspoint.com/PHP" class="lang" id="link3">PHP</a>;
Enhance your Programming skills.</p>
<p class="tutorial">...</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.find("a", id="link3")
print (tag.next_element)
tag = soup.find("a", id="link1")
print (tag.previous_element)
Output
PHP
TutorialsPoint has an excellent collection of tutorials on:
id=“link3”的<a>标签之后的next_element是字符串PHP。类似地,previous_element返回id=“link1”的<a>标签之前的字符串。
.next_elements and .previous_elements
Tag对象的这些属性分别返回生成器,其中是它后面和前面的所有标签和字符串。
Next elements example
tag = soup.find("a", id="link1")
for element in tag.next_elements:
print (element)
Output
Python
,
<a class="lang" href="https://tutorialspoint.com/Java" id="link2">Java</a>
Java
and
<a class="lang" href="https://tutorialspoint.com/PHP" id="link3">PHP</a>
PHP
;
Enhance your Programming skills.
<p class="tutorial">...</p>
...
Previous elements example
tag = soup.find("body")
for element in tag.previous_elements:
print (element)
Output
<html><head><title>TutorialsPoint</title></head>
Beautiful Soup - Modifying the Tree
Beautiful Soup 库的一个强大功能是可以操作解析后的 HTML 或 XML 文档并修改其内容。
Beautiful Soup 库具有不同的函数来执行以下操作 -
-
向文档的现有标签添加内容或新标签
-
在现有标签或字符串之前或之后插入内容
-
清除已存在标签的内容
-
修改标签元素的内容
Add content
您可以通过在 Tag 对象上使用 append() 方法向现有标签的内容添加内容。它像 Python 的列表对象的 append() 方法一样工作。
在以下示例中,HTML 脚本有一个 <p> 标签。使用 append() 附加附加文本。
Example
from bs4 import BeautifulSoup
markup = '<p>Hello</p>'
soup = BeautifulSoup(markup, 'html.parser')
print (soup)
tag = soup.p
tag.append(" World")
print (soup)
Output
<p>Hello</p>
<p>Hello World</p>
使用 append() 方法,您可以在现有标签的末尾添加新标签。首先使用 new_tag() 方法创建一个新 Tag 对象,然后将其传递给 append() 方法。
Example
from bs4 import BeautifulSoup, Tag
markup = '<b>Hello</b>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.b
tag1 = soup.new_tag('i')
tag1.string = 'World'
tag.append(tag1)
print (soup.prettify())
Example
from bs4 import BeautifulSoup, NavigableString
markup = '<b>Hello</b>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.b
new_string = NavigableString(" World")
tag.append(new_string)
print (soup.prettify())
Insert Contents
您不必在末尾添加新元素,而是可以使用 insert() 方法在 Tag 元素的子项列表中给定位置添加元素。Beautiful Soup 中的 insert() 方法的行为类似于 Python 列表对象上的 insert()。
在以下示例中,新字符串被添加到 <b> 标记,位置为 1。结果解析的文档显示结果。
Example
from bs4 import BeautifulSoup, NavigableString
markup = '<b>Excellent </b><u>from TutorialsPoint</u>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.b
tag.insert(1, "Tutorial ")
print (soup.prettify())
Output
<b>
Excellent
Tutorial
</b>
<u>
from TutorialsPoint
</u>
Beautiful Soup 还有 insert_before() 和 insert_after() 方法。它们的各自目的是在指定标记对象之前或之后插入标记或字符串。以下代码显示字符 "Python Tutorial" 添加到了 <b> 标记之后。
Example
from bs4 import BeautifulSoup, NavigableString
markup = '<b>Excellent </b><u>from TutorialsPoint</u>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.b
tag.insert_after("Python Tutorial")
print (soup.prettify())
Clear the Contents
Beautiful Soup 提供多种方法,从文档树中删除元素的内容。这些方法各自具有独特的功能。
clear() 方法最为直接。它仅仅删除指定标记元素的内容。以下示例显示了它的使用情况。
Example
from bs4 import BeautifulSoup, NavigableString
markup = '<b>Excellent </b><u>from TutorialsPoint</u>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.find('u')
tag.clear()
print (soup.prettify())
Output
<b>
Excellent
</b>
<u>
</u>
可以看到, clear() 方法删除了内容,保持标记完好。
对于以下示例,我们解析以下 HTML 文档,对所有标记调用 clear() 方法。
<html>
<body>
<p> The quick, brown fox jumps over a lazy dog.</p>
<p> DJs flock by when MTV ax quiz prog.</p>
<p> Junk MTV quiz graced by fox whelps.</p>
<p> Bawds jog, flick quartz, vex nymphs./p>
</body>
</html>
使用 clear() 方法的 Python 代码如下
Example
from bs4 import BeautifulSoup
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
tags = soup.find_all()
for tag in tags:
tag.clear()
print (soup.prettify())
Example
from bs4 import BeautifulSoup
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
tags = soup.find_all()
for tag in tags:
obj = tag.extract()
print ("Extracted:",obj)
print (soup)
Output
Extracted: <html>
<body>
<p> The quick, brown fox jumps over a lazy dog.</p>
<p> DJs flock by when MTV ax quiz prog.</p>
<p> Junk MTV quiz graced by fox whelps.</p>
<p> Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
Extracted: <body>
<p> The quick, brown fox jumps over a lazy dog.</p>
<p> DJs flock by when MTV ax quiz prog.</p>
<p> Junk MTV quiz graced by fox whelps.</p>
<p> Bawds jog, flick quartz, vex nymphs.</p>
</body>
Extracted: <p> The quick, brown fox jumps over a lazy dog.</p>
Extracted: <p> DJs flock by when MTV ax quiz prog.</p>
Extracted: <p> Junk MTV quiz graced by fox whelps.</p>
Extracted: <p> Bawds jog, flick quartz, vex nymphs.</p>
你可以提取标记或字符串。以下示例显示提取一个标记。
Example
html = '''
<ol id="HR">
<li>Rani</li>
<li>Ankita</li>
</ol>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
obj=soup.find('ol')
obj.find_next().extract()
print (soup)
Modify the Contents
我们将着眼于 replace_with() 方法,该方法允许替换标记的内容。
正如 Python 字符串一样(不可变),NavigableString 也不能就地修改。但是,使用 replace_with() 可以将标记的内部字符串替换为另一个字符串。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup("<h2 id='message'>Hello, Tutorialspoint!</h2>",'html.parser')
tag = soup.h2
tag.string.replace_with("OnLine Tutorials Library")
print (tag.string)
Output
OnLine Tutorials Library
这里有另一个示例,演示了 replace_with() 的用法。如果将 BeautifulSoup 对象作为参数传递给某些函数,例如 replace_with(),则可以合并两个已解析的文档。
Example
from bs4 import BeautifulSoup
obj1 = BeautifulSoup("<book><title>Python</title></book>", features="xml")
obj2 = BeautifulSoup("<b>Beautiful Soup parser</b>", "lxml")
obj2.find('b').replace_with(obj1)
print (obj2)
Output
<html><body><book><title>Python</title></book></body></html>
wrap() 方法用你指定的标记包装一个元素。它返回新的包装器。
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p>Hello Python</p>", 'html.parser')
tag = soup.p
newtag = soup.new_tag('b')
tag.string.wrap(newtag)
print (soup)
Beautiful Soup - Parsing a Section of a Document
假设你要使用 Beautiful Soup 仅查看文档的 <a> 标签。通常,你将解析树,并使用 find_all() 方法,并以所需标签作为参数。
soup = BeautifulSoup(fp, "html.parser")
tags = soup.find_all('a')
但是那将耗时,并且无用地占用更多内存。可创建一个 SoupStrainer 类的对象,并将其用作 BeautifulSoup 构造函数中 parse_only 参数的值。
SoupStrainer 告诉 BeautifulSoup 提取哪些部分,而解析树仅包含这些元素。若将所需信息缩小到 HTML 的特定部分,这将加速你的搜索结果。
product = SoupStrainer('div',{'id': 'products_list'})
soup = BeautifulSoup(html,parse_only=product)
上述代码行仅从产品网站中解析标题,它可能位于某个标签字段中。
类似上述情况,我们可以使用其他 soupStrainer 对象来解析 HTML 标签中的特定信息。以下是一些示例:
Example
from bs4 import BeautifulSoup, SoupStrainer
#Only "a" tags
only_a_tags = SoupStrainer("a")
#Will parse only the below mentioned "ids".
parse_only = SoupStrainer(id=["first", "third", "my_unique_id"])
soup = BeautifulSoup(my_document, "html.parser", parse_only=parse_only)
#parse only where string length is less than 10
def is_short_string(string):
return len(string) < 10
only_short_strings = SoupStrainer(string=is_short_string)
SoupStrainer 类的参数与通过搜索树的典型方法一致:name、attrs、text 和 **kwargs。
请注意,如果你使用 html5lib 解析器,此特性将不起作用,因为在这种情况下无论如何都会解析整个文档。因此,你应该使用内建的 html.parser 或 lxml 解析器。
你还可以将 SoupStrainer 传递到通过搜索树涵盖的任何方法中。
from bs4 import SoupStrainer
a_tags = SoupStrainer("a")
soup = BeautifulSoup(html_doc, 'html.parser')
soup.find_all(a_tags)
Beautiful Soup - Find all Children of an Element
HTML 脚本中标记的结构是分层的。元素一个嵌套在另一个里面。例如,最顶层的 <HTML> 标记包含 <HEAD> 和 <BODY> 标记,每个都可以包含其他的标记。最顶层元素被称为父元素。嵌套在父元素内的元素是其子元素。借助 Beautiful Soup,我们可以找到父元素的所有子元素。在本章中,我们将找出如何获取 HTML 元素的子元素。
BeautifulSoup 类中有两个配置,用于获取子元素。
-
The .children property
-
The findChildren() method
本章中的示例使用了以下 HTML 脚本 (index.html)
<html>
<head>
<title>TutorialsPoint</title>
</head>
<body>
<h2>Departmentwise Employees</h2>
<ul id="dept">
<li>Accounts</li>
<ul id='acc'>
<li>Anand</li>
<li>Mahesh</li>
</ul>
<li>HR</li>
<ul id="HR">
<li>Rani</li>
<li>Ankita</li>
</ul>
</ul>
</body>
</html>
Using .children property
Tag 对象的 .children 属性以递归方式返回所有子元素的生成器。
以下 Python 代码给出了最顶层的 <ul> 标记的所有子元素的列表。我们首先获取与 <ul> 标记相对应的 Tag 元素,然后读取其 .children 属性
Example
from bs4 import BeautifulSoup
with open("index.html") as fp:
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.ul
print (list(tag.children))
Using findChildren() method
findChildren() 方法提供了一个更全面的选择。它返回所有顶层标记下的所有子元素。
在 index.html 文档中,我们有两个嵌套的无序列表。最顶层的 <ul> 元素的 id = "dept",而两个封闭的列表的 id 分别为 = "acc" 和 "HR"。
在以下示例中,我们首先实例化指向最顶层 <ul> 元素的 Tag 对象并提取其下的子元素列表。
from bs4 import BeautifulSoup
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.find("ul", {"id": "dept"})
children = tag.findChildren()
for child in children:
print(child)
请注意,结果集以递归方式包含元素下的子元素。因此,在以下输出中,你将找到整个内部列表,后跟其中的各个元素。
<li>Accounts</li>
<ul id="acc">
<li>Anand</li>
<li>Mahesh</li>
</ul>
<li>Anand</li>
<li>Mahesh</li>
<li>HR</li>
<ul id="HR">
<li>Rani</li>
<li>Ankita</li>
</ul>
<li>Rani</li>
<li>Ankita</li>
让我们提取 id='acc' 的内部 <ul> 元素下的子元素。代码如下 -
Beautiful Soup - Find Element using CSS Selectors
在 Beautiful Soup 库中,select() 方法是用于抓取 HTML/XML 文档的重要工具。类似于 find() 和其他 find_*() 方法,select() 方法还有助于查找符合给定条件的元素。但是,find*() 方法根据标记名称及其属性搜索 PageElements,select() 方法根据给定的 CSS 选择器搜索文档树。
Beautiful Soup 还具有 select_one() 方法。select() 和 select_one() 之间的区别在于,select() 返回属于 PageElement 并由 CSS 选择器表征的所有元素的 ResultSet;而 select_one() 返回满足基于 CSS 选择器选择标准的元素的第一个出现。
在 Beautiful Soup 4.7 版本之前,select() 方法过去只能支持通用的 CSS 选择器。从 4.7 版本开始,Beautiful Soup 与 Soup Sieve CSS 选择器库集成在一起。因此,现在可以使用更多选择器。在 4.12 版本中,除了现有的便利方法 select() 和 select_one() 之外,还添加了 .css 属性。select() 方法的参数如下 −
select(selector, limit, **kwargs)
selector − 包含 CSS 选择器的字符串。
limit − 找到此数量的结果后,停止查找。
kwargs − 要传递的关键字参数。
如果 limit 参数设置为 1,则它等价于 select_one() 方法。虽然 select() 方法返回一个 Tag 对象的 ResultSet,但 select_one() 方法返回一个单个 Tag 对象。
Soup Sieve Library
Soup Sieve 是一款 CSS 选择器库。它已与 Beautiful Soup 4 集成,因此可随 Beautiful Soup 包一起安装。它提供使用现代 CSS 选择器选择、匹配和筛选文档树标记的能力。Soup Sieve 目前实现了 CSS 1 级规范到 CSS 4 级的大部分 CSS 选择器,但除了一些尚未实现的例外情况。
Soup Sieve 库具有不同类型的 CSS 选择器。基本的 CSS 选择器为 −
Example
from bs4 import BeautifulSoup, NavigableString
markup = '''
<div id="Languages">
<p>Java</p> <p>Python</p> <p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
tags = soup.select('div')
print (tags)
Example
from bs4 import BeautifulSoup
html = '''
<form>
<input type = 'text' id = 'nm' name = 'name'>
<input type = 'text' id = 'age' name = 'age'>
<input type = 'text' id = 'marks' name = 'marks'>
</form>
'''
soup = BeautifulSoup(html, 'html.parser')
obj = soup.select("#nm")
print (obj)
Example
from bs4 import BeautifulSoup, NavigableString
markup = '''
<div id="Languages">
<p>Java</p> <p>Python</p> <p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
tags = soup.select('div')
print (tags)
Example
from bs4 import BeautifulSoup
html = '''
<h1>Tutorialspoint Online Library</h1>
<p><b>It's all Free</b></p>
<a class="prog" href="https://www.tutorialspoint.com/java/java_overview.htm" id="link1">Java</a>
<a class="prog" href="https://www.tutorialspoint.com/cprogramming/index.htm" id="link2">C</a>
'''
soup = BeautifulSoup(html, 'html5lib')
print(soup.select('[href]'))
Pseudo Classes
CSS 规范定义了多个伪 CSS 类。伪类是添加到选择器中的关键字,用于定义所选元素的特殊状态。它会对现有元素添加效果。例如,:link 选择尚未访问的链接(带 href 属性的每个 <a> 和 <area> 元素)。
nth-of-type 和 nth-child 伪类选择器被广泛使用。
:nth-of-type()
:nth-of-type() 选择器根据元素在同级元素组中的位置匹配指定类型的元素。关键字 even 和 odd 将分别从子同级元素组中选择元素。
在以下示例中,选择了 <p> 类型的第二个元素。
Example
from bs4 import BeautifulSoup
html = '''
<p id="0"></p>
<p id="1"></p>
<span id="2"></span>
<span id="3"></span>
'''
soup = BeautifulSoup(html, 'html5lib')
print(soup.select('p:nth-of-type(2)'))
Beautiful Soup - Find all Comments
计算机代码中加入注释被认为是一种良好的编程实践。注释有助于理解程序的逻辑,同时也可以作为文档。和用 C、Java、Python 等语言编写的程序一样,您还可以在 HTML 和 XML 脚本中添加注释。BeautifulSoup API 可以帮助识别 HTML 文档中的所有注释。
在 HTML 和 XML 中,注释文本写在 <!-- 和 -→ 标签之间。
<!-- Comment Text -->
BeutifulSoup 包,其内部名称为 bs4,将注释定义为一个重要的对象。注释对象是一种特殊的 NavigableString 对象类型。因此,任何在 <!-- 和 -→ 之间找到的标签的 string 属性都被认为是注释。
Example
from bs4 import BeautifulSoup
markup = "<b><!--This is a comment text in HTML--></b>"
soup = BeautifulSoup(markup, 'html.parser')
comment = soup.b.string
print (comment, type(comment))
Output
This is a comment text in HTML <class 'bs4.element.Comment'>
要搜索 HTML 文档中注释的所有出现,我们应该使用 find_all() 方法。不带任何参数,find_all() 返回解析的 HTML 文档中的所有元素。可以将关键字参数 'string' 传递到 find_all() 方法。我们将为此分配函数 iscomment() 的返回值。
comments = soup.find_all(string=iscomment)
iscomment() 函数在 isinstance() 函数的帮助下验证标签中的文本是否是注释对象。
def iscomment(elem):
return isinstance(elem, Comment)
comments 变量将存储给定 HTML 文档中的所有注释文本出现。我们将在示例代码中使用以下 index.html 文件 -
<html>
<head>
<!-- Title of document -->
<title>TutorialsPoint</title>
</head>
<body>
<!-- Page heading -->
<h2>Departmentwise Employees</h2>
<!-- top level list-->
<ul id="dept">
<li>Accounts</li>
<ul id='acc'>
<!-- first inner list -->
<li>Anand</li>
<li>Mahesh</li>
</ul>
<li>HR</li>
<ul id="HR">
<!-- second inner list -->
<li>Rani</li>
<li>Ankita</li>
</ul>
</ul>
</body>
</html>
以下 Python 程序刮取了上述 HTML 文档,并找到了其中的所有注释。
Example
from bs4 import BeautifulSoup, Comment
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
def iscomment(elem):
return isinstance(elem, Comment)
comments = soup.find_all(string=iscomment)
print (comments)
Beautiful Soup - Scraping List from HTML
网页通常以有序或无序列表的形式包含信息。使用 Beautiful Soup,我们可以轻松提取 HTML 列表元素,将数据放入 Python 对象中以存储在数据库中以供进一步分析。在本章中,我们将使用 find() 和 select() 方法从 HTML 文档中抓取列表数据。
最简单的搜索解析树的方法是按其名称搜索标签。soup.<tag> 提取给定标签的内容。
HTML 提供 <ol> 和 <ul> 标签来编写有序和无序列表。和任何其他标签一样,我们可以提取这些标签的内容。
我们将使用以下 HTML 文档 -
<html>
<body>
<h2>Departmentwise Employees</h2>
<ul id="dept">
<li>Accounts</li>
<ul id='acc'>
<li>Anand</li>
<li>Mahesh</li>
</ul>
<li>HR</li>
<ol id="HR">
<li>Rani</li>
<li>Ankita</li>
</ol>
</ul>
</body>
</html>
Scraping lists by Tag
在上方的 HTML 文档中,我们有一个顶层 <ul> 列表,其中有另一个 <ul> 标签和另一个 <ol> 标签。我们首先在 soup 对象中解析文档,并在 soup.ul Tag 对象中检索第一个 <ul> 的内容。
Example
from bs4 import BeautifulSoup
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
lst=soup.ul
print (lst)
Using select() method
select() 方法本质上用于使用 CSS 选择器获取数据。但是,你也可以向其传递一个标记。在此处,我们可以将 ol 标记传递给 select() 方法。该 select_one() 方法也可以使用。它获取给定标记的第一次出现。
Using find_all() method
find() 和 fin_all() 方法更为全面。你可以将各种类型的过滤器(例如标记、属性或字符串等)传递给这些方法。在这种情况下,我们要获取列表标记的内容。
在以下代码中,find_all() 方法返回 <ul> 标记中所有元素的列表。
Example
from bs4 import BeautifulSoup
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
lst=soup.find_all("ul")
print (lst)
我们可以通过包含 attrs 参数来优化搜索过滤器。在我们的 HTML 文档中,即 <ul> 和 <ol> 标记中,我们指定了它们各自的 id 属性。因此,让我们获取 id="acc" 的 <ul> 元素的内容。
Example
from bs4 import BeautifulSoup
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
lst=soup.find_all("ul", {"id":"acc"})
print (lst)
Output
[<ul id="acc">
<li>Anand</li>
<li>Mahesh</li>
</ul>]
这是另一个示例。我们收集所有具有 <li> 标记的元素,其中内文以“A”开头。该 find_all() 方法采用一个关键字参数 string 。如果 startingwith() 函数返回 True,则它取文本的值。
Beautiful Soup - Scraping Paragraphs from HTML
HTML 文档中经常出现的标记之一是标记段落文本的 <p> 标记。使用 Beautiful Soup,你可以轻松地从解析的文档树中提取段落。在本章中,我们将讨论借助 BeautifulSoup 库抓取段落的以下方法。
-
用 <p> 标记抓取 HTML 段落
-
用 find_all() 方法抓取 HTML 段落
-
用 select() 方法抓取 HTML 段落
我们将在这些练习中使用以下 HTML 文档:
<html>
<head>
<title>BeautifulSoup - Scraping Paragraph</title>
</head>
<body>
<p id='para1'>The quick, brown fox jumps over a lazy dog.</p>
<h2>Hello</h2>
<p>DJs flock by when MTV ax quiz prog.</p>
<p>Junk MTV quiz graced by fox whelps.</p>
<p>Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
Scraping by <p> tag
搜索解析树的最简单方法是按名称搜索标签。因此,表达式 soup.p 指向 scouped 文档中的第一个 <p> 标签。
para = soup.p
若要获取所有后续 <p> 标签,您可以运行循环,直到所有 <p> 标签都被 soup 对象用尽。以下程序显示所有段落标签的美化输出。
Using find_all() method
find_all() 方法更为全面。您可以将各种类型的过滤器(例如,标签、属性或字符串等)传递给此方法。在本例中,我们希望获取 <p> 标签的内容。
在以下代码中,find_all() 方法返回 <p> 标签中所有元素的列表。
Example
from bs4 import BeautifulSoup
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
paras = soup.find_all('p')
for para in paras:
print (para.prettify())
Output
<p>
The quick, brown fox jumps over a lazy dog.
</p>
<p>
DJs flock by when MTV ax quiz prog.
</p>
<p>
Junk MTV quiz graced by fox whelps.
</p>
<p>
Bawds jog, flick quartz, vex nymphs.
</p>
我们可以使用另一种方法来查找所有 <p> 标签。首先,使用 find_all() 获取所有标签的列表,并检查每个标签的 Tag.name 是否等于 ='p'。
Example
from bs4 import BeautifulSoup
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
tags = soup.find_all()
paras = [tag.contents for tag in tags if tag.name=='p']
print (paras)
find_all() 方法还具有 attrs 参数。当您要提取具有特定属性的 <p> 标签时,此参数很有用。例如,在给定的文档中,第一个 <p> 元素的 id='para1'。若要获取它,我们需要修改标签对象,如下所示:
paras = soup.find_all('p', attrs={'id':'para1'})
Using select() method
select() 方法本质上用于使用 CSS 选择器获取数据。但是,您还可以向其传递一个标签。在这里,我们可以将 <p> 标签传递给 select() 方法。select_one() 方法也可用。它获取 <p> 标签的第一个匹配项。
Example
from bs4 import BeautifulSoup
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
paras = soup.select('p')
print (paras)
Output
[
<p>The quick, brown fox jumps over a lazy dog.</p>,
<p>DJs flock by when MTV ax quiz prog.</p>,
<p>Junk MTV quiz graced by fox whelps.</p>,
<p>Bawds jog, flick quartz, vex nymphs.</p>
]
若要筛选具有特定 id 的 <p> 标签,请使用如下 for 循环:
BeautifulSoup - Scraping Link from HTML
在从网站资源中抓取和分析内容时,通常需要提取页面包含的所有链接。在本节中,我们将会了解如何从 HTML 文档中提取链接。
HTML 有锚标记 <a> 用于插入超链接。锚标记的 href 属性允许你建立链接。此属性使用以下语法:
<a href=="web page URL">hypertext</a>
利用 find_all() 方法,我们可以在文档中收集所有锚标记,然后打印每个锚标记的 href 属性值。
在下面的示例中,我们提取 Google 主页上找到的所有链接。我们使用 requests 库来收集 https://google.com 的 HTML 内容,将其解析为 soup 对象,然后收集所有 <a> 标记。最后,我们打印 href 属性。
Example
from bs4 import BeautifulSoup
import requests
url = "https://www.google.com/"
req = requests.get(url)
soup = BeautifulSoup(req.content, "html.parser")
tags = soup.find_all('a')
links = [tag['href'] for tag in tags]
for link in links:
print (link)
运行上述程序后的部分输出如下:
Output
https://www.google.co.in/imghp?hl=en&tab=wi
https://maps.google.co.in/maps?hl=en&tab=wl
https://play.google.com/?hl=en&tab=w8
https://www.youtube.com/?tab=w1
https://news.google.com/?tab=wn
https://mail.google.com/mail/?tab=wm
https://drive.google.com/?tab=wo
https://www.google.co.in/intl/en/about/products?tab=wh
http://www.google.co.in/history/optout?hl=en
/preferences?hl=en
https://accounts.google.com/ServiceLogin?hl=en&passive=true&continue=https://www.google.com/&ec=GAZAAQ
/advanced_search?hl=en-IN&authuser=0
https://www.google.com/url?q=https://io.google/2023/%3Futm_source%3Dgoogle-hpp%26utm_medium%3Dembedded_marketing%26utm_campaign%3Dhpp_watch_live%26utm_content%3D&source=hpp&id=19035434&ct=3&usg=AOvVaw0qzqTkP5AEv87NM-MUDd_u&sa=X&ved=0ahUKEwiPzpjku-z-AhU1qJUCHVmqDJoQ8IcBCAU
但是,HTML 文档中可能包含有不同协议方案的超链接,例如 mailto: 协议用于链接到电子邮件 ID,tel: 方案用于链接到电话号码,或带有 file:// URL 方案链接到本地文件。在这种情况下,如果我们有兴趣提取以:https:// 方案开头的链接,则可以通过以下示例来实现。我们有一个由不同类型的超链接组成的 HTML 文档,其中仅提取以 https:// 开头的链接。
html = '''
<p><a href="https://www.tutorialspoint.com">Web page link </a></p>
<p><a href="https://www.example.com">Web page link </a></p>
<p><a href="mailto:nowhere@mozilla.org">Email link</a></p>
<p><a href="tel:+4733378901">Telephone link</a></p>
'''
from bs4 import BeautifulSoup
import requests
soup = BeautifulSoup(html, "html.parser")
tags = soup.find_all('a')
links = [tag['href'] for tag in tags]
for link in links:
if link.startswith("https"):
print (link)
Beautiful Soup - Get all HTML Tags
HTML 中的标签类似于 Python 或 Java 等传统编程语言中的关键字。标签具有预定义的行为,浏览器根据该行为来呈现其内容。通过 Beautiful Soup,可以收集给定 HTML 文档中的所有标签。
获得标签列表的最简单方法是将网页解析为 Soup 对象,并无参数地调用 find_all() 方法。它返回一个列表生成器,向我们提供所有标签的列表。
让我们提取 Google 首页中的所有标签列表。
Example
from bs4 import BeautifulSoup
import requests
url = "https://www.google.com/"
req = requests.get(url)
soup = BeautifulSoup(req.content, "html.parser")
tags = soup.find_all()
print ([tag.name for tag in tags])
Output
['html', 'head', 'meta', 'meta', 'title', 'script', 'style', 'style', 'script', 'body', 'script', 'div', 'div', 'nobr', 'b', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'u', 'div', 'nobr', 'span', 'span', 'span', 'a', 'a', 'a', 'div', 'div', 'center', 'br', 'div', 'img', 'br', 'br', 'form', 'table', 'tr', 'td', 'td', 'input', 'input', 'input', 'input', 'input', 'div', 'input', 'br', 'span', 'span', 'input', 'span', 'span', 'input', 'script', 'input', 'td', 'a', 'input', 'script', 'div', 'div', 'br', 'div', 'style', 'div', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'span', 'div', 'div', 'a', 'a', 'a', 'a', 'p', 'a', 'a', 'script', 'script', 'script']
当然,你可能会获得这样一个列表,其中某个特定标签可能出现多次。要获得唯一标签的列表(避免重复),请从标签对象列表构建一个集合。
将以上代码中的 print 语句更改为
Output
{'body', 'head', 'p', 'a', 'meta', 'tr', 'nobr', 'script', 'br', 'img', 'b', 'form', 'center', 'span', 'div', 'input', 'u', 'title', 'style', 'td', 'table', 'html'}
若要获取与它们关联的文本的标签,请检查字符串属性并打印(如果它不是 None)
tags = soup.find_all()
for tag in tags:
if tag.string is not None:
print (tag.name, tag.string)
可能存在一些没有文本但具有一个或多个属性的单例标签,如 <img> 标签。以下循环构造出列出此类标签的列表。
在以下代码中,HTML 字符串不是一个完整的 HTML 文档(换句话说,没有给定 <html> 和 <body> 标签)。但是,html5lib 和 lxml 解析器在解析文档树时会自动添加这些标签。因此,当我们提取标签列表时,还会看到附加的标签。
Beautiful Soup - Get Text Inside Tag
HTML 中有两种标签类型。许多标签成开闭对出现。具有对应闭合 </html> 标签的顶级 <html> 标签就是主要示例。其他示例包括 <body> 和 </body>、<p> 和 </p>、<h1> 和 </h1> 等。其他标签是自闭合标签,例如 <img> 和 <a>。自闭合标签没有文本,而带有开闭符号的大多数标签(例如 <b>Hello</b>)都有文本。在本章中,我们将了解如何借助 Beautiful Soup 库获取此类标签内部的文本部分。
Beautiful Soup 中有不止一种方法/属性,我们可以使用它们获取与标签对象关联的文本。
Sr.No |
Methods & Description |
1 |
*text 属性*获取 PageElement 的所有子字符串,如果指定,则使用分隔符连接。 |
2 |
*string 属性*从子元素到字符串的便利属性。 |
3 |
*strings 属性*产生当前 PageElement 下所有子对象的字符串部分。 |
4 |
*stripped_strings 属性*与 strings 属性相同,但剔除了换行符和空格。 |
5 |
*get_text() 方法*返回此 PageElement 的所有子字符串,如果指定了分隔符,则使用分隔符连接这些子字符串。 |
考虑以下 HTML 文档 −
<div id="outer">
<div id="inner">
<p>Hello<b>World</b></p>
<img src='logo.jpg'>
</div>
</div>
如果我们检索解析后文档树中每个标签的 stripped_string 属性,我们将发现两个 div 标签和 p 标签具有两个 NavigableString 对象 Hello 和 World。<b> 标签嵌入 world 字符串,而 <img> 没有任何文本部分。
以下示例从给定 HTML 文档中每个标签中获取文本 −
Example
html = """
<div id="outer">
<div id="inner">
<p>Hello<b>World</b></p>
<img src='logo.jpg'>
</div>
</div>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
for tag in soup.find_all():
print ("Tag: {} attributes: {} ".format(tag.name, tag.attrs))
for txt in tag.stripped_strings:
print (txt)
print()
Beautiful Soup - Find all Headings
在本节中,我们将探讨如何使用 BeautifulSoup 来查找 HTML 文档中的所有标题元素。HTML 定义了从 H1 到 H6 的六种标题样式,每种样式的字体大小递减。不同的页面章节(如:主标题、节标题、主题等)使用合适的标签。让我们采用两种不同的方式使用 find_all() 方法来提取 HTML 文档中的所有标题元素。
我们在该章节的代码示例中将使用以下 HTML 脚本(保存为 index.html) -
<html>
<head>
<title>BeautifulSoup - Scraping Headings</title>
</head>
<body>
<h2>Scraping Headings</h2>
<b>The quick, brown fox jumps over a lazy dog.</b>
<h3>Paragraph Heading</h3>
<p>DJs flock by when MTV ax quiz prog.</p>
<h3>List heading</h3>
<ul>
<li>Junk MTV quiz graced by fox whelps.</li>
<li>Bawds jog, flick quartz, vex nymphs.</li>
</ul>
</body>
</html>
Example 1
在该方法中,我们收集解析树中的所有标签,并检查每个标签的名称是否位于所有标题标签的列表中。
from bs4 import BeautifulSoup
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
headings = ['h1','h2','h3', 'h4', 'h5', 'h6']
tags = soup.find_all()
heads = [(tag.name, tag.contents[0]) for tag in tags if tag.name in headings]
print (heads)
此处,headings 是所有标题样式 h1 到 h6 的列表。如果标签的名称是其中任何一个,则标签及其内容将收集在名为 heads 的列表中。
Example 2
你可以在 find_all() 方法中传递正则表达式。请看以下正则表达式。
re.compile('^h[1-6]$')
该正则表达式查找以 h 开头、h 后面有一个数字,然后数字后结尾的所有标签。让我们将其用作下面代码中 find_all() 方法的参数 -
from bs4 import BeautifulSoup
import re
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
tags = soup.find_all(re.compile('^h[1-6]$'))
print (tags)
Beautiful Soup - Extract Title Tag
<title> 标记用于向显示在浏览器标题栏中的页面提供文本标题。它不是网页主要内容的一部分。title 标记始终出现在 <head> 标记内。
我们可以通过 Beautiful Soup 提取 title 标记的内容。我们解析 HTML 树并获取 title 标记对象。
Example
html = '''
<html>
<head>
<Title>Python Libraries</title>
</head>
<body>
<p Hello World</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html5lib")
title = soup.title
print (title)
Output
<title>Python Libraries</title>
在 HTML 中,我们可以对所有标记使用 title 属性。title 属性提供了有关元素的其他信息。当鼠标悬停在元素上时,该信息会作为工具提示文本起作用。
我们可以使用以下代码段提取每个标记的 title 属性的文本 −
Example
html = '''
<html>
<body>
<p title='parsing HTML and XML'>Beautiful Soup</p>
<p title='HTTP library'>requests</p>
<p title='URL handling'>urllib</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html5lib")
tags = soup.find_all()
for tag in tags:
if tag.has_attr('title'):
print (tag.attrs['title'])
Beautiful Soup - Extract Email IDs
从网页中提取电子邮件地址是 Web 爬取库(如 BeautifulSoup)的一个重要应用。在任何网页中,电子邮件 ID 通常出现在链接 <a> 标记的 href 属性中。电子邮件 ID 使用 mailto URL 方案编写。许多时候,电子邮件地址可能以普通文本形式(没有超链接)存在于页面内容中。在本章中,我们将使用 BeautifulSoup 库,使用简单技术从 HTML 页面中获取电子邮件 ID。
在 href 属性中使用电子邮件 ID 的典型用法如下 -
<a href = "mailto:xyz@abc.com">test link</a>
在第一个示例中,我们将考虑以下 HTML 文档,用于从超链接中提取电子邮件 ID -
<html>
<head>
<title>BeautifulSoup - Scraping Email IDs</title>
</head>
<body>
<h2>Contact Us</h2>
<ul>
<li><a href = "mailto:sales@company.com">Sales Enquiries</a></li>
<li><a href = "mailto:careers@company.com">Careers</a></li>
<li><a href = "mailto:partner@company.com">Partner with us</a></li>
</ul>
</body>
</html>
以下是查找电子邮件 ID 的 Python 代码。我们收集文档中的所有 <a> 标记,并检查标记是否具有 href 属性。如果为真,它的值在第 6 个字符之后的部分就是电子邮件 ID。
from bs4 import BeautifulSoup
import re
fp = open("contact.html")
soup = BeautifulSoup(fp, "html.parser")
tags = soup.find_all("a")
for tag in tags:
if tag.has_attr("href") and tag['href'][:7]=='mailto:':
print (tag['href'][7:])
对于给定的 HTML 文档,电子邮件 ID 将按如下方式提取 -
sales@company.com
careers@company.com
partner@company.com
在第二个示例中,我们假定电子邮件 ID 出现在文本中的任何位置。要提取它们,我们使用 regex 搜索机制。Regex 是一个复杂的字符模式。Python 的 re 模块有助于处理 regex(正则表达式)模式。以下 regex 模式用于搜索电子邮件地址 -
pat = r'[\w.+-]+@[\w-]+\.[\w.-]+'
对于此练习,我们将使用以下 HTML 文档,其中电子邮件 ID 位于 <li> 标记中。
<html>
<head>
<title>BeautifulSoup - Scraping Email IDs</title>
</head>
<body>
<h2>Contact Us</h2>
<ul>
<li>Sales Enquiries: sales@company.com</a></li>
<li>Careers: careers@company.com</a></li>
<li>Partner with us: partner@company.com</a></li>
</ul>
</body>
</html>
使用电子邮件 regex,我们将找到模式在每个 <li> 标记字符串中的出现。以下是 Python 代码 -
Beautiful Soup - Scrape Nested Tags
HTML 文档中标记或元素的排列具有层次性。标记最多可嵌套为多层。例如,<head> 和 <body> 标记嵌套在 <html> 标记中。同样,一个或多个 <li> 标记可能存在于 <ul> 标记中。在本章中,我们将找出如何抓取嵌套有一个或多个子标记的标记。
我们考虑以下 HTML 文档 −
<div id="outer">
<div id="inner">
<p>Hello<b>World</b></p>
<img src='logo.jpg'>
</div>
</div>
在这种情况下,两个 <div> 标记和一个 <p> 标记嵌套有一个或多个子元素。而 <img> 和 <b> 标记没有子标记。
findChildren() 方法返回某个标记下所有子项目的 ResultSet。因此,如果一个标记没有任何子项目,则 ResultSet 将成为空列表,如 []。
由此作为线索,以下代码找出文档树中每个标记下的标记,并显示该列表。
Example
html = """
<div id="outer">
<div id="inner">
<p>Hello<b>World</b></p>
<img src='logo.jpg'>
</div>
</div>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
for tag in soup.find_all():
print ("Tag: {} attributes: {}".format(tag.name, tag.attrs))
print ("Child tags: ", tag.findChildren())
print()
Output
Tag: div attributes: {'id': 'outer'}
Child tags: [<div id="inner">
<p>Hello<b>World</b></p>
<img src="logo.jpg"/>
</div>, <p>Hello<b>World</b></p>, <b>World</b>, <img src="logo.jpg"/>]
Tag: div attributes: {'id': 'inner'}
Child tags: [<p>Hello<b>World</b></p>, <b>World</b>, <img src="logo.jpg"/>]
Tag: p attributes: {}
Child tags: [<b>World</b>]
Tag: b attributes: {}
Child tags: []
Tag: img attributes: {'src': 'logo.jpg'}
Child tags: []
Beautiful Soup - Parsing Tables
除了文本内容,HTML 文档还可能具有 HTML 表格形式的结构化数据。借助 Beautiful Soup,我们可以将表格数据提取为 Python 对象(例如列表或字典),如果需要,可以将这些数据存储在数据库或电子表格中,然后再执行处理操作。在本章中,我们将使用 Beautiful Soup 解析 HTML 表格。
虽然 Beautiful Soup 没有用于提取表格数据的任何特殊函数或方法,但我们可以通过一些简单的抓取技巧来实现此目的。就像 SQL 或电子表格中的任何表格一样,HTML 表格包含行和列。
HTML 中使用 <table> 标签来构建一个表格结构。有一个或多个嵌套 <tr> 标签,每个标签对应一行。每一行由 <td> 标签组成,这些标签用于保存行中每个单元格中的数据。第一行通常用于列标题,且标题不放在 <td> 标签中,而是放在 <th> 标签中
以下 HTML 脚本在浏览器窗口中呈现一个简单的表格 −
<html>
<body>
<h2>Beautiful Soup - Parse Table</h2>
<table border="1">
<tr>
<th>Name</th>
<th>Age</th>
<th>Marks</th>
</tr>
<tr class='data'>
<td>Ravi</td>
<td>23</td>
<td>67</td>
</tr>
<tr class='data'>
<td>Anil</td>
<td>27</td>
<td>84</td>
</tr>
</table>
</body>
</html>
请注意,数据行的外观是使用 CSS 类 data 自定义的,用于将其与标题行区分开来。
我们现在来看如何解析表格数据。首先,我们在 BeautifulSoup 对象中获取文档树。然后,将所有列标题收集到一个列表中。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup(markup, "html.parser")
tbltag = soup.find('table')
headers = []
headings = tbltag.find_all('th')
for h in headings: headers.append(h.string)
然后获取标题行之后的具有 class='data' 属性的数据行标签。将一个词典对象(以列标题为键,每个单元格中的相应值为值)形成,并将其附加到一个字典对象列表中。
rows = tbltag.find_all_next('tr', {'class':'data'})
trows=[]
for i in rows:
row = {}
data = i.find_all('td')
n=0
for j in data:
row[headers[n]] = j.string
n+=1
trows.append(row)
trows 中收集了一个字典对象列表。然后,你可以将此列表用于其他各种目的,例如存储在 SQL 表格中、以 JSON 或 pandas 数据框对象的形式保存。
以下是完整代码 −
markup = """
<html>
<body>
<p>Beautiful Soup - Parse Table</p>
<table>
<tr>
<th>Name</th>
<th>Age</th>
<th>Marks</th>
</tr>
<tr class='data'>
<td>Ravi</td>
<td>23</td>
<td>67</td>
</tr>
<tr class='data'>
<td>Anil</td>
<td>27</td>
<td>84</td>
</tr>
</table>
</body>
</html>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(markup, "html.parser")
tbltag = soup.find('table')
headers = []
headings = tbltag.find_all('th')
for h in headings: headers.append(h.string)
print (headers)
rows = tbltag.find_all_next('tr', {'class':'data'})
trows=[]
for i in rows:
row = {}
data = i.find_all('td')
n=0
for j in data:
row[headers[n]] = j.string
n+=1
trows.append(row)
print (trows)
Beautiful Soup - Selecting nth Child
HTML 的特点是标签的层级顺序。例如,<html> 标签包含 <body> 标签,在其内部可能有一个 <div> 标签,它还可以进一步包含嵌套的 <ul> 和 <li> 元素。findChildren() 方法和 .children 特性都将返回元素正下方所有子标签的 ResultSet(列表)。你可以通过遍历列表来获得位于所需位置上的子元素,也就是第 n 个子元素。
下面的代码使用 HTML 文档中某个 <div> 标签的 children 特性。由于 children 特性的返回类型是列表迭代器,因此我们要从中检索一个 Python 列表。我们还需要从迭代器中删除空格和换行符。完成后,我们可以获取所需的子元素。这里显示了索引为 1 的 <div> 标签的子元素。
Example
from bs4 import BeautifulSoup, NavigableString
markup = '''
<div id="Languages">
<p>Java</p> <p>Python</p> <p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.div
children = tag.children
childlist = [child for child in children if child not in ['\n', ' ']]
print (childlist[1])
Output
<p>Python</p>
要使用 findChildren() 方法代替 children 特性,请将语句更改为
children = tag.findChildren()
输出不会改变。
定位第 n 个子元素的更有效方法是使用 select() 方法。select() 方法使用 CSS 选择器从当前元素中获取所需的 PageElements。
Soup 和 Tag 对象通过它们的 .css 特性来支持 CSS 选择器,该特性是一个与 CSS 选择器 API 的接口。选择器实现由 Soup Sieve 包处理,该包会随 bs4 包一起安装。
Soup Sieve 包定义了不同类型的 CSS 选择器,即由一个或多个类型选择器、ID 选择器和类选择器组成的简单、复合和复杂 CSS 选择器。这些选择器在 CSS 语言中定义。
Soup Sieve 中也有伪类选择器。CSS 伪类是添加到选择器的关键字,用于指定所选元素的特殊状态。我们将在此示例中使用 :nth-child 伪类选择器。由于我们需要选择处于第 2 个位置的 <div> 标记的子元素,因此需要将 :nthchild(2) 传递给 select_one() 方法。
Beautiful Soup - Search by text inside a Tag
Beautiful Soup 提供了不同方法来在给定的 HTML 文档中搜索特定文本。在这里,为此目的使用 find() 方法的字符串参数。
在下面的示例中,我们使用 find() 方法来搜索单词 “by”。
Example
html = '''
<p> The quick, brown fox jumps over a lazy dog.</p>
<p> DJs flock by when MTV ax quiz prog.</p>
<p> Junk MTV quiz graced by fox whelps.</p>
<p> Bawds jog, flick quartz, vex nymphs./p>
'''
from bs4 import BeautifulSoup, NavigableString
def search(tag):
if 'by' in tag.text:
return True
soup = BeautifulSoup(html, 'html.parser')
tag = soup.find('p', string=search)
print (tag)
Output
<p> DJs flock by when MTV ax quiz prog.</p>
You can find all occurrences of the word with find_all() method
tag = soup.find_all('p', string=search)
print (tag)
Output
[<p> DJs flock by when MTV ax quiz prog.</p>, <p> Junk MTV quiz graced by fox whelps.</p>]
在某些情况下,必需文本可能位于文档树深处的子标记内。我们需要首先找到没有其他元素的标记,然后检查必需文本是否在其中。
Example
html = '''
<p> The quick, brown fox jumps over a lazy dog.</p>
<p> DJs flock by when MTV ax quiz prog.</p>
<p> Junk MTV quiz graced by fox whelps.</p>
<p> Bawds jog, flick quartz, vex nymphs./p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tags = soup.find_all(lambda tag: len(tag.find_all()) == 0 and "by" in tag.text)
for tag in tags:
print (tag)
Beautiful Soup - Remove HTML Tags
在本章,让我们看看如何在 HTML 文档中移除所有标记。HTML 是一种标记语言,由预定义标记组成。标记标记与它相关联的某些文本,以便浏览器根据其预定义的含义呈现它。例如,用 <b> 标记标记的词“Hello”(例如 <b>Hello</b>)会被浏览器以粗体呈现。
如果我们想在 HTML 文档中筛选出不同的标记之间的原始文本,我们可以使用 Beautiful Soup 库中的 get_text() 或 extract() 中的任何一个方法。
get_text() 方法收集文档中的所有原始文本部分并返回一个字符串。但是,原始文档树不会被更改。
在以下示例中,get_text() 方法移除所有 HTML 标记。
Example
html = '''
<html>
<body>
<p> The quick, brown fox jumps over a lazy dog.</p>
<p> DJs flock by when MTV ax quiz prog.</p>
<p> Junk MTV quiz graced by fox whelps.</p>
<p> Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
text = soup.get_text()
print(text)
Output
The quick, brown fox jumps over a lazy dog.
DJs flock by when MTV ax quiz prog.
Junk MTV quiz graced by fox whelps.
Bawds jog, flick quartz, vex nymphs.
请注意,上面的示例中的 soup 对象仍然包含 HTML 文档的已解析树。
另一种方法是在从 soup 对象中提取之前先收集包含在 Tag 对象中的字符串。在 HTML 中,有些标记没有 string 属生(我们可以说,对于某些标记,例如 <html> 或 <body>,tag.string 为 None)。因此,我们从所有其他标记连接字符串,以从 HTML 文档中获得纯文本。
以下程序对此方法进行了演示。
Example
html = '''
<html>
<body>
<p>The quick, brown fox jumps over a lazy dog.</p>
<p>DJs flock by when MTV ax quiz prog.</p>
<p>Junk MTV quiz graced by fox whelps.</p>
<p>Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
tags = soup.find_all()
string=''
for tag in tags:
#print (tag.name, tag.string)
if tag.string != None:
string=string+tag.string+'\n'
tag.extract()
print ("Document text after removing tags:")
print (string)
print ("Document:")
print (soup)
Beautiful Soup - Remove all Styles
本章节说明如何从 HTML 文档中删除所有样式。层叠样式表 (CSS) 用于控制 HTML 文档的不同方面的显示方式。其中包括为文本使用特定字体、颜色、对齐方式、间距等设置样式。CSS 会通过不同方式应用于 HTML 标签。
其中一种方法是在 CSS 文件中定义不同样式,并通过文档 <head> 部分中的 <link> 标签将它们包含到 HTML 脚本中。例如,
Example
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
. . .
. . .
</body>
</html>
HTML 脚本主体部分中的不同标签将会使用 mystyle.css 文件中的定义。
另一种方法是在 HTML 文档自身的 <head> 部分中定义样式配置。主体部分中的标签将会使用在此处提供的定义来呈现。
内部样式示例:
<html>
<head>
<style>
p {
text-align: center;
color: red;
}
</style>
</head>
<body>
<p>para1.</p>
<p id="para1">para2</p>
<p>para3</p>
</body>
</html>
在任何情况下,为以编程方式删除样式,只需要从 soup 对象中删除 head 标签。
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
soup.head.extract()
第三种方法是通过在标签中包含 style 属性来按行定义样式。该 style 属性可能包含一个或更多个样式属性定义,如颜色、大小等。例如:
<body>
<h1 style="color:blue;text-align:center;">This is a heading</h1>
<p style="color:red;">This is a paragraph.</p>
</body>
为从 HTML 文档中删除这些内联样式,你需要查看标签对象的 attrs 字典中是否定义了 style 键,如果定义了,就删除该键。
tags=soup.find_all()
for tag in tags:
if tag.has_attr('style'):
del tag.attrs['style']
print (soup)
以下代码将删除内联样式以及 head 标签本身,因此结果 HTML 树中将不会有任何样式。
html = '''
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1 style="color:blue;text-align:center;">This is a heading</h1>
<p style="color:red;">This is a paragraph.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
soup.head.extract()
tags=soup.find_all()
for tag in tags:
if tag.has_attr('style'):
del tag.attrs['style']
print (soup.prettify())
Beautiful Soup - Remove all Scripts
HTML 中经常使用的一个标记是 <script> 标记。它有助于在 HTML 中嵌入客户端脚本(如 JavaScript 代码)。在本章中,我们将使用 BeautifulSoup 从 HTML 文档中删除脚本标记。
<script> 标记有一个对应的 </script> 标记。在这两个标记之间,你可以包含对外部 JavaScript 文件的引用,或将 JavaScript 代码与 HTML 脚本本身内联。
要包含一个外部 Javascript 文件,请使用以下语法 −
<head>
<script src="javascript.js"></script>
</head>
然后,你可以在 HTML 中调用在此文件中定义的函数。
除了引用外部文件之外,你还可以将 JavaScipt 代码放在 <script> 和 </script> 代码内的 HTML 中。如果将其放在 HTML 文档的 <head> 部分中,那么该功能将在整个文档树中可用。另一方面,如果将其放在 <body> 部分的任何位置,则 JavaScript 函数从此处可用。
<body>
<p>Hello World</p>
<script>
alert("Hello World")
</script>
</body>
使用 Beautiful 轻松去除所有脚本标签。您必须从解析树中收集所有脚本标签的列表并逐一提取它们。
Example
html = '''
<html>
<head>
<script src="javascript.js"></scrript>
</head>
<body>
<p>Hello World</p>
<script>
alert("Hello World")
</script>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
for tag in soup.find_all('script'):
tag.extract()
print (soup)
Beautiful Soup - Remove Empty Tags
在 HTML 中,许多标记具有一个开放式标记和一个结束式标记。此类标记主要用于定义格式化属性,如 <b> 和 </b>、<h1> 和 </h1> 等。也有一些自闭合标记不带结束标记也没有文本部分。例如 <img>、<br>、<input> 等。然而,在编写 HTML 时,可能会无意插入不带任何文本的标记,例如 <p></p>。我们需要借助 Beautiful Soup 库函数移除此类空标记。
移除不带任何文本的文本标记非常简单,如果你可以调用标记上的 extract() 方法且其内部文本的长度为 0。
for tag in tags:
if (len(tag.get_text(strip=True)) == 0):
tag.extract()
但是,这会移除标记,例如 <hr>、<img> 和 <input> 等。这些都是自闭合标记或单例标记。你不希望关闭带有一个或多个属性的标记,即使没有与其关联的文本。所以你必须检查一个标记是否带有任何属性且 get_text() 返回无。
在以下示例中,都存在 HTML 字符串中带有空文本标记和一些单例标记的情况。该代码保留带属性的标记,但移除不带有嵌入文本的标记。
Example
html ='''
<html>
<body>
<p>Paragraph</p>
<embed type="image/jpg" src="Python logo.jpg" width="300" height="200">
<hr>
<b></b>
<p>
<a href="#">Link</a>
<ul>
<li>One</li>
</ul>
<input type="text" id="fname" name="fname">
<img src="img_orange_flowers.jpg" alt="Flowers">
</body>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
tags =soup.find_all()
for tag in tags:
if (len(tag.get_text(strip=True)) == 0):
if len(tag.attrs)==0:
tag.extract()
print (soup)
Output
<html>
<body>
<p>Paragraph</p>
<embed height="200" src="Python logo.jpg" type="image/jpg" width="300"/>
<p>
<a href="#">Link</a>
<ul>
<li>One</li>
</ul>
<input id="fname" name="fname" type="text"/>
<img alt="Flowers" src="img_orange_flowers.jpg"/>
</p>
</body>
</html>
请注意,原始 html 代码带有一个不带有包围 </p> 的 <p> 标记。解析器自动插入结束标记。如果你将解析器更改为 lxml 或 html5lib,结束标记的位置可能会改变。
Beautiful Soup - Remove Child Elements
HTML 文档是不同标记的分层排列,其中一个标记可能在其上嵌套一个或多个标记,并在多个层级中。我们如何删除特定标记的子元素?使用 BeautifulSoup,这非常容易。
BeautifulSoup 库中有两种主要方法,可以删除特定标记。decompose() 方法和 extract() 方法,区别在于后者返回被移除的内容,而前者只是将其销毁。
因此,要删除子元素,请为给定的 Tag 对象调用 findChildren() 方法,然后在每个方法上 extract() 或 decompose()。
考虑以下代码段:
soup = BeautifulSoup(fp, "html.parser")
soup.decompose()
print (soup)
这将销毁整个 soup 对象本身,即文档的已解析树。显然,我们不想这样做。
现在是以下代码:
soup = BeautifulSoup(fp, "html.parser")
tags = soup.find_all()
for tag in tags:
for t in tag.findChildren():
t.extract()
在文档树中,<html> 是第一个标记,所有其他标记都是其子代,因此,在循环的第一次迭代中,它将删除除 <html> 和 </html> 之外的所有标记。
如果我们想删除特定标记的子代,则可以使用此方法更有效。例如,您可能希望删除 HTML 表格的头行。
以下 HTML 脚本有一个表格,第一个 <tr> 元素具有用 <th> 标记标记的标题。
<html>
<body>
<h2>Beautiful Soup - Remove Child Elements</h2>
<table border="1">
<tr class='header'>
<th>Name</th>
<th>Age</th>
<th>Marks</th>
</tr>
<tr>
<td>Ravi</td>
<td>23</td>
<td>67</td>
</tr>
<tr>
<td>Anil</td>
<td>27</td>
<td>84</td>
</tr>
</table>
</body>
</html>
我们可以使用以下 Python 代码删除具有 <th> 单元的 <tr> 标记的所有子元素。
Beautiful Soup - find vs find_all
Beautiful Soup 库包括 find() 和 find_all() 方法。解析 HTML 或 XML 文档时,两种方法都是最常使用的方法之一。从特定的文档树中,你常常需要找到一个确定标记类型的 PageElement,或具有某些属性,或具有特定 CSS 样式等。这些条件作为参数提供给 find() 和 find_all() 方法。两者的主要区别点在于,find() 找到满足条件的第一个子元素,而 find_all() 方法搜索条件的所有子元素。
find() 方法的定义如下语法 −
Syntax
find(name, attrs, recursive, string, **kwargs)
name 参数指定标记名称的筛选器。使用 attrs,可以针对标记属性值设置筛选器。如果 recursive 参数为 True,则会执行递归搜索。你可以将可变 kwargs 传递为属性值筛选器的字典。
soup.find(id = 'nm')
soup.find(attrs={"name":'marks'})
find_all() 方法接收与 find() 方法完全一样所有的参数,此外还有 limit 参数。这是一个整数,它将搜索限制为给定筛选器条件指定数量的匹配项。如果没有设置,find_all() 将在该 PageElement 下的所有子元素中搜索条件。
soup.find_all('input')
lst=soup.find_all('li', limit =2)
如果将 find_all() 方法的 limit 参数设置为 1,它将虚拟充当 find() 方法。
两种方法的返回类型不同。find() 方法返回最早找到的一个 Tag 对象或 NavigableString 对象。find_all() 方法返回一个 ResultSet,其中包含满足筛选器条件的所有 PageElement。
下面是一个演示 find 和 find_all 方法之间的区别的示例。
Example
from bs4 import BeautifulSoup
markup =open("index.html")
soup = BeautifulSoup(markup, 'html.parser')
ret1 = soup.find('input')
ret2 = soup.find_all ('input')
print (ret1, 'Return type of find:', type(ret1))
print (ret2)
print ('Return tyoe find_all:', type(ret2))
#set limit =1
ret3 = soup.find_all ('input', limit=1)
print ('find:', ret1)
print ('find_all:', ret3)
Output
<input id="nm" name="name" type="text"/> Return type of find: <class 'bs4.element.Tag'>
[<input id="nm" name="name" type="text"/>, <input id="age" name="age" type="text"/>, <input id="marks" name="marks" type="text"/>]
Return tyoe find_all: <class 'bs4.element.ResultSet'>
find: <input id="nm" name="name" type="text"/>
find_all: [<input id="nm" name="name" type="text"/>]
Beautiful Soup - Specifying the Parser
将 HTML 文档树解析为 BeautifulSoup 类的对象。此类的构造函数需要以 HTML 字符串或指向 HTML 文件的文件对象作为强制参数。构造函数具有所有其他可选参数,其中最重要的为特征。
BeautifulSoup(markup, features)
此处标记为 HTML 字符串或文件对象。features 参数指定要使用的解析器。它可以是特定解析器,例如 “lxml”、“lxml-xml”、“html.parser”或 “html5lib;或要使用的标记类型(“html”、“html5”、“xml”)。
如果未给出 features 参数,Beautiful Soup 会选择已安装的最佳 HTML 解析器。Beautiful Soup 将 lxml 的解析器评为最佳,然后是 html5lib,最后是 Python 的内置解析器。
你可以指定以下任一项 −
要解析的标记类型。Beautiful Soup 目前支持 “html”、“xml”和 “html5”。
要使用的解析器库的名称。当前支持的选项为 “lxml”、“html5lib”和 “html.parser”(Python 的内置 HTML 解析器)。
要安装 lxml 或 html5lib 解析器,请使用命令 −
pip3 install lxml
pip3 install html5lib
这些解析器具有各自的优点和缺点,如下所示 -
Parser: html5lib
Usage − BeautifulSoup(markup, "html5lib")
Disadvantages
-
Very slow
-
External Python dependency
不同的解析器会从同一文档创建不同的解析树。最大的区别在于 HTML 解析器和 XML 解析器之间。下面是一个短文档,已解析为 HTML −
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup("<a><b /></a>", "html.parser")
print (soup)
Output
<a><b></b></a>
空 <b /> 标记不是有效的 HTML。因此,解析器会将其变成 <b></b> 标记对。
现在的同一个文档已解析为 XML。请注意,空 <b /> 标记已保留,并且该文档给出了 XML 声明,而不是被放入 <html> 标记中。
Output
<?xml version="1.0" encoding="utf-8"?>
<a><b/></a>
对于格式良好的 HTML 文档,所有 HTML 解析器都会产生类似的解析树,尽管一个解析器将比另一个解析器更快。
然而,如果 HTML 文档不够完美,那么不同类型的解析器将会产生不同的结果。请参见当用不同的解析器解析 “<a></p>” 时结果有什么不同 −
lxml parser
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup("<a></p>", "lxml")
print (soup)
Output
<html><body><a></a></body></html>
请注意,HTML 中悬空的 </p> 标记会被忽略。
Beautiful Soup - Comparing Objects
根据 BeautifulSoup,如果两个可导航字符串或标记对象表示相同的 HTML/XML 标记,则它们相等。
现在让我们看看下面的示例,其中两个 <b> 标记被视为相等,即使它们位于对象树的不同部分,因为它们都看起来像 "<b>Java</b>"。
Example
from bs4 import BeautifulSoup
markup = "<p>Learn <i>Python</i>, <b>Java</b>, advanced <i>Python</i> and advanced <b>Java</b>! from Tutorialspoint</p>"
soup = BeautifulSoup(markup, "html.parser")
b1 = soup.find('b')
b2 = b1.find_next('b')
print(b1== b2)
print(b1 is b2)
Example
from bs4 import BeautifulSoup
markup = "<p>Learn <i>Python</i>, <b>Java</b>, advanced <i>Python</i> and advanced <b>Java</b>! from Tutorialspoint</p>"
soup = BeautifulSoup(markup, "html.parser")
i1 = soup.find('i')
i2 = i1.find_next('i')
print(i1.string== i2.string)
print(i1.string is i2.string)
Beautiful Soup - Copying Objects
要创建任何标记或 NavigableString 的副本,请使用 Python 标准库中 copy 模块中的 copy() 函数。
Example
from bs4 import BeautifulSoup
import copy
markup = "<p>Learn <b>Python, Java</b>, <i>advanced Python and advanced Java</i>! from Tutorialspoint</p>"
soup = BeautifulSoup(markup, "html.parser")
i1 = soup.find('i')
icopy = copy.copy(i1)
print (icopy)
Beautiful Soup - Get Tag Position
Beautiful Soup 中的 Tag 对象具有两个有用的属性,可提供有关其在 HTML 文档中的位置的信息。它们是 −
sourceline − 找到标记的行号
sourcepos − 标签在其所在行中的起始索引。
html.parser(Python 的内置解析器)和 html5lib 解析器支持这些属性。当你使用 lmxl 解析器时,它们不可用。
在以下示例中,使用 html.parser 解析 HTML 字符串,我们在 HTML 字符串中找到 <p> 标记的行号和位置。
Example
html = '''
<html>
<body>
<p>Web frameworks</p>
<ul>
<li>Django</li>
<li>Flask</li>
</ul>
<p>GUI frameworks</p>
<ol>
<li>Tkinter</li>
<li>PyQt</li>
</ol>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
p_tags = soup.find_all('p')
for p in p_tags:
print (p.sourceline, p.sourcepos, p.string)
Output
4 0 Web frameworks
9 0 GUI frameworks
对于 html.parser,这些数字表示小于符号的初始位置,在本例中为 0。当使用 html5lib 解析器时,它略有不同。
Example
html = '''
<html>
<body>
<p>Web frameworks</p>
<ul>
<li>Django</li>
<li>Flask</li>
</ul>
<p>GUI frameworks</p>
<ol>
<li>Tkinter</li>
<li>PyQt</li>
</ol>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html5lib')
li_tags = soup.find_all('li')
for l in li_tags:
print (l.sourceline, l.sourcepos, l.string)
Beautiful Soup - Encoding
所有 HTML 或 XML 文档都写入一些特定编码(如 ASCII 或 UTF-8)。但是,当您将该 HTML/XML 文档加载到 BeautifulSoup 时,它已被转换成 Unicode。
Example
from bs4 import BeautifulSoup
markup = "<p>I will display £</p>"
soup = BeautifulSoup(markup, "html.parser")
print (soup.p)
print (soup.p.string)
Output
<p>I will display £</p>
I will display £
之所以会出现以上情况,是因为 BeautifulSoup 在内部使用名为 Unicode, Dammit 的子库检测文档的编码,然后将其转换成 Unicode。
但是,并非总是 Unicode, Dammit 能正确猜测。由于要逐字节搜索文档以猜测编码,因此会花费大量时间。如果您已经知道编码,可以将其作为 from_encoding 传递到 BeautifulSoup 构造器中,这样可以节省一些时间并避免错误发生。
下面是一个 BeautifulSoup 识别错误的示例,将 ISO-8859-8 文档识别为 ISO-8859-7 −
Example
from bs4 import BeautifulSoup
markup = b"<h1>\xed\xe5\xec\xf9</h1>"
soup = BeautifulSoup(markup, 'html.parser')
print (soup.h1)
print (soup.original_encoding)
Example
from bs4 import BeautifulSoup
markup = b"<h1>\xed\xe5\xec\xf9</h1>"
soup = BeautifulSoup(markup, "html.parser", from_encoding="iso-8859-8")
print (soup.h1)
print (soup.original_encoding)
Output
<h1>םולש</h1>
iso-8859-8
BeautifulSoup 4.4.0 中的另一项新功能是 exclude_encoding。在您不知道正确编码但确定 Unicode, Dammit 未显示正确结果时,可以使用它。
soup = BeautifulSoup(markup, exclude_encodings=["ISO-8859-7"])
Output encoding
BeautifulSoup 的输出是 UTF-8 文档,与输入到 BeautifulSoup 的文档无关。下面的文档中,波兰语字符采用 ISO-8859-2 格式。
Example
markup = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-2">
</HEAD>
<BODY>
ą ć ę ł ń ó ś ź ż Ą Ć Ę Ł Ń Ó Ś Ź Ż
</BODY>
</HTML>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(markup, "html.parser", from_encoding="iso-8859-8")
print (soup.prettify())
Output
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
</head>
<body>
ą ć ę ł ń ó ś ź ż Ą Ć Ę Ł Ń Ó Ś Ź Ż
</body>
</html>
在上述示例中,如果您注意到,<meta> 标签已被重写,以反映由 BeautifulSoup 生成的文档现为 UTF-8 格式。
如果您不希望生成的输出为 UTF-8,可以在 prettify() 中分配所需的编码。
print(soup.prettify("latin-1"))
Output
b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n<html>\n <head>\n <meta content="text/html; charset=latin-1" http-equiv="content-type"/>\n </head>\n <body>\n ą ć ę ł ń \xf3 ś ź ż Ą Ć Ę Ł Ń \xd3 Ś Ź Ż\n </body>\n</html>\n'
在上述示例中,我们对整个文档进行了编码,但是您也可以对汤中的任何特定元素进行编码,就像对其为 Python 字符串一样 −
soup.p.encode("latin-1")
soup.h1.encode("latin-1")
Output
b'<p>My first paragraph.</p>'
b'<h1>My First Heading</h1>'
任何无法用您选择的编码表示的字符将被转换成数字 XML 实体引用。下面是一个示例 −
markup = u"<b>\N{SNOWMAN}</b>"
snowman_soup = BeautifulSoup(markup)
tag = snowman_soup.b
print(tag.encode("utf-8"))
Beautiful Soup - Output Formatting
如果提供给 BeautifulSoup 构造函数的 HTML 字符串包含任何 HTML 实体,它们将被转换为 Unicode 字符。
HTML 实体是一个以 & (&)开头并以分号(;)结尾的字符串。它们用于显示保留字符(否则将被解释为 HTML 代码)。一些 HTML 实体的示例:
< |
less than |
< |
< |
> |
greater than |
> |
> |
& |
ampersand |
& |
& |
" |
double quote |
" |
" |
' |
single quote |
' |
' |
" |
Left Double quote |
“ |
“ |
" |
Right double quote |
” |
” |
£ |
Pound |
£ |
£ |
¥ |
yen |
¥ |
¥ |
€ |
euro |
€ |
€ |
© |
copyright |
© |
© |
默认情况下,在输出时转义的唯一字符是裸露的 & 和尖括号。这些被转换为“&”、“<”和“>”。
对于其他字符,它们将被转换为 Unicode 字符。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup("Hello “World!”", 'html.parser')
print (str(soup))
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup("Hello “World!”", 'html.parser')
print (soup.encode())
Output
b'Hello \xe2\x80\x9cWorld!\xe2\x80\x9d'
要更改此行为,请为 prettify() 方法的格式化程序参数提供一个值。对于格式化程序,以下可能的值:
formatter="minimal" - 这是默认值。字符串仅会得到足够的处理,以确保 Beautiful Soup 能够生成有效的 HTML/XML
formatter="html" − 只要有可能,Beautiful Soup 将把 Unicode 字符转换为 HTML 实体。
formatter="html5" - 它类似于 formatter="html”,但 Beautiful Soup 将在 HTML 空标签(如“br”)中省略结束斜杠。
formatter=None - Beautiful Soup 根本不会在输出时修改字符串。这是最快的选项,但可能会导致 Beautiful Soup 生成无效的 HTML/XML。
Beautiful Soup - Pretty Printing
要显示 HTML 文档的整个已解析树或特定标记的内容,您也可以使用 print() 函数或同样调用 str() 函数。
Example
from bs4 import BeautifulSoup
soup = BeautifulSoup("<h1>Hello World</h1>", "lxml")
print ("Tree:",soup)
print ("h1 tag:",str(soup.h1))
Output
Tree: <html><body><h1>Hello World</h1></body></html>
h1 tag: <h1>Hello World</h1>
str() 函数返回一个以 UTF-8 编码的字符串。
要获得格式良好的 Unicode 字符串,请使用 Beautiful Soup 的 prettify() 方法。它对 Beautiful Soup 解析树进行格式化,以便每个标记都位于单独的行上并带有缩进。它允许您轻松可视化 Beautiful Soup 解析树的结构。
考虑以下 HTML 字符串。
<p>The quick, <b>brown fox</b> jumps over a lazy dog.</p>
通过使用 prettify() 方法,我们可以更好地理解其结构 −
html = '''
<p>The quick, <b>brown fox</b> jumps over a lazy dog.</p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "lxml")
print (soup.prettify())
Beautiful Soup - NavigableString Class
Beautiful Soup API 中普遍存在的一个主要对象是 NavigableString 类的对象。它表示大多数 HTML 标记的开始和结束部分之间的字符串或文本。例如,如果 <b>Hello</b> 是要解析的标记,Hello 是 NavigableString。
NavigableString 类是 bs4 包中的 PageElement 类的子类,也是 Python 的内置 str 类的子类。因此,它继承了 PageElement 方法,如 find_*()、insert、append、wrap、unwrap 方法以及 str 类的 upper、lower、find、isalpha 等方法。
此类的构造函数采用一个参数,即 str 对象。
Example
from bs4 import NavigableString
new_str = NavigableString('world')
现在,您可以使用此 NavigableString 对象对解析的树执行各种操作,例如 append、insert、find 等。
在下面的示例中,我们将新创建的 NavigableString 对象附加到现有的 Tab 对象。
Example
from bs4 import BeautifulSoup, NavigableString
markup = '<b>Hello</b>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.b
new_str = NavigableString('world')
tag.append(new_str)
print (soup)
Output
<b>Hello</b>world
正如我们所看到的, string 位于 <b> 标签之后。
Beautiful Soup 提供了一个 new_string() 方法。创建一个与这个 BeautifulSoup 对象相关联的新 NavigableString。
让我们使用 new_string() 方法创建一个 NavigableString 对象,并将其添加到 PageElements。
Beautiful Soup - Convert Object to String
Beautiful Soup API 有三类主要对象。soup 对象、Tag 对象和 NavigableString 对象。让我们找出如何将这些对象转换为字符串。在 Python 中,字符串是一个 str 对象。
我们有一个以下 HTML 文档
html = '''
<p>Hello <b>World</b></p>
'''
让我们将这个字符串作为 BeautifulSoup 构造函数的参数。然后使用 Python 的内置 str() 函数将 soup 对象强制转换为字符串对象。
该 HTML 字符串的已解析树将基于使用的解析器而构建。内置 html 解析器不会添加 <html> 和 <body> 标记。
Output
<p>Hello <b>World</b></p>
另一方面,html5lib 解析器会在插入 <html> 和 <body> 等形式标记后构建树。
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html5lib')
print (str(soup))
Output
<html><head></head><body><p>Hello <b>World</b></p>
</body></html>
Tag 对象有一个字符串属性,用于返回 NavigableString 对象。
tag = soup.find('b')
obj = (tag.string)
print (type(obj),obj)
Output
string <class 'bs4.element.NavigableString'> World
还为 Tag 对象定义了 Text 属性。它返回标记中包含的文本,并清除所有内部标记和属性。
如果 HTML 字符串为 −
html = '''
<p>Hello <div id='id'>World</div></p>
'''
我们尝试获取 <p> 标记的文本属性
tag = soup.find('p')
obj = (tag.text)
print ( type(obj), obj)
Beautiful Soup - Convert HTML to Text
Beautiful Soup 库等网络爬虫的一个重要但经常需要的应用程序是从 HTML 脚本中提取文本。您可能需要丢弃所有标签以及与其关联的属性(如果有),并从文档中分离原始文本。Beautiful Soup 中的 get_text() 方法适用于此目的。
这里有一个演示 get_text() 方法用法的基本示例。您可以通过删除所有 HTML 标签来获取 HTML 文档中的所有文本。
Example
html = '''
<html>
<body>
<p> The quick, brown fox jumps over a lazy dog.</p>
<p> DJs flock by when MTV ax quiz prog.</p>
<p> Junk MTV quiz graced by fox whelps.</p>
<p> Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
text = soup.get_text()
print(text)
Output
The quick, brown fox jumps over a lazy dog.
DJs flock by when MTV ax quiz prog.
Junk MTV quiz graced by fox whelps.
Bawds jog, flick quartz, vex nymphs.
get_text() 方法有一个可选的分隔符参数。在以下示例中,我们将 get_text() 方法的分隔符参数指定为“#”。
html = '''
<p>The quick, brown fox jumps over a lazy dog.</p>
<p>DJs flock by when MTV ax quiz prog.</p>
<p>Junk MTV quiz graced by fox whelps.</p>
<p>Bawds jog, flick quartz, vex nymphs.</p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
text = soup.get_text(separator='#')
print(text)
Output
#The quick, brown fox jumps over a lazy dog.#
#DJs flock by when MTV ax quiz prog.#
#Junk MTV quiz graced by fox whelps.#
#Bawds jog, flick quartz, vex nymphs.#
get_text() 方法还有另一个参数 strip,可以为 True 或 False。让我们检查 strip 参数设置真时的效果。默认情况下它为 False。
html = '''
<p>The quick, brown fox jumps over a lazy dog.</p>
<p>DJs flock by when MTV ax quiz prog.</p>
<p>Junk MTV quiz graced by fox whelps.</p>
<p>Bawds jog, flick quartz, vex nymphs.</p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
text = soup.get_text(strip=True)
print(text)
Beautiful Soup - Parsing XML
BeautifulSoup 还可以解析 XML 文档。您需要将 fatures='xml' 参数传递给 Beautiful() 构造函数。
假设我们在当前的工作目录中有以下内容 books.xml −
Example
<?xml version="1.0" ?>
<books>
<book>
<title>Python</title>
<author>TutorialsPoint</author>
<price>400</price>
</book>
</books>
以下代码会解析给定的 XML 文件 −
from bs4 import BeautifulSoup
fp = open("books.xml")
soup = BeautifulSoup(fp, features="xml")
print (soup)
print ('type:', type(soup))
执行以上代码后,您应该会得到以下结果 −
<?xml version="1.0" encoding="utf-8"?>
<books>
<book>
<title>Python</title>
<author>TutorialsPoint</author>
<price>400</price>
</book>
</books>
type: <class 'bs4.BeautifulSoup'>
XML parser Error
默认情况下,Beautiful Soup 程序包会将文档解析为 HTML,然而,它非常易于使用,并且使用 beautifulsoup4 非常优雅地处理格式错误的 XML。
要将文档解析为 XML,您需要具有 lxml 解析器,只需要将 "xml" 作为第二个参数传递给 Beautiful Soup 构造函数即可 -
soup = BeautifulSoup(markup, "lxml-xml")
或
soup = BeautifulSoup(markup, "xml")
一个常见的 XML 解析错误是 -
AttributeError: 'NoneType' object has no attribute 'attrib'
在使用 find() 或 findall() 函数时,某些元素丢失或未定义,可能会发生这种情况。
Beautiful Soup - Error Handling
在尝试使用 Beautiful Soup 解析 HTML/XML 文档时,您可能会遇到错误,这并非来自您的脚本,而是来自片段的结构,因为 BeautifulSoup API 会引发错误。
默认情况下,Beautiful Soup 程序包会将文档解析为 HTML,然而,它非常易于使用,并且使用 beautifulsoup4 非常优雅地处理格式错误的 XML。
要将文档解析为 XML,您需要具有 lxml 解析器,只需要将 "xml" 作为第二个参数传递给 Beautiful Soup 构造函数即可 -
soup = BeautifulSoup(markup, "lxml-xml")
或
soup = BeautifulSoup(markup, "xml")
一个常见的 XML 解析错误是 -
AttributeError: 'NoneType' object has no attribute 'attrib'
在使用 find() 或 findall() 函数时,某些元素丢失或未定义,可能会发生这种情况。
除了上述提及的解析错误之外,您可能会遇到其他解析问题,例如环境问题,其中您的脚本可能在一个操作系统下工作,但在另一个操作系统下却不行,可能在一个虚拟环境下工作,但在另一个虚拟环境下却不行,或者可能无法在虚拟环境外工作。所有这些问题都可能是因为两个环境有不同的可用解析器库。
建议了解或检查您当前工作环境中的默认解析器。您可以检查当前工作环境中可用的当前默认解析器,或显式地将所需的解析器库作为第二个参数传递给 BeautifulSoup 构造函数。
由于 HTML 标签和属性不区分大小写,所有三个 HTML 解析器都将标签和属性名称转换为小写。但是,如果您要保留混合大小写或大写标签和属性,那么最好将文档解析为 XML。
UnicodeEncodeError
让我们看看下面的代码段 -
Output
UnicodeEncodeError: 'charmap' codec can't encode character '\u011f'
上面的问题可能是由于两个主要情况造成的。您可能尝试打印您的控制台不知道如何显示的 Unicode 字符。其次,您尝试写入文件,并传递了一个不受默认编码支持的 Unicode 字符。
解决上述问题的一种方法是在生成 soup 以获取所需结果之前对响应文本/字符进行编码,如下所示 -
responseTxt = response.text.encode('UTF-8')
KeyError: [attr]
当有问题的标签没有定义 attr 属性时,访问 tag['attr'] 会导致此错误。最常见的错误是:“KeyError: 'href'”和“KeyError: 'class'”。如果您不确定 attr 是否已定义,请使用 tag.get('attr')。
for item in soup.fetch('a'):
try:
if (item['href'].startswith('/') or "tutorialspoint" in item['href']):
(...)
except KeyError:
pass # or some other fallback action
Beautiful Soup - Trouble Shooting
如果你在尝试解析 HTML/XML 文档时遇到问题,则更有可能是因为使用的解析器正在解释文档。为了帮助你找到并纠正问题,Beautiful Soup API 提供了一个诊断程序 diagnose()。
Beautiful Soup 中的 diagnose() 方法是一个诊断套件,用于隔离常见问题。如果你难以理解 Beautiful Soup 对文档执行了哪些操作,请将文档作为参数传递给 diagnose() 函数。一份报告显示了不同解析器如何处理文档,并告诉你是否缺少解析器。
diagnose() 方法在 bs4.diagnose 模块中定义。其输出以如下消息开头 −
Output
Diagnostic running on Beautiful Soup 4.12.2
Python version 3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)]
Found lxml version 4.9.2.0
Found html5lib version 1.1
Trying to parse your markup with html.parser
Here's what html.parser did with the markup:
如果没有找到这些解析器中的任何一个,还会出现一条相应的消息。
I noticed that html5lib is not installed. Installing it may help.
如果馈送到 diagnose() 方法的 HTML 文档形成正确,则任何解析器解析的树都将相同。但是,如果它形成不正确,那么不同的解析器会进行不同的解释。如果你没有得到你预期的树,则更改解析器可能会很有帮助。
有时,你可能为 XML 文档选择了 HTML 解析器。HTML 解析器在不正确地解析文档时会添加所有 HTML 标记。查看输出,你将意识到错误,并可在纠正中提供帮助。
如果 Beautiful Soup 发出 HTMLParser.HTMLParseError,请尝试更改解析器。
解析错误 HTMLParser.HTMLParseError: 格式错误的开始标记和 HTMLParser.HTMLParseError: 错误的结束标记均由 Python 的内置 HTML 解析器库生成,解决方案是安装 lxml 或 html5lib。
如果你遇到 SyntaxError: 语法无效(在行 ROOT_TAG_NAME = '[document]' 中),这是由于在 Python 3 下运行 Beautiful Soup 的旧 Python 2 版本,而没有转换代码。
ImportError 出现消息“No module named HTMLParser”是因为在 Python 3 中使用了旧的 Python 2 版 BeautifulSoup。
同时,ImportError:No module named html.parser - 是在 Python 2 中运行 Python 3 版本的 BeautifulSoup 导致的。
如果您收到 ImportError:No module named BeautifulSoup - 是因为在尚未安装 BS3 的系统上运 Beautiful Soup 3 代码。或者,不知道包名称已更改为 bs4,编写了 Beautiful Soup 4 代码。
最后,ImportError:No module named bs4 - 也可能是因为尝试在尚未安装 BS4 的系统上运行 Beautiful Soup 4 代码。
Beautiful Soup - Porting Old Code
你可以对来自 Beautiful Soup 的早期版本中的代码进行更改,使之与最新版本兼容,在导入语句中进行以下更改 -
Example
from BeautifulSoup import BeautifulSoup
#becomes this:
from bs4 import BeautifulSoup
如果你遇到了 ImportError “No module named BeautifulSoup”,这意味着你尝试运行 Beautiful Soup 3 代码,但是你只安装了 Beautiful Soup 4。同样地,如果你遇到了 ImportError “No module named bs4”,是因为你尝试运行 Beautiful Soup 4 代码,但是你只安装了 Beautiful Soup 3。
Beautiful Soup 3 使用了 Python 的 SGMLParser,这是一个在 Python 3.0 中已被删除的模块。Beautiful Soup 4 默认使用 html.parser,但是你也可以使用 lxml 或 html5lib。
尽管 BS4 基本上与 BS3 向后兼容,但它的很多方法已被弃用且赋予了新的名称,以便符合 PEP 8 合规要求。
这里有一些示例 -
replaceWith -> replace_with
findAll -> find_all
findNext -> find_next
findParent -> find_parent
findParents -> find_parents
findPrevious -> find_previous
getText -> get_text
nextSibling -> next_sibling
previousSibling -> previous_sibling
Beautiful Soup - contents Property
Example 1
标签对象的内容 -
from bs4 import BeautifulSoup
markup = '''
<div id="Languages">
<p>Java</p>
<p>Python</p>
<p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.div
print (tag.contents)
Example 2
文档的整个内容 -
from bs4 import BeautifulSoup, NavigableString
markup = '''
<div id="Languages">
<p>Java</p> <p>Python</p> <p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
print (soup.contents)
Example 3
请注意, NavigableString 对象没有内容属性。如果我们尝试访问它会引发 AttributeError。
from bs4 import BeautifulSoup, NavigableString
markup = '''
<div id="Languages">
<p>Java</p> <p>Python</p> <p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.p
s=tag.contents[0]
print (s.contents)
Output
Traceback (most recent call last):
File "C:\Users\user\BeautifulSoup\2.py", line 11, in <module>
print (s.contents)
^^^^^^^^^^
File "C:\Users\user\BeautifulSoup\Lib\site-packages\bs4\element.py", line 984, in __getattr__
raise AttributeError(
AttributeError: 'NavigableString' object has no attribute 'contents'
Beautiful Soup - children Property
Method Description
Beautiful Soup 库中的 Tag 对象具有 children 属性。它返回用于迭代直接的子元素和文本节点(即 Navigable String)的生成器。
Example 1
from bs4 import BeautifulSoup, NavigableString
markup = '''
<div id="Languages">
<p>Java</p> <p>Python</p> <p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.div
children = tag.children
for child in children:
print (child)
Example 2
soup 对象也拥有 children 属性。
from bs4 import BeautifulSoup, NavigableString
markup = '''
<div id="Languages">
<p>Java</p> <p>Python</p> <p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
children = soup.children
for child in children:
print (child)
Example 3
在以下示例中,我们将 NavigableString 对象追加到 <p> 标记并获取子项列表。
from bs4 import BeautifulSoup, NavigableString
markup = '''
<div id="Languages">
<p>Java</p> <p>Python</p> <p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
soup.p.extend(['and', 'JavaScript'])
children = soup.p.children
for child in children:
print (child)
Beautiful Soup - string Property
Method Description
在 Beautiful Soup 中,soup 和 Tag 对象具有一个便利属性 - string 属性。它返回 PageElement、Soup 或 Tag 中的单个字符串。如果此元素只有一个字符串子项,那么将返回与之对应的 NavigableString。如果这个元素有一个子标签,返回值是子标签的“string”属性,如果元素本身是一个字符串(没有子项),那么 string 属性将返回 None。
Example 1
以下代码有一个 HTML 字符串,其中包含一个 <div> 标签,该标签包含三个 <p> 元素。我们找到第一个 <p> 标签的 string 属性。
from bs4 import BeautifulSoup, NavigableString
markup = '''
<div id="Languages">
<p>Java</p> <p>Python</p> <p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.p
navstr = tag.string
print (navstr, type(navstr))
nav_str = str(navstr)
print (nav_str, type(nav_str))
Output
Java <class 'bs4.element.NavigableString'>
Java <class 'str'>
string 属性返回一个 NavigableString。它可以使用 str() 函数强制转换为一个常规的 Python 字符串
Beautiful Soup - strings Property
Method Description
对于包含多个子级的任何页面元素,可以通过 strings 属性获取每个子级的内部文本。与 string 属性不同,strings 处理元素包含多个子级的情况。strings 属性返回生成器对象。它会生成对应于每个子元素的 NavigableStrings 序列。
Example 1
你可以为汤对象和标记对象检索 strings 属性的值。在以下示例中,检查了汤对象的 stings 属性。
from bs4 import BeautifulSoup, NavigableString
markup = '''
<div id="Languages">
<p>Java</p> <p>Python</p> <p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
print ([string for string in soup.strings])
Output
['\n', '\n', 'Java', ' ', 'Python', ' ', 'C++', '\n', '\n']
注意列表中的换行符和空格。我们可以使用 stripped_strings 属性删除它们。
Beautiful Soup - stripped_strings Property
Method Description
Tag/Soup 对象的 stripped_strings 属性给出了与 strings 属性类似的返回结果,但去除了额外的换行符和空格。因此,可以说 stripped_strings 属性造成了对象中属于使用对象的内部元素的可遍历字符串对象的生成器。
Example 1
在下面的示例中,BeautifulSoup 对象中解析的文档树中所有元素的字符串在应用剥离操作后被显示。
from bs4 import BeautifulSoup, NavigableString
markup = '''
<div id="Languages">
<p>Java</p> <p>Python</p> <p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
print ([string for string in soup.stripped_strings])
Beautiful Soup - descendants Property
Method Description
在 Beautiful Soup API 中,您可以使用 PageElement 对象的 descendants 属性遍历其下的所有子元素列表。此属性返回一个生成器对象,可以通过该对象以广度优先的顺序检索子元素。
在搜索树结构时,广度优先遍历从树根开始,并在继续进入下一深度级别的节点之前,探索当前深度处的所有节点。
Example 1
在下面的代码中,我们有一个带有嵌套无序列表标记的 HTML 文档。我们以广度优先的方式解析子元素。
html = '''
<ul id='outer'>
<li class="mainmenu">Accounts</li>
<ul>
<li class="submenu">Anand</li>
<li class="submenu">Mahesh</li>
</ul>
<li class="mainmenu">HR</li>
<ul>
<li class="submenu">Anil</li>
<li class="submenu">Milind</li>
</ul>
</ul>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.find('ul', {'id': 'outer'})
tags = soup.descendants
for desc in tags:
print (desc)
Output
<ul id="outer">
<li class="mainmenu">Accounts</li>
<ul>
<li class="submenu">Anand</li>
<li class="submenu">Mahesh</li>
</ul>
<li class="mainmenu">HR</li>
<ul>
<li class="submenu">Anil</li>
<li class="submenu">Milind</li>
</ul>
</ul>
<li class="mainmenu">Accounts</li>
Accounts
<ul>
<li class="submenu">Anand</li>
<li class="submenu">Mahesh</li>
</ul>
<li class="submenu">Anand</li>
Anand
<li class="submenu">Mahesh</li>
Mahesh
<li class="mainmenu">HR</li>
HR
<ul>
<li class="submenu">Anil</li>
<li class="submenu">Milind</li>
</ul>
<li class="submenu">Anil</li>
Anil
<li class="submenu">Milind</li>
Milind
Beautiful Soup - parent Property
Method Description
BeautifulSoup库中的parent属性返回所述PegeElement的直接父元素。parents属性返回的值的类型是Tag对象。对于BeautifulSoup对象,其父级是文档对象
Example 1
此示例使用.parent属性来查找示例HTML字符串中第一个<p>标签的直接父元素。
html = """
<html>
<head>
<title>TutorialsPoint</title>
</head>
<body>
<p>Hello World</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.p
print (tag.parent.name)
Example 2
在以下示例中,我们看到<title>标签封闭在<head>标签内。因此,<title>标签的parent属性返回<head>标签。
html = """
<html>
<head>
<title>TutorialsPoint</title>
</head>
<body>
<p>Hello World</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.title
print (tag.parent)
Example 3
Python的内置HTML解析器的行为与html5lib和lxml解析器略有不同。内置解析器不会尝试从提供的字符串中构建一个完美的文档。如果字符串中不存在的话,它不会添加附加的父标签,如body或html。另一方面,html5lib和lxml解析器会添加这些标签以使文档成为一个完美的HTML文档。
html = """
<p><b>Hello World</b></p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
print (soup.p.parent.name)
soup = BeautifulSoup(html, 'html5lib')
print (soup.p.parent.name)
Beautiful Soup - parents Property
Method Description
BeautifulSoup 库中的 parents 属性以递归方式检索所述 PegeElement 的所有父元素。parents 属性返回的值的类型是一个生成器,借助该生成器,我们可以列出从下到上的父元素。
Example 1
此示例使用 .parents 从深入埋藏在文档中的 <a> 标记跳转到文档的最顶端。在下面的代码中,我们将跟踪示例 HTML 字符串中第一个 <p> 标记的父标记。
html = """
<html><head><title>TutorialsPoint</title></head>
<body>
<p>Hello World</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.p
for element in tag.parents:
print (element.name)
Example 2
在下面的示例中,我们可以看到 <b> 标记被包含在 <p> 标记里面。它上方的两个 div 标记有一个 id 属性。我们尝试只打印那些具有 id 属性的元素。has_attr() 方法用于此目的。
html = """
<div id="outer">
<div id="inner">
<p>Hello<b>World</b></p>
</div>
</div>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.b
for parent in tag.parents:
if parent.has_attr("id"):
print(parent["id"])
Beautiful Soup - next_sibling Property
Example 1
index.html 工资页面由一个 HTML 表单组成,其中包含三个具有 name 属性的输入元素。在下面的示例中,找到了 name 属性为 nm 的输入标记的下一个兄弟元素。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.find('input', {'name':'age'})
print (tag.find_previous())
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.find('input', {'id':'nm'})
sib = tag.next_sibling
print (sib)
Example 2
在下一个示例中,我们有一个 HTML 文档,其中包含 <p> 标记内的几个标记。next_sibling 属性返回其中 <b> 标记旁边的标记。
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p><b>Hello</b><i>Python</i></p>", 'html.parser')
tag1 = soup.b
print ("next:",tag1.next_sibling)
Example 3
考虑以下文档中的 HTML 字符串。它有两级 <p> 标记。第一个 <p> 标记的下一个兄弟元素应提供第二个 <p> 标记的内容。
html = '''
<p><b>Hello</b><i>Python</i></p>
<p>TutorialsPoint</p>
'''
soup = BeautifulSoup(html, 'html.parser')
tag1 = soup.p
print ("next:",tag1.next_sibling)
Beautiful Soup - previous_sibling Property
Method Description
在同一缩进级别上出现的 HTML 标签称为同级标签。PageElement 的 previous_sibling 属性返回一个前一个标签(出现在当前标签之前的标签),该标签处于同一级别或位于相同父项下。此属性封装了 find_previous_sibling() 方法。
Example 1
在以下代码中,HTML 字符串包含在 <p> 标记中的两个相邻标记。它显示在 <b> 标记之前出现的兄弟标记。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup("<p><b>Hello</b><i>Python</i></p>", 'html.parser')
tag = soup.i
sibling = tag.previous_sibling
print (sibling)
Example 2
我们使用 index.html 文件进行解析。该页面包含带有三个输入元素的 HTML 表单。哪个元素是具有 id 属性为 age 的输入元素的前一兄弟元素?以下代码显示了它:
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.find('input', {'id':'age'})
sib = tag.previous_sibling.previous_sibling
print (sib)
Beautiful Soup - next_siblings Property
Method Description
在相同缩进级别出现的 HTML 标签被称为兄弟标签。Beautiful Soup 中的 next_siblings 属性返回用于迭代相同父元素下的所有后续标签和字符串的生成器对象。
Example 1
在 index.html 中的 HTML 表单代码包含三个输入元素。以下脚本使用 next_siblings 属性来收集 id 属性为 nm 的输入元素的下一个兄弟元素
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.find('input', {'id':'nm'})
siblings = tag.next_siblings
print (list(siblings))
Output
['\n', <input id="age" name="age" type="text"/>, '\n', <input id="marks" name="marks" type="text"/>, '\n']
Example 2
让我们为此目的使用以下 HTML 片段:
使用以下代码遍历下一个兄弟元素标签。
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p><b>Excellent</b><i>Python</i><u>Tutorial</u></p>", 'html.parser')
tag1 = soup.b
print ("next siblings:")
for tag in tag1.next_siblings:
print (tag)
Example 3
下一个示例显示 <head> 标签只有 body 标签这一个下一个兄弟元素。
html = '''
<html>
<head>
<title>Hello</title>
</head>
<body>
<p>Excellent</p><p>Python</p><p>Tutorial</p>
</body>
</head>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tags = soup.head.next_siblings
print ("next siblings:")
for tag in tags:
print (tag)
Beautiful Soup - previous_siblings Property
Method Description
在同一缩进级别上出现的 HTML 标签称为同级标签。Beautiful Soup 中的 previous_siblings 属性返回一个生成器对象,用于迭代当前标签之前的同级标签和字符串,它们位于相同父项下。它给出的输出与 find_previous_siblings() 方法类似。
Example 1
以下示例解析给定的 HTML 字符串,其中有一些标签嵌入在外部 <p> 标签中。我们借助 previous_siblings 属性获取了下划线标签的前一个同级标签。
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p><b>Excellent</b><i>Python</i><u>Tutorial</u></p>", 'html.parser')
tag1 = soup.u
print ("previous siblings:")
for tag in tag1.previous_siblings:
print (tag)
Example 2
在以下示例使用的 index.html 文件中,HTML 表单中存在三个输入元素。我们找出与 id 标记为 marks 的同级标签中位于 <form> 标签下的同级标签。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.find('input', {'id':'marks'})
sibs = tag.previous_siblings
print ("previous siblings:")
for sib in sibs:
print (sib)
Output
previous siblings:
<input id="age" name="age" type="text"/>
<input id="nm" name="name" type="text"/>
Example 3
<html> 的顶级标签始终存在两个同级标签——head 和 body。因此,<body> 标签只有一个前一个同级标签,即 head,如下代码所示:
html = '''
<html>
<head>
<title>Hello</title>
</head>
<body>
<p>Excellent</p><p>Python</p><p>Tutorial</p>
</body>
</head>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tags = soup.body.previous_siblings
print ("previous siblings:")
for tag in tags:
print (tag)
Beautiful Soup - next_element Property
Method Description
在 Beautiful Soup 库中,next_element 属性返回紧邻当前 PageElement 的 Tag 或 NavigableString,即使它位于父树之外。还有一个具有类似行为的 next 属性
Example 1
在从给定 HTML 字符串解析的文档树中,我们找到 <b> 标记的 next_element
html = '''
<p><b>Excellent</b><p>Python</p><p id='id1'>Tutorial</p></p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
tag = soup.b
print (tag)
nxt = tag.next_element
print ("Next:",nxt)
nxt = tag.next_element.next_element
print ("Next:",nxt)
Output
<b>Excellent</b>
Next: Excellent
Next: <p>Python</p>
输出有点奇怪,因为 <b>Excellent</b> 的下一个元素显示为“Excellent”,这是因为内部字符串被注册为下一个元素。若要将所需结果 (<p>Python</p>) 作为下一个元素,请提取内部 NavigableString 对象的 next_element 属性。
Example 2
BeautifulSoup PageElements 还支持类似于 next_element 属性的 next 属性
html = '''
<p><b>Excellent</b><p>Python</p><p id='id1'>Tutorial</p></p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
tag = soup.b
print (tag)
nxt = tag.next
print ("Next:",nxt)
nxt = tag.next.next
print ("Next:",nxt)
Beautiful Soup - previous_element Property
Method Description
在 Beautiful Soup 库中,previous_element 属性返回紧接在当前 PageElement 之前的 Tag 或 NavigableString,即使它不在父级树中。还有 previous 属性,类似的行为
Example 1
我们从给定 HTML 字符串中解析出的文档树中, 找到 <p id='id1'> 标签的 previous_element。
html = '''
<p><b>Excellent</b><p>Python</p><p id='id1'>Tutorial</p></p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
tag = soup.find('p', id='id1')
print (tag)
pre = tag.previous_element
print ("Previous:",pre)
pre = tag.previous_element.previous_element
print ("Previous:",pre)
Output
<p id="id1">Tutorial</p>
Previous: Python
Previous: <p>Python</p>
输出有点奇怪,因为显示的 previous 元素是 Python,那是因为内部字符串被注册为 previous 元素。如要获取预期的结果(<p>Python</p>)作为 previous 元素,请获取内在 NavigableString 对象的 previous_element 特性。
Example 2
BeautifulSoup PageElements 还支持 previous 特性,它类似于 previous_element 特性。
html = '''
<p><b>Excellent</b><p>Python</p><p id='id1'>Tutorial</p></p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
tag = soup.find('p', id='id1')
print (tag)
pre = tag.previous
print ("Previous:",pre)
pre = tag.previous.previous
print ("Previous:",pre)
Beautiful Soup - next_elements Property
Example 1
next_elements 属性返回出现在文档字符串中 <b> 标签之后的标签和 NavibaleStrings,如下所示:
html = '''
<p><b>Excellent</b><p>Python</p><p id='id1'>Tutorial</p></p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.find('b')
nexts = tag.next_elements
print ("Next elements:")
for next in nexts:
print (next)
Example 2
所有出现在 <p> 标签之后的元素列在下面:
from bs4 import BeautifulSoup
html = '''
<p>
<b>Excellent</b><i>Python</i>
</p>
<u>Tutorial</u>
'''
soup = BeautifulSoup(html, 'html.parser')
tag1 = soup.find('p')
print ("Next elements:")
print (list(tag1.next_elements))
Output
Next elements:
['\n', <b>Excellent</b>, 'Excellent', <i>Python</i>, 'Python', '\n', '\n', <u>Tutorial</u>, 'Tutorial', '\n']
Beautiful Soup - previous_elements Property
Example 1
previous_elements 属性返回在下文档字符串中出现在 <p> 标签前的标记和 NavibaleStrings:
html = '''
<p><b>Excellent</b><p>Python</p><p id='id1'>Tutorial</p></p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.find('p', id='id1')
pres = tag.previous_elements
print ("Previous elements:")
for pre in pres:
print (pre)
Output
Previous elements:
Python
<p>Python</p>
Excellent
<b>Excellent</b>
<p><b>Excellent</b><p>Python</p><p id="id1">Tutorial</p></p>
Example 2
出现在 <u> 标签之前的所有元素如下:
from bs4 import BeautifulSoup
html = '''
<p>
<b>Excellent</b><i>Python</i>
</p>
<u>Tutorial</u>
'''
soup = BeautifulSoup(html, 'html.parser')
tag1 = soup.find('u')
print ("previous elements:")
print (list(tag1.previous_elements))
Output
previous elements:
['\n', '\n', 'Python', <i>Python</i>, 'Excellent', <b>Excellent</b>, '\n', <p>
<b>Excellent</b><i>Python</i>
</p>, '\n']
Beautiful Soup - find() Method
Parameters
name − 对标记名称的筛选。
attrs − 对属性值进行筛选的字典。
recursive − 如果为 True,则 find() 将执行递归搜索。否则,仅考虑直接子元素。
limit − 在找到指定数量的出现次数后停止寻找。
kwargs − 对属性值进行筛选的字典。
Example 1
让我们为了这个目的使用以下 HTML 脚本(作为 index.html):
<html>
<head>
<title>TutorialsPoint</title>
</head>
<body>
<form>
<input type = 'text' id = 'nm' name = 'name'>
<input type = 'text' id = 'age' name = 'age'>
<input type = 'text' id = 'marks' name = 'marks'>
</form>
</body>
</html>
下面的 Python 代码找到了 id 为 nm 的元素:
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
obj = soup.find(id = 'nm')
print (obj)
Beautiful Soup - find_all() Method
Parameters
name − 对标记名称的筛选。
attrs − 对属性值进行筛选的字典。
recursive − 如果为 True,则 find() 将执行递归搜索。否则,仅考虑直接子元素。
limit − 在找到指定数量的出现次数后停止寻找。
kwargs − 对属性值进行筛选的字典。
Example 1
当我们能够以 name 的形式传递一个值时,Beautiful Soup 才会考虑具有特定名称的标签。文本字符串会被忽略,与不匹配名称的标签也会被忽略。在此示例中,我们将 title 传递给 find_all() 方法。
from bs4 import BeautifulSoup
html = open('index.html')
soup = BeautifulSoup(html, 'html.parser')
obj = soup.find_all('input')
print (obj)
Output
[<input id="nm" name="name" type="text"/>, <input id="age" name="age" type="text"/>, <input id="marks" name="marks" type="text"/>]
Example 2
我们将在本示例中使用以下 HTML 脚本:
<html>
<body>
<h2>Departmentwise Employees</h2>
<ul id="dept">
<li>Accounts</li>
<ul id='acc'>
<li>Anand</li>
<li>Mahesh</li>
</ul>
<li>HR</li>
<ol id="HR">
<li>Rani</li>
<li>Ankita</li>
</ol>
</ul>
</body>
</html>
我们能够向 find_all() 方法的 name 参数中传递一个字符串。使用字符串,你可以搜索字符串而非标签。你可以传递字符串、正则表达式、列表、函数或真值。
在本示例中,一个函数被传递给了 name 参数。所有以“A”开头的名称都会由 find_all() 方法返回。
from bs4 import BeautifulSoup
def startingwith(ch):
return ch.startswith('A')
soup = BeautifulSoup(html, 'html.parser')
lst=soup.find_all(string=startingwith)
print (lst)
Beautiful Soup - find_parents() Method
Example 1
我们将在本示例中使用以下 HTML 脚本:
<html>
<body>
<h2>Departmentwise Employees</h2>
<ul id="dept">
<li>Accounts</li>
<ul id='acc'>
<li>Anand</li>
<li>Mahesh</li>
</ul>
<li>HR</li>
<ol id="HR">
<li>Rani</li>
<li>Ankita</li>
</ol>
</ul>
</body>
</html>
Beautiful Soup - find_parent() Method
Example 1
我们将在本示例中使用以下 HTML 脚本:
<html>
<body>
<h2>Departmentwise Employees</h2>
<ul id="dept">
<li>Accounts</li>
<ul id='acc'>
<li>Anand</li>
<li>Mahesh</li>
</ul>
<li>HR</li>
<ol id="HR">
<li>Rani</li>
<li>Ankita</li>
</ol>
</ul>
</body>
</html>
在以下示例中,我们找到包含字符串“HR”的标记的名称。
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
obj=soup.find(string='HR')
print (obj.find_parent().name)
Beautiful Soup - find_next_siblings() Method
Method Description
find_next_siblings() 方法类似于 next_sibling 属性。它查找此 PageElement 同一级别内所有符合给定条件且在文档中后续出现的兄弟元素。
Parameters
-
name − 对标记名称的筛选。
-
attrs − 对属性值进行筛选的字典。
-
string − 要搜索的字符串(而非标记)。
-
limit − 在找到指定数量的出现次数后停止寻找。
-
kwargs − 对属性值进行筛选的字典。
Example 1
让我们为此目的使用以下 HTML 片段:
<p>
<b>
Excellent
</b>
<i>
Python
</i>
<u>
Tutorial
</u>
</p>
在下面的代码中,我们尝试查找所有的 <b> 标签的同级元素。在 HTML 字符串中有两个同级的标签用于抓取。
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p><b>Excellent</b><i>Python</i><u>Tutorial</u></p>", 'html.parser')
tag1 = soup.find('b')
print ("next siblings:")
for tag in tag1.find_next_siblings():
print (tag)
Beautiful Soup - find_next_sibling() Method
Method Description
Beautiful Soup 中的 find_next_sibling() 方法查找与给定条件匹配的,且在文档中之后出现的,在这个 PageElement 中的同级中最接近的同级。此方法类似于 next_sibling 属性。
Example 1
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p><b>Hello</b><i>Python</i></p>", 'html.parser')
tag1 = soup.find('b')
print ("next:",tag1.find_next_sibling())
Beautiful Soup - find_previous_siblings() Method
Method Description
Beautiful Soup包中的find_previous_siblings()方法返回所有在文档中出现在此PAgeElement更前面的兄弟,并且符合给定的条件。
Parameters
-
name − 对标记名称的筛选。
-
attrs − 对属性值进行筛选的字典。
-
string - 具有特定文本的 NavigableString 的过滤器。
-
limit − 找到大量结果后停止查找。
-
kwargs − 对属性值进行筛选的字典。
Example 1
让我们为此目的使用以下 HTML 片段:
<p>
<b>
Excellent
</b>
<i>
Python
</i>
<u>
Tutorial
</u>
</p>
在下面的代码中,我们尝试查找所有 <> 标记的同级元素。在用于搜索的 HTML 字符串中,同级别还有两个标记。
from bs4 import BeautifulSoup
soup = BeautifulSoup("<p><b>Excellent</b><i>Python</i><u>Tutorial</u></p>", 'html.parser')
tag1 = soup.find('u')
print ("previous siblings:")
for tag in tag1.find_previous_siblings():
print (tag)
Example 2
网页(index.html)有一个 HTML 表单,其中包含三个输入元素。我们使用 id 属性为 marks 找到一个输入元素,然后查找其之前的兄弟元素。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.find('input', {'id':'marks'})
sibs = tag.find_previous_sibling()
print (sibs)
Example 3
HTML 字符串中有两个 <p> 标记。我们找出了 id 属性为 id1 的标记之前的兄弟元素。
html = '''
<p><b>Excellent</b><p>Python</p><p id='id1'>Tutorial</p></p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.find('p', id='id1')
ptags = tag.find_previous_siblings()
for ptag in ptags:
print ("Tag: {}, Text: {}".format(ptag.name, ptag.text))
Beautiful Soup - find_previous_sibling() Method
Method Description
Beautiful Soup中的find_previous_sibling()方法返回最早出现在文档中并且符合给定条件的与该PageElement最接近的兄弟元素。
Parameters
-
name − 对标记名称的筛选。
-
attrs − 对属性值进行筛选的字典。
-
string - 具有特定文本的 NavigableString 的过滤器。
-
kwargs − 对属性值进行筛选的字典。
Example 1
从以下示例中使用的HTML字符串,我们可以找出标签名为“u”的<i>标签的前一兄弟元素。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup("<p><u>Excellent</u><b>Hello</b><i>Python</i></p>", 'html.parser')
tag = soup.i
sibling = tag.find_previous_sibling('u')
print (sibling)
Example 2
网页(index.html)有一个HTML表单,其中包含三个输入元素。我们通过id属性找到marks,然后找到其前一个兄弟,该兄弟的id设置为nm。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.find('input', {'id':'marks'})
sib = tag.find_previous_sibling(id='nm')
print (sib)
Example 3
在下面的代码中,HTML字符串有两个<p>元素和一个位于外部<p>标签內的字符串。我们使用find_previous_string()方法来查找与<p>Tutorial</p>标签处于兄弟关系的NavigableString对象。
html = '''
<p>Excellent<p>Python</p><p>Tutorial</p></p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.find('p', string='Tutorial')
ptag = tag.find_previous_sibling(string='Excellent')
print (ptag, type(ptag))
Beautiful Soup - find_all_next() Method
Method Description
Beautiful Soup 中的 find_all_next() 方法找到与给定条件匹配并出现在文档中的此元素后面的所有 PageElements。此方法返回标记或 NavigableString 对象,其方法的参数与 find_all() 中的参数完全相同。
Parameters
-
name − 对标记名称的筛选。
-
attrs − 对属性值进行筛选的字典。
-
recursive − 如果为 True,则 find() 将执行递归搜索。否则,仅考虑直接子元素。
-
limit − 在找到指定数量的出现次数后停止寻找。
-
kwargs − 对属性值进行筛选的字典。
Example 1
使用 index.html 作为此示例的 HTML 文档,我们首先定位 <form> 标签并使用 find_all_next() 方法收集它之后的所有元素。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.form
tags = tag.find_all_next()
print (tags)
Output
[<input id="nm" name="name" type="text"/>, <input id="age" name="age" type="text"/>, <input id="marks" name="marks" type="text"/>]
Example 2
在此,我们对 find_all_next() 方法应用筛选器,以收集 <form> 之后的、ID 为 nm 或 age 的所有标签。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.form
tags = tag.find_all_next(id=['nm', 'age'])
print (tags)
Beautiful Soup - find_next() Method
Method Description
Beautiful soup 中的 find_next() 方法将找到与给定条件匹配的第一个 PageElement,并且出现在文档中较后的部分。返回文档中当前标签后面的第一个标签或 NavigableString。与所有其他 find 方法一样,此方法具有以下语法 -
Parameters
-
name − 对标记名称的筛选。
-
attrs − 对属性值进行筛选的字典。
-
string - 具有特定文本的 NavigableString 的过滤器。
-
kwargs − 对属性值进行筛选的字典。
Example 1
此示例使用了带以下脚本的网页 index.html
<html>
<head>
<title>TutorialsPoint</title>
</head>
<body>
<h1>TutorialsPoint</h1>
<form>
<input type = 'text' id = 'nm' name = 'name'>
<input type = 'text' id = 'age' name = 'age'>
<input type = 'text' id = 'marks' name = 'marks'>
</form>
</body>
</html>
我们首先找到 <form> 标签,然后再找到其旁边的标签。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.h1
print (tag.find_next())
Output
<form>
<input id="nm" name="name" type="text"/>
<input id="age" name="age" type="text"/>
<input id="marks" name="marks" type="text"/>
</form>
Example 2
在这个示例中,我们首先找到 name='age' 的 <input> 标签,然后获取其下一个标签。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.find('input', {'name':'age'})
print (tag.find_next())
Beautiful Soup - find_all_previous() Method
Method Description
Beautiful Soup 中的 find_all_previous() 方法会向后查看此 PageElement 文档,并查找与给定条件匹配且出现在当前元素之前的所有 PageElements。它返回一个 ResultsSet 的 PageElements,该结果集出现在文档中的当前标记之前。与所有其他查找方法一样,此方法具有以下语法:
Parameters
-
name − 对标记名称的筛选。
-
attrs − 对属性值进行筛选的字典。
-
string - 具有特定文本的 NavigableString 的过滤器。
-
limit − 找到大量结果后停止查找。
-
kwargs − 对属性值进行筛选的字典。
Return Value
find_all_previous() 方法返回一个 Tag 或 NavigableString 对象的结果集。如果 limit 参数为 1,则该方法等效于 find_previous() 方法。
Example 1
在此示例中,显示了出现在第一个 input 标记之前的每个对象的 name 属性。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.find('input')
for t in tag.find_all_previous():
print (t.name)
Example 2
在所考虑的 HTML 文档(index.html)中,有三个输入元素。使用以下代码,我们打印 marks.nm 属性之前的 <input> 标记之前所有标记的标记名称。为了区分之前的两个输入标记,我们还会打印 attrs 属性。请注意,其他标记没有任何属性。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.find('input', {'name':'marks'})
pretags = tag.find_all_previous()
for pretag in pretags:
print (pretag.name, pretag.attrs)
Output
input {'type': 'text', 'id': 'age', 'name': 'age'}
input {'type': 'text', 'id': 'nm', 'name': 'name'}
form {}
h1 {}
body {}
title {}
head {}
html {}
Beautiful Soup - find_previous() Method
Method Description
Beautiful Soup 中的 find_previous() 方法从该 PageElement 文档中向后查找并查找与给定条件匹配的第一个 PageElement。它返回在文档中当前标签之前的第一个标签或 NavigableString。与所有其他查找方法一样,该方法具有以下语法 -
Parameters
-
name − 对标记名称的筛选。
-
attrs − 对属性值进行筛选的字典。
-
string - 具有特定文本的 NavigableString 的过滤器。
-
kwargs − 对属性值进行筛选的字典。
Example 1
在下面的示例中,我们尝试查找 <body> 标签之前的对象。碰巧是 <title> 元素。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.body
print (tag.find_previous())
Example 2
在该示例中使用的 HTML 文档中有三个输入元素。下面的代码找到 name 属性 = age 的输入元素并查找其前面的元素。
from bs4 import BeautifulSoup
fp = open("index.html")
soup = BeautifulSoup(fp, 'html.parser')
tag = soup.find('input', {'name':'age'})
print (tag.find_previous())
Beautiful Soup - select() Method
Method Description
在 BeautifulSoup 库中,select() 方法是抓取 HTML/XML 文档的一个重要工具。与 find() 和 find_*() 方法类似,select() 方法也有助于找到满足给定条件的元素。根据给定的 CSS 选择器(作为参数)在文档树中选择元素。
Beautiful Soup 还具有 select_one() 方法。select() 和 select_one() 之间的区别在于,select() 返回属于 PageElement 并由 CSS 选择器表征的所有元素的 ResultSet;而 select_one() 返回满足基于 CSS 选择器选择标准的元素的第一个出现。
在 BeautifulSoup 4.7 版之前,select() 方法通常只支持常见的 CSS 选择器。从 4.7 版开始,BeautifulSoup 与 Soup Sieve CSS 选择器库集成在一起。因此,现在可以使用更多的选择器。在 4.12 版中,除了现有的便捷方法 select() 和 select_one() 之外,还添加了一个 .css 属性。
Parameters
-
selector − 包含 CSS 选择器的字符串。
-
limit − 找到此数量的结果后,停止查找。
-
kwargs − 要传递的关键字参数。
如果将限制参数设置为 1,它将等同于 select_one() 方法。
Return Value
select() 方法返回一个 Tag 对象的结果集。select_one() 方法返回一个单独的 Tag 对象。
Soup Sieve 库具有不同类型的 CSS 选择器。基本的 CSS 选择器为 −
-
类型选择器通过节点名称匹配元素。例如 −
tags = soup.select('div')
-
通用选择器(*)匹配任何类型的元素。示例 -
tags = soup.select('*')
-
ID 选择器基于元素的 id 属性来匹配元素。# 符号表示 ID 选择器。示例 -
tags = soup.select("#nm")
-
class 选择器基于 class 属性中包含的值来匹配元素。类名前缀为 . 符号是 CSS class 选择器。示例 -
tags = soup.select(".submenu")
Example: Type Selector
from bs4 import BeautifulSoup, NavigableString
markup = '''
<div id="Languages">
<p>Java</p> <p>Python</p> <p>C++</p>
</div>
'''
soup = BeautifulSoup(markup, 'html.parser')
tags = soup.select('div')
print (tags)
Example: ID selector
from bs4 import BeautifulSoup
html = '''
<form>
<input type = 'text' id = 'nm' name = 'name'>
<input type = 'text' id = 'age' name = 'age'>
<input type = 'text' id = 'marks' name = 'marks'>
</form>
'''
soup = BeautifulSoup(html, 'html.parser')
obj = soup.select("#nm")
print (obj)
Example: class selector
html = '''
<ul>
<li class="mainmenu">Accounts</li>
<ul>
<li class="submenu">Anand</li>
<li class="submenu">Mahesh</li>
</ul>
<li class="mainmenu">HR</li>
<ul>
<li class="submenu">Rani</li>
<li class="submenu">Ankita</li>
</ul>
</ul>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tags = soup.select(".mainmenu")
print (tags)
Beautiful Soup - append() Method
Method Description
Beautiful Soup 中的 append() 方法在当前标记对象的末尾添加给定的字符串或另一个标记。该 append() 方法的工作方式类似于 Python 的列表对象的 append() 方法。
Example 1
在以下示例中,HTML 脚本有一个 <p> 标记。使用 append() 附加文本。在以下示例中,HTML 脚本有一个 <p> 标记。使用 append() 附加文本。
from bs4 import BeautifulSoup
markup = '<p>Hello</p>'
soup = BeautifulSoup(markup, 'html.parser')
print (soup)
tag = soup.p
tag.append(" World")
print (soup)
Example 2
通过 append() 方法,你可以在现有标记的末尾添加新标记。首先使用 new_tag() 方法创建一个新标记对象,然后将其传递给 append() 方法。
from bs4 import BeautifulSoup, Tag
markup = '<b>Hello</b>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.b
tag1 = soup.new_tag('i')
tag1.string = 'World'
tag.append(tag1)
print (soup.prettify())
Beautiful Soup - extend() Method
Method Description
Beautiful Soup 中的 extend() 方法已从版本 4.7 起添加到 Tag 类中。它将列表中的所有元素添加到标记。此方法类似于标准 Python 列表的 extend() 方法 - 它接受一个字符串数组以附加到标记的内容中。
Beautiful Soup - NavigableString() Method
Method Description
bs4 包中的 NavigableString() 方法是 NavigableString 类的构造方法。NavigableString 表示解析文档的最内层子元素。此方法将常规 Python 字符串转换为 NavigableString。相反,内置的 str() 方法将 NavigableString 对象转换为 Unicode 字符串。
Example 1
在下面的代码中,HTML 字符串包含一个空的 <b> 标签。我们向其中添加一个 NavigableString 对象。
html = """
<p><b></b></p>
"""
from bs4 import BeautifulSoup, NavigableString
soup = BeautifulSoup(html, 'html.parser')
navstr = NavigableString("Hello World")
soup.b.append(navstr)
print (soup)
Example 2
在这个示例中,我们看到两个 NavigableString 对象被追加到一个空的 <b> 标签。标签响应 strings 属性而不是 string 属性。它是一种 NavigableString 对象的生成器。
html = """
<p><b></b></p>
"""
from bs4 import BeautifulSoup, NavigableString
soup = BeautifulSoup(html, 'html.parser')
navstr = NavigableString("Hello")
soup.b.append(navstr)
navstr = NavigableString("World")
soup.b.append(navstr)
for s in soup.b.strings:
print (s, type(s))
Example 3
如果我们访问了 <b> 标签对象的 stripped_strings 属性而不是 strings 属性,则会得到 Unicode 字符串的生成器,即 str 对象。
html = """
<p><b></b></p>
"""
from bs4 import BeautifulSoup, NavigableString
soup = BeautifulSoup(html, 'html.parser')
navstr = NavigableString("Hello")
soup.b.append(navstr)
navstr = NavigableString("World")
soup.b.append(navstr)
for s in soup.b.stripped_strings:
print (s, type(s))
Beautiful Soup - new_tag() Method
Beautiful Soup 库中的 new_tag() 方法会创建一个新的标记对象,该对象与一个现有的 BeautifulSoup 对象关联。您可以使用此工厂方法将新标记附加或插入到文档树中。
Parameters
-
name - 新标记的名称。
-
namespace - 新标记的 XML 命名空间的 URI,可选。
-
prefix - 新标记的 XML 命名空间的前缀,可选。
-
attrs - 此标记的属性值字典。
-
sourceline - 标记在源文档中被找到的行号。
-
sourcepos - 标记在
sourceline
中被找到的字符位置。 -
kwattrs - 新标记的属性值的关键字参数。
Example 1
以下示例演示了 new_tag() 方法的用法。<a> 元素的一个新标记。标记对象使用 href 和字符串属性初始化,然后插入到文档树中。
from bs4 import BeautifulSoup
soup = BeautifulSoup('<p>Welcome to <b>online Tutorial library</b></p>', 'html.parser')
tag = soup.new_tag('a')
tag.attrs['href'] = "www.tutorialspoint.com"
tag.string = "Tutorialspoint"
soup.b.insert_before(tag)
print (soup)
Output
<p>Welcome to <a href="www.tutorialspoint.com">Tutorialspoint</a><b>online Tutorial library</b></p>
Example 2
在以下示例中,我们有一个有两个输入元素的 HTML 表单。我们创建了一个新的输入标记并将其附加到表单标记。
html = '''
<form>
<input type = 'text' id = 'nm' name = 'name'>
<input type = 'text' id = 'age' name = 'age'>
</form>'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
tag = soup.form
newtag=soup.new_tag('input', attrs={'type':'text', 'id':'marks', 'name':'marks'})
tag.append(newtag)
print (soup)
Output
<form>
<input id="nm" name="name" type="text"/>
<input id="age" name="age" type="text"/>
<input id="marks" name="marks" type="text"/></form>
Beautiful Soup - insert() Method
Method Description
Beautiful Soup 中的 insert() 方法在标签元素的子项列表中,在指定位置添加一个元素。Beautiful Soup 中的 insert() 方法的行为,类似于在 Python 列表对象上的 insert() 方法。
Example 1
在以下示例中,新字符串被添加到 <b> 标记,位置为 1。结果解析的文档显示结果。
from bs4 import BeautifulSoup, NavigableString
markup = '<b>Excellent </b><u>from TutorialsPoint</u>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.b
tag.insert(1, "Tutorial ")
print (soup.prettify())
Example 2
在下面的示例中,insert() 方法被用于依次将列表中的字符串插入到 HTML 标记中的 <p> 标签。
from bs4 import BeautifulSoup, NavigableString
markup = '<p>Excellent Tutorials from TutorialsPoint</p>'
soup = BeautifulSoup(markup, 'html.parser')
langs = ['Python', 'Java', 'C']
i=0
for lang in langs:
i+=1
tag = soup.new_tag('p')
tag.string = lang
soup.p.insert(i, tag)
print (soup.prettify())
Beautiful Soup - insert_before() Method
Method Description
Beautiful soup 中的 insert_before() 方法将标签或字符串插入解析树中其他内容的正前方。插入的元素成为 this one 的直接前继元素。插入的元素可以是标签或字符串。
Example 1
以下示例将文本 "Here is an" 插入给定 HTML 标记字符串中的 "Excellent" 前方。
from bs4 import BeautifulSoup, NavigableString
markup = '<b>Excellent</b> Python Tutorial <u>from TutorialsPoint</u>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.b
tag.insert_before("Here is an ")
print (soup.prettify())
Example 2
您还可以在另一个标签前插入标签。请看这个示例。
from bs4 import BeautifulSoup, NavigableString
markup = '<P>Excellent <b>Tutorial</b> from TutorialsPoint</u>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.b
tag1 = soup.new_tag('b')
tag1.string = "Python "
tag.insert_before(tag1)
print (soup.prettify())
Beautiful Soup - insert_after() Method
Method Description
Beautiful 汤中的 insert_after() 方法在解析树中的某个元素后立即插入标签或字符串。插入的元素成为该元素的直接后继。插入的元素可以是标签或字符串。
Example 1
以下代码在第一个 <b> 标签后插入字符串"Python"。
from bs4 import BeautifulSoup
markup = '<p>An <b>Excellent</b> Tutorial <u>from TutorialsPoint</u>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.b
tag.insert_after("Python ")
print (soup.prettify())
Example 2
您还可以在另一个标签前插入标签。请看这个示例。
from bs4 import BeautifulSoup, NavigableString
markup = '<P>Excellent <b>Tutorial</b> from TutorialsPoint</p>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.b
tag1 = soup.new_tag('b')
tag1.string = "on Python "
tag.insert_after(tag1)
print (soup.prettify())
Example 3
可以在某个标签后插入多个标签或字符串。
from bs4 import BeautifulSoup, NavigableString
markup = '<P>Excellent <b>Tutorials</b> from TutorialsPoint</p>'
soup = BeautifulSoup(markup, 'html.parser')
tag = soup.p
tag1 = soup.new_tag('i')
tag1.string = 'and Java'
tag.insert_after("on Python", tag1)
print (soup.prettify())
Beautiful Soup - clear() Method
Method Description
Beautiful Soup 库中的 clear() 方法清除标签的内部内容,保持标签的完整性。如果存在子元素,将调用其 extract() 方法。如果 decompose 参数设置为 True,则调用 decompose() 方法,而不是 extract()。
Example 1
由于 clear() 方法在表示整个文档的 soup 对象上调用,因此所有内容都会被移除,文档将为空。
html = '''
<html>
<body>
<p>The quick, brown fox jumps over a lazy dog.</p>
<p>DJs flock by when MTV ax quiz prog.</p>
<p>Junk MTV quiz graced by fox whelps.</p>
<p>Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
soup.clear()
print(soup)
Example 2
在以下示例中,我们找到所有 <p> 标签并在每个标签上调用 clear() 方法。
html = '''
<html>
<body>
<p>The quick, brown fox jumps over a lazy dog.</p>
<p>DJs flock by when MTV ax quiz prog.</p>
<p>Junk MTV quiz graced by fox whelps.</p>
<p>Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
tags = soup.find_all('p')
for tag in tags:
tag.clear()
print(soup)
Example 3
我们在此清除 <body> 标签的内容,同时将 decompose 参数设置为 Tue。
html = '''
<html>
<body>
<p>The quick, brown fox jumps over a lazy dog.</p>
<p>DJs flock by when MTV ax quiz prog.</p>
<p>Junk MTV quiz graced by fox whelps.</p>
<p>Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
tags = soup.find('body')
ret = tags.clear(decompose=True)
print(soup)
Beautiful Soup - extract() Method
Method Description
Beautiful Soup 库中的 extract() 方法用于从文档树中移除标签或字符串。extract() 方法返回已移除的对象。它类似于 Python 列表中的 pop() 方法。
Example 1
html = '''
<div>
<p>Hello Python</p>
</div>
'''
from bs4 import BeautifulSoup
soup=BeautifulSoup(html, 'html.parser')
tag1 = soup.find("div")
tag2 = tag1.find("p")
ret = tag2.extract()
print ('Extracted:',ret)
print ('original:',soup)
Example 2
考虑以下 HTML 标记 -
<html>
<body>
<p> The quick, brown fox jumps over a lazy dog.</p>
<p> DJs flock by when MTV ax quiz prog.</p>
<p> Junk MTV quiz graced by fox whelps.</p>
<p> Bawds jog, flick quartz, vex nymphs./p>
</body>
</html>
以下为代码 -
from bs4 import BeautifulSoup
fp = open('index.html')
soup = BeautifulSoup(fp, 'html.parser')
tags = soup.find_all()
for tag in tags:
obj = tag.extract()
print ("Extracted:",obj)
print (soup)
Output
Extracted: <html>
<body>
<p> The quick, brown fox jumps over a lazy dog.</p>
<p> DJs flock by when MTV ax quiz prog.</p>
<p> Junk MTV quiz graced by fox whelps.</p>
<p> Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
Extracted: <body>
<p> The quick, brown fox jumps over a lazy dog.</p>
<p> DJs flock by when MTV ax quiz prog.</p>
<p> Junk MTV quiz graced by fox whelps.</p>
<p> Bawds jog, flick quartz, vex nymphs.</p>
</body>
Extracted: <p> The quick, brown fox jumps over a lazy dog.</p>
Extracted: <p> DJs flock by when MTV ax quiz prog.</p>
Extracted: <p> Junk MTV quiz graced by fox whelps.</p>
Extracted: <p> Bawds jog, flick quartz, vex nymphs.</p>
Example 3
您还可以将 extract() 方法与 find_next()、find_previous() 方法和 next_element、previous_element 属性一起使用。
html = '''
<div>
<p><b>Hello</b><b>Python</b></p>
</div>
'''
from bs4 import BeautifulSoup
soup=BeautifulSoup(html, 'html.parser')
tag1 = soup.find("b")
ret = tag1.next_element.extract()
print ('Extracted:',ret)
print ('original:',soup)
Beautiful Soup - decompose() Method
Method Description
decompose() 方法销毁当前元素及其子元素,因此元素从树中移除,将其擦除及其下的所有内容。你可以通过 decomposed
属性来检查元素是否已分解。如果已销毁,返回 True,否则返回 false。
Example 1
当我们对 BeautifulSoup 对象本身调用 descompose() 方法时,整个内容将被销毁。
html = '''
<html>
<body>
<p>The quick, brown fox jumps over a lazy dog.</p>
<p>DJs flock by when MTV ax quiz prog.</p>
<p>Junk MTV quiz graced by fox whelps.</p>
<p>Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
soup.decompose()
print ("decomposed:",soup.decomposed)
print (soup)
Output
decomposed: True
document: Traceback (most recent call last):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
TypeError: can only concatenate str (not "NoneType") to str
由于 soup 对象已分解,它返回 True,但是,你会得到如上所示的 TypeError。
Example 2
下面的代码使用 decompose() 方法,删除 HTML 字符串中所有出现的 <p> 标签。
html = '''
<html>
<body>
<p>The quick, brown fox jumps over a lazy dog.</p>
<p>DJs flock by when MTV ax quiz prog.</p>
<p>Junk MTV quiz graced by fox whelps.</p>
<p>Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
p_all = soup.find_all('p')
[p.decompose() for p in p_all]
print ("document:",soup)
Example 3
在此,我们从 HTML 文档树中找到 <body> 标签,并分解前一个元素,该元素恰好是 <title> 标签。生成的文档树中省略了 <title> 标签。
html = '''
<html>
<head>
<title>TutorialsPoint</title>
</head>
<body>
Hello World
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
tag = soup.body
tag.find_previous().decompose()
print ("document:",soup)
Beautiful Soup - replace_with() Method
Example 1
在这个示例中,<p> 标签被使用 replace_with() 方法替换为 <b>。
html = '''
<html>
<body>
<p>The quick, brown fox jumps over a lazy dog.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
tag1 = soup.find('p')
txt = tag1.string
tag2 = soup.new_tag('b')
tag2.string = txt
tag1.replace_with(tag2)
print (soup)
Example 2
你可以简单地通过对标签 string 对象调用 replace_with() 方法,将标签的内部文本替换为另一个字符串。
html = '''
<html>
<body>
<p>The quick, brown fox jumps over a lazy dog.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
tag1 = soup.find('p')
tag1.string.replace_with("DJs flock by when MTV ax quiz prog.")
print (soup)
Example 3
可用于替换的标签对象,可通过任意 find() 方法获得。在这里,我们替换 <p> 标签旁边的标签的文本。
html = '''
<html>
<body>
<p>The quick, <b>brown</b> fox jumps over a lazy dog.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
tag1 = soup.find('p')
tag1.find_next('b').string.replace_with('black')
print (soup)
Beautiful Soup - wrap() Method
Example 1
在这个例子中, <b> 标签被包装在 <div> 标签中。
html = '''
<html>
<body>
<p>The quick, <b>brown</b> fox jumps over a lazy dog.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
tag1 = soup.find('b')
newtag = soup.new_tag('div')
tag1.wrap(newtag)
print (soup)
Output
<html>
<body>
<p>The quick, <div><b>brown</b></div> fox jumps over a lazy dog.</p>
</body>
</html>
Beautiful Soup - unwrap() Method
Example 1
在以下示例中,从 HTML 字符串中移除 <b> 标签。
html = '''
<p>The quick, <b>brown</b> fox jumps over a lazy dog.</p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
tag1 = soup.find('b')
newtag = tag1.unwrap()
print (soup)
Example 2
下面的代码打印 unwrap() 方法的返回的值。
html = '''
<p>The quick, <b>brown</b> fox jumps over a lazy dog.</p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
tag1 = soup.find('b')
newtag = tag1.unwrap()
print (newtag)
Example 3
unwrap() 方法非常适合剥离标记,如下代码所示:
html = '''
<html>
<body>
<p>The quick, brown fox jumps over a lazy dog.</p>
<p>DJs flock by when MTV ax quiz prog.</p>
<p>Junk MTV quiz graced by fox whelps.</p>
<p>Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
#print (soup.unwrap())
for tag in soup.find_all():
tag.unwrap()
print (soup)
Beautiful Soup - smooth() Method
Method Description
在调用一系列修改解析树的方法后,可能会彼此相邻放置两个或更多 NavigableString 对象。 smooth() 方法通过合并连续的字符串来平滑此元素的子元素。在对树进行大量修改的操作后,这样做可以让可读输出看起来更自然。
Example 1
html ='''<html>
<head>
<title>TutorislsPoint/title>
</head>
<body>
Some Text
<div></div>
<p></p>
<div>Some more text</div>
<b></b>
<i></i> # COMMENT
</body>
</html>'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
soup.find('body').sm
for item in soup.find_all():
if not item.get_text(strip=True):
p = item.parent
item.replace_with('')
p.smooth()
print (soup.prettify())
Output
<html>
<head>
<title>
TutorislsPoint/title>
</title>
</head>
<body>
Some Text
<div>
Some more text
</div>
# COMMENT
</body>
</html>
Beautiful Soup - prettify() Method
Method Description
要获得格式良好的 Unicode 字符串,请使用 Beautiful Soup 的 prettify() 方法。它对 Beautiful Soup 解析树进行格式化,以便每个标记都位于单独的行上并带有缩进。它允许您轻松可视化 Beautiful Soup 解析树的结构。
Example 1
考虑以下 HTML 字符串。
<p>The quick, <b>brown fox</b> jumps over a lazy dog.</p>
通过使用 prettify() 方法,我们可以更好地理解其结构 −
html = '''
<p>The quick, <b>brown fox</b> jumps over a lazy dog.</p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "lxml")
print (soup.prettify())
Output
<b>
brown fox
</b>
prettify() 方法用于理解文档的结构。但是,它不应该用于重新对其进行格式化,因为它会添加空白(采用新行的形式),并更改 HTML 文档的含义。
prettify() 方法可以选择提供 formatter 参数,以指定要使用的格式化。
以下是 formatter 的可能值。
formatter="minimal" − 它是默认值。将对字符串进行足够的处理以确保 Beautiful Soup 生成有效的 HTML/XML。
formatter="html" − 只要有可能,Beautiful Soup 将把 Unicode 字符转换为 HTML 实体。
formatter="html5" − 它类似于 formatter="html",但是 Beautiful Soup 将在 HTML 空标签(例如 "br")中省略结束斜杠。
formatter=None − Beautiful Soup 将不修改输出中的字符串。这是最快的选项,但可能导致 Beautiful Soup 生成无效的 HTML/XML。
Beautiful Soup - encode() Method
Method Description
Beautiful Soup 中的 encode() 方法呈现给定的 PageElement 及其内容的字节字符串表示形式。
prettify() 方法允许你轻松直观地展示 Beautiful Soup 解析树的结构,它有 encoding 参数。encode() 方法在 prettify() 方法中的作用与编码相同。
Parameters
-
encoding − 目标编码。
-
indent_level − 渲染的每行都将
-
indented this many levels. Used internally in recursive calls while pretty-printing.
-
formatter − Formatter object,或一个指定标准制表符之一的字符串。
-
errors − 一个错误处理策略。
Example 1
默认情况下,编码参数为 utf-8。以下代码显示了羹对象经过编码后的字节字符串表示形式。
from bs4 import BeautifulSoup
soup = BeautifulSoup("Hello “World!”", 'html.parser')
print (soup.encode('utf-8'))
Example 2
制表符对象具有以下预定义值 −
formatter="minimal" − 它是默认值。将对字符串进行足够的处理以确保 Beautiful Soup 生成有效的 HTML/XML。
formatter="html" − 只要有可能,Beautiful Soup 将把 Unicode 字符转换为 HTML 实体。
formatter="html5" − 它类似于 formatter="html",但是 Beautiful Soup 将在 HTML 空标签(例如 "br")中省略结束斜杠。
formatter=None − Beautiful Soup 将不修改输出中的字符串。这是最快的选项,但可能导致 Beautiful Soup 生成无效的 HTML/XML。
在以下示例中,不同的制表符值被用作 encode() 方法的参数。
from bs4 import BeautifulSoup
french = "<p>Il a dit <<Sacré bleu!>></p>"
soup = BeautifulSoup(french, 'html.parser')
print ("minimal: ")
print(soup.p.encode(formatter="minimal"))
print ("html: ")
print(soup.p.encode(formatter="html"))
print ("None: ")
print(soup.p.encode(formatter=None))
Output
minimal:
b'<p>Il a dit <<Sacr\xc3\xa9 bleu!>></p>'
html:
b'<p>Il a dit <<Sacré bleu!>></p>'
None:
b'<p>Il a dit <<Sacr\xc3\xa9 bleu!>></p>'
Beautiful Soup - decode() Method
Method Description
Beautiful Soup 中的 decode() 方法将解析树作为 HTML 或 XML 文档返回为字符串或 Unicode 表示形式。此方法使用为编码注册的编解码器解码字节。它的函数与 encode() 方法相反。您调用 encode() 获取字节串,调用 decode() 获取 Unicode。让我们通过一些示例来学习 decode() 方法。
Beautiful Soup - get_text() Method
Example 1
在以下示例中,get_text() 方法移除所有 HTML 标记。
html = '''
<html>
<body>
<p> The quick, brown fox jumps over a lazy dog.</p>
<p> DJs flock by when MTV ax quiz prog.</p>
<p> Junk MTV quiz graced by fox whelps.</p>
<p> Bawds jog, flick quartz, vex nymphs.</p>
</body>
</html>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
text = soup.get_text()
print(text)
Output
The quick, brown fox jumps over a lazy dog.
DJs flock by when MTV ax quiz prog.
Junk MTV quiz graced by fox whelps.
Bawds jog, flick quartz, vex nymphs.
Example 2
在以下示例中,我们将 get_text() 方法的分隔符参数指定为“#”。
html = '''
<p>The quick, brown fox jumps over a lazy dog.</p>
<p>DJs flock by when MTV ax quiz prog.</p>
<p>Junk MTV quiz graced by fox whelps.</p>
<p>Bawds jog, flick quartz, vex nymphs.</p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
text = soup.get_text(separator='#')
print(text)
Output
#The quick, brown fox jumps over a lazy dog.#
#DJs flock by when MTV ax quiz prog.#
#Junk MTV quiz graced by fox whelps.#
#Bawds jog, flick quartz, vex nymphs.#
Example 3
当 strip 参数设置为 True 时,让我们检查其效果。默认情况下为 False。
html = '''
<p>The quick, brown fox jumps over a lazy dog.</p>
<p>DJs flock by when MTV ax quiz prog.</p>
<p>Junk MTV quiz graced by fox whelps.</p>
<p>Bawds jog, flick quartz, vex nymphs.</p>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
text = soup.get_text(strip=True)
print(text)
Beautiful Soup - diagnose() Method
Method Description
Beautiful Soup 中的 diagnose() 方法是一个诊断套件,用于隔离常见问题。如果你难以理解 Beautiful Soup 对文档执行了哪些操作,请将文档作为参数传递给 diagnose() 函数。一份报告显示了不同解析器如何处理文档,并告诉你是否缺少解析器。
Example
让我们为这个练习获取这个简单文档 −
<h1>Hello World
<b>Welcome</b>
<P><b>Beautiful Soup</a> <i>Tutorial</i><p>
以下代码对上述 HTML 脚本运行诊断 −
markup = '''
<h1>Hello World
<b>Welcome</b>
<P><b>Beautiful Soup</a> <i>Tutorial</i><p>
'''
from bs4.diagnose import diagnose
diagnose(markup)
该 diagonose() 输出以一条消息开头,显示了哪些解析器可用 −
Diagnostic running on Beautiful Soup 4.12.2
Python version 3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)]
Found lxml version 4.9.2.0
Found html5lib version 1.1
如果要诊断的文档是一个完美的 HTML 文档,那么所有解析器的结果都几乎相似。但是,在我们的示例中,有许多错误。
首先,使用内置的 html.parser。报告如下 −
Trying to parse your markup with html.parser
Here's what html.parser did with the markup:
<h1>
Hello World
<b>
Welcome
</b>
<p>
<b>
Beautiful Soup
<i>
Tutorial
</i>
<p>
</p>
</b>
</p>
</h1>
你可以看到,Python 的内置解析器不会插入 <html> 和 <body> 标记。未闭合的 <h1> 标记在结尾处提供了匹配的 <h1>。
html5lib 和 lxml 解析器均通过用 <html>、<head> 和 <body> 标记包装文档来完成文档。
Trying to parse your markup with html5lib
Here's what html5lib did with the markup:
<html>
<head>
</head>
<body>
<h1>
Hello World
<b>
Welcome
</b>
<p>
<b>
Beautiful Soup
<i>
Tutorial
</i>
</b>
</p>
<p>
<b>
</b>
</p>
</h1>
</body>
</html>
使用 lxml 解析器,请注意 </h1> 的插入位置。不完整的 <b> 标记也会纠正,并且悬挂的 </a> 会被移除。
Trying to parse your markup with lxml
Here's what lxml did with the markup:
<html>
<body>
<h1>
Hello World
<b>
Welcome
</b>
</h1>
<p>
<b>
Beautiful Soup
<i>
Tutorial
</i>
</b>
</p>
<p>
</p>
</body>
</html>
diagnose() 方法还会将文档解析为 XML 文档,这在我们这里可能多余。
Trying to parse your markup with lxml-xml
Here's what lxml-xml did with the markup:
<?xml version="1.0" encoding="utf-8"?>
<h1>
Hello World
<b>
Welcome
</b>
<P>
<b>
Beautiful Soup
</b>
<i>
Tutorial
</i>
<p/>
</P>
</h1>
让我们向 diagnose() 方法提供 XML 文档,而不是 HTML 文档。
<?xml version="1.0" ?>
<books>
<book>
<title>Python</title>
<author>TutorialsPoint</author>
<price>400</price>
</book>
</books>
现在,如果我们运行诊断,即使是 XML,也会应用 html 解析器。
Trying to parse your markup with html.parser
Warning (from warnings module):
File "C:\Users\mlath\OneDrive\Documents\Feb23 onwards\BeautifulSoup\Lib\site-packages\bs4\builder\__init__.py", line 545
warnings.warn(
XMLParsedAsHTMLWarning: It looks like you're parsing an XML document using an HTML parser. If this really is an HTML document (maybe it's XHTML?), you can ignore or filter this warning. If it's XML, you should know that using an XML parser will be more reliable. To parse this document as XML, make sure you have the lxml package installed, and pass the keyword argument `features="xml"` into the BeautifulSoup constructor.
使用 html.parser,会显示一条警告消息。使用 html5lib,包含 XML 版本信息的第一个文本行会被注释掉,并且文档的其余部分将被解析,就像它是 HTML 文档一样。
Trying to parse your markup with html5lib
Here's what html5lib did with the markup:
<!--?xml version="1.0" ?-->
<html>
<head>
</head>
<body>
<books>
<book>
<title>
Python
</title>
<author>
TutorialsPoint
</author>
<price>
400
</price>
</book>
</books>
</body>
</html>
lxml html 解析器不会插入注释,而是将其解析为 HTML。
Trying to parse your markup with lxml
Here's what lxml did with the markup:
<?xml version="1.0" ?>
<html>
<body>
<books>
<book>
<title>
Python
</title>
<author>
TutorialsPoint
</author>
<price>
400
</price>
</book>
</books>
</body>
</html>
lxml-xml 解析器将文档解析为 XML。
Trying to parse your markup with lxml-xml
Here's what lxml-xml did with the markup:
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" ?>
<books>
<book>
<title>
Python
</title>
<author>
TutorialsPoint
</author>
<price>
400
</price>
</book>
</books>
诊断报告可能被证明对查找 HTML/XML 文档中的错误很有用。