简介
网络为我们提供了比我们能阅读和理解的更多数据,因此我们经常希望以编程方式处理这些信息,以便理解它。有时,网站创建者通过 .csv
或逗号分隔值文件或通过 API(应用程序编程接口)向我们提供这些数据。其他时候,我们需要自己从网络上收集文本。
本教程将介绍如何使用 Requests 和 Beautiful Soup Python 包来利用网页数据。Requests 模块允许您将 Python 程序与 Web 服务集成,而 Beautiful Soup 模块旨在快速完成屏幕抓取。使用 Python 交互式控制台和这两个库,我们将学习如何收集网页并处理其中可用的文本信息。
安装 Requests
让我们首先激活我们的 Python 3 编程环境。确保您位于环境所在的目录,并运行以下命令:
. my_env/bin/activate
为了处理网页,我们需要请求页面。Requests 库允许您以人类可读的方式在 Python 程序中使用 HTTP。
在激活我们的编程环境后,我们将使用 pip 安装 Requests:
pip install requests
安装 Requests 库时,您将收到以下输出:
Collecting requests Downloading requests-2.26.0-py2.py3-none-any.whl (88kB) 100% |████████████████████████████████| 92kB 3.1MB/s ...Installing collected packages: chardet, urllib3, certifi, idna, requestsSuccessfully installed certifi-2017.4.17 chardet-3.0.4 idna-2.5 requests-2.26.0 urllib3-1.21.1
如果 Requests 已经安装,您将从终端窗口收到类似以下的反馈:
Requirement already satisfied...
安装 Requests 到我们的编程环境后,我们可以继续安装下一个模块。
安装 Beautiful Soup
与安装 Requests 一样,我们将使用 pip 安装 Beautiful Soup。当前版本的 Beautiful Soup 4 可以使用以下命令安装:
pip install beautifulsoup4
运行此命令后,您应该会看到类似以下的输出:
Collecting beautifulsoup4 Downloading beautifulsoup4-4.10.0-py3-none-any.whl (97 kB) |████████████████████████████████| 97 kB 6.8 MB/sCollecting soupsieve>1.2 Downloading soupsieve-2.3.1-py3-none-any.whl (37 kB)Installing collected packages: soupsieve, beautifulsoup4Successfully installed beautifulsoup4-4.10.0 soupsieve-2.3.1
现在 Beautiful Soup 和 Requests 都已安装,我们可以继续了解如何使用这些库来抓取网站。
使用 Requests 收集网页
现在我们已经安装了要使用的两个 Python 库,我们可以熟悉一下如何浏览基本网页。
让我们首先进入 Python 交互式控制台:
python
从这里,我们将导入 Requests 模块,以便我们可以收集一个示例网页:
import requests
我们将把示例网页 mockturtle.html
的 URL(下面)赋给变量 url
:
url = 'https://assets.digitalocean.com/articles/eng_python/beautiful-soup/mockturtle.html'
接下来,我们可以使用 request.get()
方法将该页面的请求结果赋给变量 page
。我们将该方法传递给页面的 URL(分配给 url
变量)。
page = requests.get(url)
变量 page
被分配了一个响应对象:
>>> page<Response [200]>>>>
上面的响应对象告诉我们方括号中的 status_code
属性(在本例中为 200
)。可以显式调用此属性:
>>> page.status_code200>>>
返回的 200
代码告诉我们页面下载成功。以数字 2
开头的代码通常表示成功,而以 4
或 5
开头的代码表示发生了错误。您可以从 W3C 的状态码定义中了解更多关于 HTTP 状态码的信息。
为了处理网络数据,我们将要访问网页文件的基于文本的内容。我们可以使用 page.text
(或者如果我们想要以字节形式访问响应,则使用 page.content
)来读取服务器响应的内容。
page.text
按下 ENTER
后,我们将收到以下输出:
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"/n "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">/n/n<html lang="en-US" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">/n<head>/n <meta http-equiv="content-type" content="text/html; charset=us-ascii" />/n/n <title>Turtle Soup</title>/n</head>/n/n<body>/n <h1>Turtle Soup</h1>/n/n <p class="verse" id="first">Beautiful Soup, so rich and green,<br />/n Waiting in a hot tureen!<br />/n Who for such dainties would not stoop?<br />/n Soup of the evening, beautiful Soup!<br />/n Soup of the evening, beautiful Soup!<br /></p>/n/n <p class="chorus" id="second">Beau--ootiful Soo--oop!<br />/n Beau--ootiful Soo--oop!<br />/n Soo--oop of the e--e--evening,<br />/n Beautiful, beautiful Soup!<br /></p>/n/n <p class="verse" id="third">Beautiful Soup! Who cares for fish,<br />/n Game or any other dish?<br />/n Who would not give all else for two<br />/n Pennyworth only of Beautiful Soup?<br />/n Pennyworth only of beautiful Soup?<br /></p>/n/n <p class="chorus" id="fourth">Beau--ootiful Soo--oop!<br />/n Beau--ootiful Soo--oop!<br />/n Soo--oop of the e--e--evening,<br />/n Beautiful, beauti--FUL SOUP!<br /></p>/n</body>/n</html>/n'>>>
在这里,我们看到页面的完整文本被打印出来,包括所有的 HTML 标记。但是,由于没有太多的间距,很难阅读。
在下一节中,我们可以利用 Beautiful Soup 模块以更加人性化的方式处理这些文本数据。
使用 Beautiful Soup 逐步解析页面
Beautiful Soup 库可以从解析后的 HTML 和 XML 文档(包括具有非闭合标签或标记混乱等格式不正确的标记的文档)中创建解析树。这个功能将使网页文本比我们从 Requests 模块中看到的更易读。
首先,我们将在 Python 控制台中导入 Beautiful Soup:
from bs4 import BeautifulSoup
接下来,我们将运行 page.text
文档通过该模块,以便为我们提供一个 BeautifulSoup
对象 —— 也就是说,我们将通过运行 Python 内置的 html.parser
对 HTML 进行解析,从而得到从解析页面中得到的解析树。构造的对象将以嵌套数据结构的形式表示为 mockturtle.html
文档。这被赋值给变量 soup
。
soup = BeautifulSoup(page.text, 'html.parser')
为了在终端上显示页面的内容,我们可以使用 prettify()
方法将 Beautiful Soup 解析树转换为格式良好的 Unicode 字符串。
print(soup.prettify())
这将使每个 HTML 标记都单独显示在自己的一行上:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html lang="en-US" xml:lang="en-US" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta content="text/html; charset=utf-8" http-equiv="content-type"/> <title> Turtle Soup </title> </head> <body> <h1> Turtle Soup </h1> <p class="verse" id="first"> Beautiful Soup, so rich and green, <br/> Waiting in a hot tureen! <br/> Who for such dainties would not stoop? <br/> Soup of the evening, beautiful Soup! ...</html>
在上面的输出中,我们可以看到每行只有一个标记,并且由于 Beautiful Soup 使用的树形模式,标记是嵌套的。
查找标记的实例
我们可以使用 Beautiful Soup 的 find_all
方法从页面中提取单个标记。这将返回文档中给定标记的所有实例。
soup.find_all('p')
在我们的对象上运行该方法将返回歌曲的完整文本以及相关的 <p>
标记和该请求标记中包含的任何标记,这里包括换行标记 <br/>
:
[<p class="verse" id="first">Beautiful Soup, so rich and green,<br/> Waiting in a hot tureen!<br/> Who for such dainties would not stoop?<br/> Soup of the evening, beautiful Soup!<br/> Soup of the evening, beautiful Soup!<br/></p>, <p class="chorus" id="second">Beau--ootiful Soo--oop!<br/>... Beau--ootiful Soo--oop!<br/> Soo--oop of the e--e--evening,<br/> Beautiful, beauti--FUL SOUP!<br/></p>]
您会注意到上面的输出数据包含在方括号 [ ]
中。这意味着它是 Python 的列表数据类型。
因为它是一个列表,我们可以调用其中的特定项(例如,第三个 <p>
元素),并使用 get_text()
方法从该标记内提取所有文本:
soup.find_all('p')[2].get_text()
我们收到的输出将是这种情况下第三个 <p>
元素中的内容:
'Beautiful Soup! Who cares for fish,/n Game or any other dish?/n Who would not give all else for two/n Pennyworth only of Beautiful Soup?/n Pennyworth only of beautiful Soup?'
请注意,返回的字符串中也显示了 /n
换行符。
按类和 ID 查找标记
在使用 Beautiful Soup 处理网页数据时,与 CSS 选择器相关的 HTML 元素,如类和 ID,可能会有所帮助。我们可以通过使用 find_all()
方法并将类和 ID 字符串作为参数传递来针对特定的类和 ID。
首先,让我们找到所有 chorus
类的实例。在 Beautiful Soup 中,我们将类的字符串分配给关键字参数 class_
:
soup.find_all(class_='chorus')
当我们运行上述行时,我们将收到以下列表作为输出:
[<p class="chorus" id="second">Beau--ootiful Soo--oop!<br/> Beau--ootiful Soo--oop!<br/> Soo--oop of the e--e--evening,<br/> Beautiful, beautiful Soup!<br/></p>, <p class="chorus" id="fourth">Beau--ootiful Soo--oop!<br/> Beau--ootiful Soo--oop!<br/> Soo--oop of the e--e--evening,<br/> Beautiful, beauti--FUL SOUP!<br/></p>]
具有 chorus
类的两个 <p>
标记部分被打印到终端上。
我们还可以指定我们只想在 <p>
标记内搜索 chorus
类,以防它用于多个标记:
soup.find_all('p', class_='chorus')
运行上面的行将产生与之前相同的输出。
我们还可以使用 Beautiful Soup 来定位与 HTML 标记相关联的 ID。在这种情况下,我们将字符串 'third'
分配给关键字参数 id
:
soup.find_all(id='third')
一旦我们运行上面的行,我们将收到以下输出:
[<p class="verse" id="third">Beautiful Soup! Who cares for fish,<br/> Game or any other dish?<br/> Who would not give all else for two<br/> Pennyworth only of Beautiful Soup?<br/> Pennyworth only of beautiful Soup?<br/></p>]
与 ID 为 third
的 <p>
标记相关联的文本将与相关标记一起打印到终端上。
结论
本教程带领你使用 Python 的 Requests 模块获取网页,并对该网页的文本数据进行初步的抓取,以便更好地理解 Beautiful Soup。