返回博客
指南
Sorin-Gabriel MaricaLast updated on Mar 31, 20262 min read

使用 Python 和 BeautifulSoup 提取和解析网页数据

使用 Python 和 BeautifulSoup 提取和解析网页数据

网页爬虫是极具价值的工具,可帮助您从网站中提取特定信息。理论上,您可以手动完成这项工作,但使用网页爬虫能让您更高效、更高效地处理海量数据。

Python 是网页抓取领域最受欢迎的编程语言之一。该语言自带 BeautifulSoup 库,能极大简化抓取流程。二者结合,使得使用 Python 进行网页抓取比其他语言要简单得多。

就我个人而言,使用 BeautifulSoup 是从零开始构建简单网页抓取工具的最便捷方式。若想深入了解,请继续阅读,我将向您展示如何使用 Python 和 BeautifulSoup 创建自己的网页抓取工具。

BeautifulSoup 概述

正如其文档所述,BeautifulSoup 是一个用于从 HTML 和 XML 文件中提取数据的 Python 库。因此,你可以先使用 Python 从网站中提取 HTML 内容,再利用 BeautifulSoup 解析该 HTML 以获取相关信息。

使用 BeautifulSoup 的主要优势在于其简洁的语法。借助该库,你可以遍历 DOM 树、查找特定元素或修改 HTML 内容。所有这些优势使其成为解析 HTML 和 XML 文档最受欢迎的 Python 库。

安装

要安装 BeautifulSoup,请查阅此处的指南,因为安装方式会因您使用的机器而异。本文中,我使用的是 Linux 系统,只需运行以下命令即可:

pip install beautifulsoup4

如果您使用 Python 3,则可能需要使用以下命令进行安装:

pip3 install beautifulsoup4

请注意,我的机器上已安装 Python 3。如果您是 Python 新手,可以在此处找到安装指南。此外,您还可以查阅我们关于使用 Python 构建网络爬虫的终极指南,以获取更多相关信息。

使用 BeautifulSoup 构建爬虫

现在,如果一切顺利,我们就可以开始构建自己的爬虫了。在本篇文章中,我选择从烂番茄(Rotten Tomatoes)获取影史排名前100电影,并将所有数据同时保存为 JSON 和 CSV 格式。

获取页面源代码

为了热身并熟悉 BeautifulSoup,我们将首先获取页面的完整 HTML 代码,并将其保存到一个名为“page.txt”的新文件中。

若想查看任意页面的 HTML 源代码,可在 Google Chrome 中按下 CTRL+U。这将打开一个新标签页,您会看到类似以下内容:

若要使用 BeautifulSoup 和 Python 获取相同的源代码,我们可以使用以下代码:

import requests
from bs4 import BeautifulSoup

scraped_url = 'https://www.rottentomatoes.com/top/bestofrt/'
page = requests.get(scraped_url)

soup = BeautifulSoup(page.content, 'html.parser')

file = open('page.txt', mode='w', encoding='utf-8')
file.write(soup.prettify())

在此代码中,我们向烂番茄(RottenTomatoes)页面发送请求,并将页面所有内容加载到一个 BeautifulSoup 对象中。本示例中 BeautifulSoup 的唯一用途是最后调用的“prettify()”函数,该函数会对 HTML 代码进行格式化处理,使其更易于阅读。

为了更好地理解该函数,以这段 HTML 代码“<div><span>Test&lt;/span></div>”为例,prettify 函数会添加制表符,并将代码转换为以下格式:

<div>

   <span>

       Test

   </span>

</div>

该代码的最终结果是生成一个名为 page.txt 的文件,其中包含我们链接的完整页面源代码:

请注意,这是在任何 JavaScript 代码执行之前的页面源代码。有时网站可能会选择动态更改其页面内容。在这种情况下,页面源代码将与实际显示给用户的页面内容有所不同。如果您需要您的爬虫执行 JavaScript,您可以阅读我们关于使用 Selenium 构建 Web 爬虫的指南,或者您可以使用 WebScrapingAPI——我们的产品将为您解决此问题。

获取网页数据

如果您查看前面的页面源代码,会发现其中包含电影名称及其评分。幸运的是,烂番茄(RottenTomatoes)并未动态加载电影列表,因此我们可以直接抓取所需信息。

首先,我们检查页面以了解 HTML 的结构。为此,您可以右键单击电影标题并选择“检查元素”选项。随后应出现如下窗口:

我用红线标出了这张图片中的有用信息。你可以看到,页面以表格形式展示热门电影,且每行表格包含四个单元格(<tr> 元素)。

第一个单元格包含电影的排名位置,第二个单元格包含评分信息(类名为 tMeterScore 的元素),第三个单元格包含电影标题,最后一个单元格则显示评论数量。

了解这一结构后,我们现在可以开始提取所需的信息了。

import requests
from bs4 import BeautifulSoup
 
links_base = 'https://www.rottentomatoes.com'
scraped_url = 'https://www.rottentomatoes.com/top/bestofrt/'
page = requests.get(scraped_url)
 
soup = BeautifulSoup(page.content, 'html.parser')
 
table = soup.find("table", class_="table") # We extract just the table code from the entire page
rows = table.findAll("tr") # This will extract each table row, in an array
 
movies = []
 
for index, row in enumerate(rows):
    if index > 0: # We skip the first row since this row only contains the column names
        link = row.find("a") # We get the link from the table row
        rating = row.find(class_="tMeterScore") # We get the element with the class tMeterScore from the table row
        movies.append({
            "link": links_base + link.get('href'), # The href attribute of the link
            "title": link.string.strip(), # The strip function removes blank spaces at the beginning and the end of a string
            "rating": rating.string.strip().replace("&nbsp;", ""), # We remove &nbsp; from the string and the blank spaces
        })
        
print(movies)

运行此代码后,您应得到如下结果:

在此示例中,我们提取表格内容并遍历表格行。由于第一行仅包含列名,我们将跳过它。

对于其余行,我们将继续提取锚点(<a>)元素以及类名为“tMeterScore”的span元素。获取这些元素后,我们便能提取所需信息。

电影标题位于锚点元素内,链接是锚点的“href”属性,评分则位于类名为“tMeterScore”的span元素内。我们只需为每一行创建一个新字典,并将其追加到电影列表中。

保存网页数据

到目前为止,爬虫已经获取并格式化了数据,但我们仅在终端内显示了这些信息。此外,我们还可以将这些信息以 JSON 或 CSV 格式保存到计算机上。爬虫的完整代码(包括创建本地文件)如下:

import requests
from bs4 import BeautifulSoup
import csv
import json
 
links_base = 'https://www.rottentomatoes.com'
scraped_url = 'https://www.rottentomatoes.com/top/bestofrt/'
page = requests.get(scraped_url)
 
soup = BeautifulSoup(page.content, 'html.parser')
 
table = soup.find("table", class_="table") # We extract just the table code from the entire page
rows = table.findAll("tr") # This will extract each table row from the table, in an array
 
movies = []
 
for index, row in enumerate(rows):
    if index > 0: # We skip the first row since this row only contains the column names
        link = row.find("a") # We get the link from the table row
        rating = row.find(class_="tMeterScore") # We get the element with the class tMeterScore from the table row
        movies.append({
            "link": links_base + link.get('href'), # The href attribute of the link
            "title": link.string.strip(), # The strip function removes blank spaces at the beginning and the end of a string
            "rating": rating.string.strip().replace("&nbsp;", ""), # We remove &nbsp; from the string and the blank spaces
        })
        
file = open('movies.json', mode='w', encoding='utf-8')
file.write(json.dumps(movies))
 
writer = csv.writer(open("movies.csv", 'w'))
for movie in movies:
    writer.writerow(movie.values())

进一步抓取

既然已获取所有信息,您可以选择进一步进行抓取。请记住,每部电影都有一个链接。您可以继续抓取电影页面,并提取更多相关信息。

例如,查看电影《一夜风流》(1934)的页面时,你会发现还可以抓取观众评分、片长、类型等有用的信息。

然而,在短时间内发出所有这些请求看起来非常异常,可能会触发 CAPTCHA 验证甚至导致 IP 被封禁。为避免这种情况,你应该使用轮换代理,这样发送的流量看起来会更自然,并且会来自多个 IP 地址。

BeautifulSoup 的其他功能

虽然我们的烂番茄爬虫已经完成,但 BeautifulSoup 仍有很多功能值得探索。在处理任何项目时,建议您始终打开文档链接,以便在遇到困难时能快速查找解决方案。

例如,BeautifulSoup 支持遍历页面的 DOM 树:

from bs4 import BeautifulSoup

soup = BeautifulSoup("<head><title>Title</title></head><body><div><p>Some text <span>Span</span></p></div></body>", 'html.parser')

print(soup.head.title) # Will print "<title>Title</title>"
print(soup.body.div.p.span) # Will print "<span>Span</span>"

当需要选择无法通过属性识别的元素时,此功能将大有帮助。在这种情况下,唯一的方法就是通过 DOM 结构来定位它。

BeautifulSoup的另一个亮点在于它支持修改页面源代码:

from bs4 import BeautifulSoup

soup = BeautifulSoup("<head><title>Title</title></head><body><div><p>Some text <span>Span</span></p></div></body>", 'html.parser')

soup.head.title.string = "New Title"
print(soup)
# The line above will print "<head><title>New Title</title></head><body><div><p>Some text <span>Span</span></p></div></body>"

若您想开发一款允许用户优化网页的服务,此功能将极具价值。例如,您可以使用脚本抓取网站、获取 CSS 文件、对其进行压缩,并将其替换回 HTML 源代码中。可能性无穷无尽!

始终要聪明地进行抓取

我真心希望你记住这一点:使用 Python 和 BeautifulSoup 进行网页抓取是一个绝佳的选择。与其他编程语言相比,它能让整个过程变得简单许多。

我们构建的用于从烂番茄(Rotten Tomatoes)获取史上最高评分电影的爬虫,仅需几分钟即可编写完成,你甚至可以将其与我们《PHP爬虫终极指南》中的IMDB爬虫结合使用。

然而,某些网站比其他网站更容易被爬虫访问。虽然本文中的项目简单有趣,但有些项目却完全不是这样。有时网站会竭尽全力防止其内容被爬取。

在某些情况下,唯一能成功抓取内容的方法就是通过多IP轮换和真实浏览器来伪装你的操作。针对这种情况,我们开发了 WebScrapingAPI——这一强大的解决方案提供代理轮换、JavaScript 渲染功能,让你能够以最少的麻烦抓取任何目标网站!

别光听我一人的说法,亲自试一试吧!您现在即可开始免费试用,获得 5000 次 API 调用额度,且无需提供信用卡信息等任何敏感数据。

关于作者
Sorin-Gabriel Marica, 全栈开发工程师 @ WebScrapingAPI
Sorin-Gabriel Marica全栈开发工程师

索林·马里卡(Sorin Marica)是 WebScrapingAPI 的全栈及 DevOps 工程师,负责开发产品功能并维护确保平台平稳运行的基础设施。

开始构建

准备好扩展您的数据收集规模了吗?

加入2,000多家企业,使用WebScrapingAPI在无需任何基础设施开销的情况下,以企业级规模提取网络数据。