抓取动态网页(Python中正则表达式的3种抓取其中数据的方法(一))

优采云 发布时间: 2022-03-25 18:21

  抓取动态网页(Python中正则表达式的3种抓取其中数据的方法(一))

  3种方法来抓取其中的数据。首先是正则表达式,然后是流行的BeautifulSoup模块,最后是强大的lxml模块。

  1 正则表达式

  如果你是正则表达式的新手或者需要一些提示,可以查看​​​​以获得完整的介绍。即使你在其他编程语言中使用过正则表达式,我仍然建议你逐步复习 Python 中正则表达式的编写。

  由于可以在每章中构建或使用前几章的内容,因此我建议您遵循类似于本书代码库的文件结构。所有代码都可以从代码库的代码目录运行,以便导入工作正常。如果您希望创建不同的结构,请注意所有来自其他章节的导入都需要更改(例如,来自下面代码中的 chp1.advanced_link_crawler​​)。

  当我们使用正则表达式获取国家(或地区)地区数据时,首先需要尝试匹配``元素中的内容,如下图所示。

  >>> import re

>>> from chp1.advanced_link_crawler import download

>>> url = 'http://example.python-scraping.com/view/UnitedKingdom-239'

>>> html = download(url)

>>> re.findall(r'(.*?)', html)

['<img />

',

'244,820 square kilometres',

'62,348,447',

'GB',

'United Kingdom',

'London',

'<a>EU</a>

',

'.uk',

'GBP',

'Pound',

'44',

'@# #@@|@## #@@|@@# #@@|@@## #@@|@#@ #@@|@@#@ #@@|GIR0AA',

'^(([A-Z]d{2}[A-Z]{2})|([A-Z]d{3}[A-Z]{2})|([A-Z]{2}d{2} [A-Z]{

2})|([A-Z]{2}d{3}[A-Z]{2})|([A-Z]d[A-Z]d[A-Z]{2}) |([A-Z]{2}d[A-Z]

d[A-Z]{2})|(GIR0AA))$',

'en-GB,cy-GB,gd',

'<a>IE </a>

']

  从以上结果可以看出,``标签用于多个国家(或地区)属性。如果我们只想抓取国家(或地区)区域,我们可以选择第二个匹配元素,如下图。

  >>> re.findall('(.*?)', html)[1]

'244,820 square kilometres'

  虽然这个方案现在可用,但如果页面发生变化,它很可能会失败。例如,表已更改为删除第二个匹配元素中的区域数据。如果我们只抓取当前的数据,我们可以忽略这种未来可能发生的变化。但是,如果我们希望将来能够再次获取这些数据,我们需要提出一个更强大的解决方案,尽可能避免这种布局更改的影响。为了使正则表达式更明确,我们可以添加它的父元素 `,它应该是唯一的,因为它有一个 ID 属性。

  >>> re.findall('Area:

(.*?)', html)

['244,820 square kilometres']

  这个迭代版本看起来好一点,但是网页更新还有很多其他的方式也会让这个正则表达式不令人满意。例如,将双引号改为单引号,在``标签之间添加额外的空格,或者更改area_label​​等。下面是一个改进版本,试图支持这些可能性。

  >>> re.findall('''.*?(.*?)''', html)

['244,820 square kilometres']

  虽然这个正则表达式更容易适应未来的变化,但它也存在构造困难、可读性差的问题。此外,还有很多其他的小布局变化让这个正则表达式不尽如人意,比如在``标签中增加了​​​​​​​​​​​​​​他们的 CSS 类或 ID。

  从这个例子可以看出,正则表达式为我们提供了一种抓取数据的捷径,但是这种方法过于脆弱,在页面更新后容易出现问题。幸运的是,有更好的数据提取解决方案,例如我们将在本章中介绍的其他抓取库。

  2美汤

  ​美丽的汤​​​

  是一个非常流行的 Python 库,它解析网页并提供方便的界面来定位内容。如果您尚未安装该模块,您可以使用以下命令安装其最新版本。

  pip install beautifulsoup4

  使用 Beautiful Soup 的第一步是将下载的 HTML 内容解析成一个汤文档。因为很多网页没有很好的 HTML 格式,Beautiful Soup 需要修复其标签的打开和关闭状态。例如,在下面这个简单网页的清单中,存在属性值和未闭合标签周围缺少引号的问题。

  

Area

Population

  如果将Population列表项解析为Area列表项的子项,而不是两个并列的列表项,我们在获取时会得到错误的结果。让我们看看Beautiful Soup是如何处理它的。

  >>> from bs4 import BeautifulSoup

>>> from pprint import pprint

>>> broken_html = 'AreaPopulation

'

>>> # parse the HTML

>>> soup = BeautifulSoup(broken_html, 'html.parser')

>>> fixed_html = soup.prettify()

>>> pprint(fixed_html)

Area

Population

  我们可以看到,使用默认的 html.parser 并不能得到正确解析的 HTML。从前面的代码片段可以看出,由于它使用了嵌套的li​​​​元素,会导致定位困难。幸运的是,我们还有其他解析器可供选择。我们可以安装LXML(详见2.2.3),或者使用​​​html5lib​​​。要安装html5lib​​​,只需使用​​pip​​。

  pip install html5lib

  现在,我们可以重复此代码,只需对解析器进行以下更改。

  >>> soup = BeautifulSoup(broken_html, 'html5lib')

>>> fixed_html = soup.prettify()

>>> pprint(fixed_html)

Area

Population

  至此,使用html5lib的​​BeautifulSoup​​​​已经能够正确解析缺少的属性引号和结束标记,并且还添加了​​和​​​标记,使其成为完整的HTML文档。使用lxml时也可以看到类似的结果。

  现在,我们可以使用find()​​​和​​​find_all()​​方法来定位我们需要的元素。

  >>> ul = soup.find('ul', attrs={'class':'country_or_district'})

>>> ul.find('li') # returns just the first match

Area

>>> ul.find_all('li') # returns all matches

[Area

, Population

  有关可用方法和参数的完整列表,请访问 Beautiful Soup 的官方文档。

  下面是示例网站中使用该方法提取国家(或地区)区域数据的完整代码。

  >>> from bs4 import BeautifulSoup

>>> url = 'http://example.python-scraping.com/places/view/United-Kingdom-239'

>>> html = download(url)

>>> soup = BeautifulSoup(html)

>>> # locate the area row

>>> tr = soup.find(attrs={'id':'places_area__row'})

>>> td = tr.find(attrs={'class':'w2p_fw'}) # locate the data element

>>> area = td.text # extract the text from the data element

>>> print(area)

244,820 square kilometres

  此代码虽然比正则表达式代码更复杂,但更易于构建和理解。此外,布局的小变化,如额外的空白和制表符属性,我们不必再担心了。我们也知道 Beautiful Soup 可以帮助我们清理页面,即使它收录不完整的 HTML,允许我们从非常不完整的 网站 代码中提取数据。

  3Lxml

  ​​​​​

  它是一个基于XML解析库libxml2的基础上构建的Python库。它是用C语言编写的,解析速度比Beautiful Soup快,但安装过程也比较复杂,尤其是在Windows下。最新的安装说明可以在这里找到。​​​​如果您自己安装库有困难,您也可以使用 Anaconda 来完成。

  您可能不熟悉 Anaconda,它是一个员工创建的包和环境管理器,主要专注于开源数据科学包。您可以按照安装说明下载并安装 Anaconda。需要注意的是,使用 Anaconda 的快速安装会将您的 PYTHON_PATH 设置为 Conda 的 Python 安装位置。

  和 Beautiful Soup 一样,使用 lxml 模块的第一步是将可能无效的 HTML 解析成统一的格式。下面是使用此模块解析相同的不完整 HTML 的示例。

  >>> from lxml.html import fromstring, tostring

>>> broken_html = 'AreaPopulation

'

>>> tree = fromstring(broken_html) # parse the HTML

>>> fixed_html = tostring(tree, pretty_print=True)

>>> print(fixed_html)

Area

Population

  同样,​​​lxml​​​可以正确解析缺少的属性和关闭标签的引号,但模块不会添加额外的​​和​​​标签。这些都不是标准 XML 的要求,所以对于 lxml,插入它们不是必须的。

  解析输入内容后,进入选择元素的步骤。这时候lxml有几种不同的方法,比如类似于Beautiful Soup的XPath选择器和find()方法。然而,对于这个例子,我们将使用 CSS 选择器,因为它们更简洁,并且可以在第 5 章解析动态内容时重用。一些读者可能已经从他们使用 jQuery 选择器的经验或它们在前面的使用中熟悉了它们——结束 Web 应用程序开发。在本章后面,我们将比较这些选择器与 XPath 的性能。要使用 CSS 选择器,您可能需要先安装 cssselect 库,如下所示。

  pip install cssselect

  现在,我们可以使用 lxml 的 CSS 选择器从示例页面中提取区域数据。

  >>> tree = fromstring(html)

>>> td = tree.cssselect('tr#places_area__row > td.w2p_fw')[0]

>>> area = td.text_content()

>>> print(area)

244,820 square kilometres

  通过在代码树上使用cssselect​​​方法,我们可以使用CSS语法选择表中ID为places_area__row​​​的行元素,然后选择类为w2p_fw的子表数据标签​​​​. 由于cssselect返回一个列表,所以我们需要获取其中的第一个结果并调用text_content方法遍历所有子元素,并返回每个元素的关联文本。在这种情况下,虽然我们只有一个元素,但此功能对于更复杂的提取示例很有用。

  作者:[德语] Katharine Jarmul,[澳大利亚] Richard Lawson

  译者:李斌

  为 Python 3.6 版本编写。

  提供示例完整源码和示例网站搭建源码,保证用户可以在本地成功复现爬取网站环境,保证网站的稳定性和可靠性以及代码运行的可用性结果重现性。

  互联网收录许多有用的数据,其中大部分是免费和公开的。但是,这些数据并不好用,它们嵌入在 网站 的架构和样式中,也需要小心提取。作为采集和理解网络上大量信息的一种方式,网络抓取技术变得越来越有用。

  本书是使用 Python 3.6 的新功能抓取 Web 数据的入门指南。本书解释了如何从静态网站中提取数据,以及如何使用数据库和文件缓存技术来节省时间和管理服务器负载,然后描述如何使用浏览器、爬虫和并发爬虫来开发更复杂的爬虫.

  使用 PyQt 和 Selenium,您可以决定何时以及如何从依赖于 JavaScript 的 网站 中抓取数据,以及更好地理解在复杂的 CAPTCHA 保护 网站 上提交表单的方法。本书还解释了如何使用 mechanize 等 Python 包进行自动化处理,如何使用 Scrapy 库创建基于类的爬虫,以及如何在真实的 网站 上实现所学的爬虫技巧。

  本书最后介绍了使用爬虫测试网站、远程爬虫技术、图像处理和其他相关主题。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线