- 本书赞誉
- 前言
- 目标读者
- 不适合阅读本书的读者
- 本书结构
- 什么是数据处理
- 遇到困难怎么办
- 排版约定
- 使用代码示例
- 致谢
- 第 1 章 Python 简介
- 第 2 章 Python 基础
- 第 3 章 供机器读取的数据
- 第 4 章 处理 Excel 文件
- 第 5 章 处理 PDF 文件 以及用 Python 解决问题
- 第 6 章 数据获取与存储
- 第 7 章 数据清洗:研究、匹配与格式化
- 第 8 章 数据清洗:标准化和脚本化
- 第 9 章 数据探索和分析
- 第 10 章 展示数据
- 第 11 章 网页抓取:获取并存储网络数据
- 第 12 章 高级网页抓取:屏幕抓取器与爬虫
- 第 13 章 应用编程接口
- 第 14 章 自动化和规模化
- 第 15 章 结论
- 附录 A 编程语言对比
- 附录 B 初学者的 Python 学习资源
- 附录 C 学习命令行
- 附录 D 高级 Python 设置
- 附录 E Python 陷阱
- 附录 F IPython 指南
- 附录 G 使用亚马逊网络服务
- 关于作者
- 关于封面
11.4 使用 Beautiful Soup 读取网页
Beautiful Soup 是最流行、最简单的用于网页抓取的 Python 库之一。对于不同的需求,在网页抓取中它可能提供了你所需的一切。它很简单、直接,并且很容易学习。让我们看一下如何使用 Beautiful Soup 解析页面。首先,使用 pip 安装这个库(使用 beautifulsoup4,因为早期的版本已经不再支持和开发了):
pip install beautifulsoup4
让我们重新看一下在早些时候检查过的一个简单的页面,即 Enough 项目的 Take Action 页面(http://www.enoughproject.org/take_action)。我们想要看一下是否可以正确地解析所有的活动调用,并且保存它们。下面是导入页面到 Beautiful Soup 中的实例,这样我们可以开始读取它:
from bs4 import BeautifulSoup ➊ import requests page = requests.get('http://www.enoughproject.org/take_action') ➋ bs = BeautifulSoup(page.content) ➌ print bs.title print bs.find_all('a') ➍ print bs.find_all('p')
❶ 首先,直接从 beautifulsoup4 库导入解析器。
❷ 使用 requests 库来抓取页面上的内容,这行代码将响应(和它的内容)赋值给 page 变量。
❸ 为了开始使用 Beautiful Soup 解析,这行代码传递页面内容到 BeautifulSoup 类。可以使用 content 属性获取响应的源页面。
❹ 一旦解析了页面对象,可以使用它的属性和方法。这行代码让 Beautiful Soup 找到页面中所有的 a 标签(或链接)。
可以打开一个页面,读取响应到一个 Beautiful Soup 对象,并且使用这个对象的属性来查看标题、页面中所有的段落,以及页面上所有的链接。
我们已经学习了 HTML 中有关家族关系的知识,下面查看一下页面中的关系:
header_children = [c for c in bs.head.children] ➊ print header_children navigation_bar = bs.find(id="globalNavigation") ➋ for d in navigation_bar.descendants: ➌ print d for s in d.previous_siblings: ➍ print s
❶ 使用列表生成式创建一个页面中头部的所有子元素的列表。通过将 Beautiful Soup 页面对象和 .head(调取页面的头部)以及 .children 联系在一起,可以查看所有包含在头部中的节点。如果需要的话,可以解析头部的元内容,包括页面描述。
❷ 如果使用开发者工具观察页面,你会看到导航栏使用一个 CSS 选择器 ID globalNavigation 定义。这行代码使用页面对象的 find 方法,传递一个 ID,并且定位导航栏。
❸ 使用导航栏的 descendants 方法遍历导航栏的后继。
❹ 到导航栏的最后一个后继,这行代码使用 .previous_sibling 来遍历导航元素的邻居。
家族树让我们通过 Beautiful Soup 库 page 类中的内置属性和方法导航。正如可以从头部和导航栏示例中看到的那样,从页面中选择一个区域,并遍历孩子、后代或邻居是很容易的。Beautiful Soup 的语法非常简单,并且将元素和它们的属性链式绑定到一起(像 .head.children)。对此有了了解之后,让我们专注于页面的主要部分,看一下是否可以拉取一些可能感兴趣的内容。
如果通过开发者工具观察页面,会注意到一些事情。首先,看起来每一个动作对象都位于一个 views-row div 中。这些 divs 有许多不同的类,但是它们都有一个 views-row 类。这是开始解析的好起点。标题位于一个 h2 标签中,同时链接也在该 h2 标签中,位于一个锚标签中。对于动作的调用位于 views-row div 的子 div 中的段落里面。现在可以使用 Beautiful Soup 解析页面。
首先,我们想要利用已掌握的 Beautiful Soup 知识,以及对页面结构和导航结构方式的理解,找到内容。下面是完成这件事的代码:
from bs4 import BeautifulSoup import requests page = requests.get('http://www.enoughproject.org/take_action') bs = BeautifulSoup(page.content) ta_divs = bs.find_all("div", class_="views-row") ➊ print len(ta_divs) ➋ for ta in ta_divs: title = ta.h2 ➌ link = ta.a about = ta.find_all('p') ➍ print title, link, about
❶ 使用 Beautiful Soup 找到并返回类中包含字符串 views-row 的所有 divs。
❷ 打印来检查数字是否是可以在网站上看到的故事行数,预示着正确地匹配了行数据。
❸ 遍历这些行数据,并基于页面的研究获取想要的标签。标题位于一个 h2 标签中,并且是行中唯一的 h2 标签。链接是第一个锚标签。
❹ 因为不确定在每行数据中有多少个段落标签,所以匹配所有的段落标签来得到文本。由于使用了 .find_all 方法,Beautiful Soup 返回一个列表,而不是第一个匹配的元素。
你应该会看到类似于下面的输出:
<h2><a href="https://ssl1.americanprogress.org/o/507/p/dia/action3/common/ public/?action_KEY=391">South Sudan: On August 17th, Implement "Plan B" </a></h2> <a href="https://ssl1.americanprogress.org/o/507/p/dia/action3/common/public/ ?action_KEY=391">South Sudan: On August 17th, Implement "Plan B" </a> [<p>During President Obama's recent trip to Africa, the international community set a deadline of August 17 for a peace deal to be signed by South Sudan's warring parties....]
这些内容可能随着站点更新而改变,但是你应该会看到一个 h2 元素,之后是一个锚(a)元素,然后是每个节点段落的列表。当下的输出是混乱的,不仅因为我们正在使用一个 print,还因为 Beautiful Soup 打印了完整的元素和它的内容。相对于完整的元素,我们更想要关注于必需的部分,也就是标题文本、链接 hrefs 和段落文本。可以使用 Beautiful Soup 来仔细地查看这部分数据:
all_data = [] for ta in ta_divs: data_dict = {} data_dict['title'] = ta.h2.get_text() ➊ data_dict['link'] = ta.a.get('href') ➋ data_dict['about'] = [p.get_text() for p in ta.find_all('p')] ➌ all_data.append(data_dict) print all_data
❶ 使用 get_text 方法抽取所有来自 HTML 元素的字符串。这样会获得标题文本。
❷ 为了得到一个元素的属性,使用 get 方法。当看到 <ahref="http://foo.com">Foo</a>,并想提取链接时,可以调用 .get("href") 来返回 href 值(即,foo.com)。
❸ 为了抽取段落文本,使用 get_text 方法,遍历 find_all 方法返回的段落。这行代码使用列表生成式来编译一个有着动作内容调用的字符串列表。
现在数据和输出呈现了一个更加有组织的格式。在变量 all_data 中,保存了一个所有数据的列表。现在每一个数据输入都和匹配键保存在其字典中。我们用一种整洁的方式,使用一些新的方法(get 和 get_text)从页面抓取了数据,并且数据现在存放在数据字典中。代码更加清晰和精确,可以通过添加辅助函数让它更加清晰(像第 8 章介绍的)。
除此之外,可以自动化脚本来检查是否有新的动作调用。如果保存数据到 SQLite,并且将其用于每月检查刚果的劳工实践,可以自动化报告。在每一个新报告中,可以抽取这些数据,并且对对抗冲突矿产和童工激起更多的兴趣。
Beautiful Soup 是一个易于使用的工具,并且其文档(https://www.crummy.com/software/BeautifulSoup/bs4/doc/)中介绍了很多其他可用方法的实例。这个库对于初学者来说很棒,并且有很多简单的函数;然而,跟一些其他的 Python 库相比,它太简单了。
由于 Beautiful Soup 的解析是基于正则表达式的,用在缺乏正确标签结构的破损网页上很有效。但是如果想要遍历更加复杂的页面,或者想要抓取器运行得更快并且快速地浏览页面,有很多更加高级的 Python 库可用。让我们看一下许多天才网页抓取器开发者最爱的库:lxml。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论