3种抓取其中数据的方法。首先是正则表达式,然后是流行的BeautifulSoup模块,最后是强大的lxml模块。
1 正则表达式
当我们使用正则表达式抓取国家(或地区)面积数据时,首先需要尝试匹配``元素中的内容,如下所示。
从上述结果中可以看出,多个国家(或地区)属性都使用了``标签。如果我们只想抓取国家(或地区)面积,可以只选择第二个匹配的元素,如下所示。
这个迭代版本看起来更好一些,但是网页更新还有很多其他方式,同样可以让该正则表达式无法满足。比如,将双引号变为单引号,`标签之间添加多余的空格,或是变更area_label`等。下面是尝试支持这些可能性的改进版本。
虽然该正则表达式更容易适应未来变化,但又存在难以构造、可读性差的问题。此外,还有很多其他微小的布局变化也会使该正则表达式无法满足,比如在`标签里添加title属性,或者tr、td`元素修改了它们的CSS类或ID。
从本例中可以看出,正则表达式为我们提供了抓取数据的快捷方式,但是该方法过于脆弱,容易在网页更新后出现问题。幸好,还有更好的数据抽取解决方案,比如我们将在本章介绍的其他抓取库。
2 Beautiful Soup
Beautiful Soup
是一个非常流行的Python库,它可以解析网页,并提供了定位内容的便捷接口。如果你还没有安装该模块,可以使用下面的命令安装其最新版本。
使用Beautiful Soup的第一步是将已下载的HTML内容解析为soup文档。由于许多网页都不具备良好的HTML格式,因此Beautiful Soup需要对其标签开合状态进行修正。例如,在下面这个简单网页的列表中,存在属性值两侧引号缺失和标签未闭合的问题。
如果Population列表项被解析为Area列表项的子元素,而不是并列的两个列表项的话,我们在抓取时就会得到错误的结果。下面让我们看一下Beautiful Soup是如何处理的。
我们可以看到,使用默认的html.parser并没有得到正确解析的HTML。从前面的代码片段可以看出,由于它使用了嵌套的li元素,因此可能会导致定位困难。幸运的是,我们还有其他解析器可以选择。我们可以安装LXML(2.2.3节中将会详细介绍),或使用html5lib。要想安装html5lib,只需使用pip。
现在,我们可以重复这段代码,只对解析器做如下变更。
此时,使用了html5lib的BeautifulSoup已经能够正确解析缺失的属性引号以及闭合标签,并且还添加了和标签,使其成为完整的HTML文档。当你使用lxml时,也可以看到类似的结果。
现在,我们可以使用find()和find_all()方法来定位我们需要的元素了。
想要了解可用方法和参数的完整列表,请访问Beautiful Soup的官方文档。
下面是使用该方法抽取示例网站中国家(或地区)面积数据的完整代码。
这段代码虽然比正则表达式的代码更加复杂,但又更容易构造和理解。而且,像多余的空格和标签属性这种布局上的小变化,我们也无须再担心了。我们还知道即使页面中包含了不完整的HTML,Beautiful Soup也能帮助我们整理该页面,从而让我们可以从非常不完整的网站代码中抽取数据。
3 Lxml
Lxml
是基于libxml2这一XML解析库构建的Python库,它使用C语言编写,解析速度比Beautiful Soup更快,不过安装过程也更为复杂,尤其是在Windows中。如果你在自行安装该库时遇到困难,也可以使用Anaconda来实现。
你可能对Anaconda不太熟悉,它是由Continuum Analytics公司员工创建的主要专注于开源数据科学包的包和环境管理器。你可以按照其安装说明下载及安装Anaconda。需要注意的是,使用Anaconda的快速安装会将你的PYTHON_PATH设置为Conda的Python安装位置。
和Beautiful Soup一样,使用lxml模块的第一步也是将有可能不合法的HTML解析为统一格式。下面是使用该模块解析同一个不完整HTML的例子。
同样地,lxml也可以正确解析属性两侧缺失的引号,并闭合标签,不过该模块没有额外添加和标签。这些都不是标准XML的要求,因此对于lxml来说,插入它们并不是必要的。
解析完输入内容之后,进入选择元素的步骤,此时lxml有几种不同的方法,比如XPath选择器和类似Beautiful Soup的find()方法。不过,在本例中,我们将会使用CSS选择器,因为它更加简洁,并且能够在第5章解析动态内容时得以复用。一些读者可能由于他们在jQuery选择器方面的经验或是前端Web应用开发中的使用对它们已经有所熟悉。在本章的后续部分,我们将对比这些选择器与XPath的性能。要想使用CSS选择器,你可能需要先安装cssselect库,如下所示。
现在,我们可以使用lxml的CSS选择器,抽取示例页面中的面积数据了。
通过对代码树使用cssselect方法,我们可以利用CSS语法来选择表格中ID为places_area__row的行元素,然后是类为w2p_fw的子表格数据标签。由于cssselect返回的是一个列表,我们需要获取其中的第一个结果,并调用text_content方法,以迭代所有子元素并返回每个元素的相关文本。