使用Python进行web抓取的新手指南

Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发。

使用基本的Python工具获得一些实践经验,以获取完整的HTML站点。

1.png

图片来源 : Jason Baker for Opensource.com.

有很多很棒的书可以帮助您学习Python,但是谁真正读了这些书呢?(提示:不是我)。
很多人觉得参考书很有用,但我通常不会从头到尾阅读全书来学习。我是通过做项目,努力搞清楚一些事情,然后读另一本书来学习。所以,暂时丢掉书,让我们学习一些Python。
下面是我用Python编写的第一个抓取项目的指南。它对Python和HTML的假定知识非常少。本文旨在说明如何使用Python库请求访问网页内容,并使用BeatifulSoup4以及JSON和pandas解析内容。我将简要介绍Selenium,但不会深入研究如何使用该库(该主题有自己的教程)。最后,我希望向您展示一些技巧和窍门,以减少网络抓取的麻烦。

安装依赖
本指南中的所有资源都可以在我的GitHub回购中找到。如果您需要安装Python 3的帮助,请查看Linux,Windows和Mac的教程。

2.png

如果你喜欢使用JupyterLab,可以使用此笔记本运行所有代码。有很多方法可以安装JupyterLab,这是其中一种:

3.png

为我们的网页抓取项目设定目标

  • 现在我们已经安装了依赖项,但是抓取网页需要什么呢?

  • 让我们退后一步,并确保阐明我们的目标。这是我成功完成Web抓取项目的要求列表 :

  • 收集值得构建有效的网络刮板的信息

  • 下载可以通过网络抓取工具合法地和道德地收集的信息

  • 了解如何在HTML代码中找到目标信息

  • 拥有正确的工具:在这种情况下,它是库BeautifulSoup和request

  • 如何解析JSON对象

  • 有足够的数据技能可以使用pandas

  • 关于HTML的评论:尽管HTML是运行Internet的野兽,但我们最需要了解的是标签的工作方式。标签是夹在尖括号括起来的标签之间的信息的集合。例如,这是一个假标签,称为“ pro-tip”:

4.png

我们可以通过调用其标签“ pro-tip”来访问其中的信息(“您需要知道的所有...”)。本教程将进一步介绍如何查找和访问标签。要进一步了解HTML基础知识,请查看本文。

在网络抓取项目中寻找什么
一些收集数据的目标比其他目标更适合于网络抓取。我的合格项目指导方针如下 :
没有可用于数据的公共API。通过API捕获结构化数据会容易得多,这将有助于阐明收集数据的合法性和道德性。需要大量的结构化数据,采用规则的,可重复的格式来证明这一点。刮网可能会很痛苦。BeautifulSoup(bs4)使此操作变得更容易,但不可避免的是需要定制的网站的个性。不需要相同的数据格式,但这确实使事情变得容易。当前存在的“边际案例”(偏离规范)越多,刮取将越复杂。
免责声明:我的法律培训为零;以下内容并非旨在作为正式的法律建议。
关于合法性,访问大量信息可能会令人陶醉,但是仅仅因为有可能并不意味着就应该这样做。

值得庆幸的是,有一些公共信息可以指导我们的道德和网络爬虫。大多数网站都有与该网站相关联的robots.txt文件,指示允许哪些刮取活动,哪些不允许。它主要是用于与搜索引擎(最终的网络抓取工具)进行交互。但是,网站上的许多信息都被视为公共信息。因此,有些人将robots.txt文件视为一组建议,而不是具有法律约束力的文档。robots.txt文件未涉及诸如道德收集和数据使用之类的主题。
在开始抓取项目之前,我问自己以下问题

  • 我要刮取受版权保护的材料吗?

  • 我的抓取活动会损害个人隐私吗?

  • 我是否发出大量可能会使服务器超载或损坏的请求?

  • 报废是否有可能暴露我不拥有的知识产权?

  • 是否有管理网站使用的服务条款,我是否遵循这些条款?

  • 我的抓取活动会减少原始数据的价值吗?(例如,我是否打算按原样重新打包数据,或者可能从原始来源中窃取网站流量)?

  • 当我抓取网站时,请确保对所有这些问题回答“否”

要想更深入地了解这些法律问题,请参阅Krotov和Silva出版的2018年出版的出版物《网络抓取的合法性和伦理》,以及塞拉斯出版的《20年的网络抓取》和《计算机欺诈和滥用法案》。

现在是时候抓取了
经过上述评估,我想到了一个项目。我的目标是提取爱达荷州所有Family Dollar商店的地址。这些商店在农村地区规模很大,因此我想了解在一个相当乡村的状态下有多少家商店。
起点是Family Dollar的位置页面。

5.png

首先,在Python虚拟环境中加载先决条件。从这里的代码是指被添加到一个Python文件(scraper.py如果你正在寻找一个名称),或在JupyterLab电池运行。

6.png

接下来,从目标URL请求数据。

7.png

BeautifulSoup将采用HTML或XML内容并将其转换为复杂的对象树。这是我们将使用的几种常见对象类型:

BeautifulSoup —— 解析的内容
标签 —— 一个标准的HTML标签,您将遇到的bs4元素的主要类型
NavigableString —— 标签内的文本字符串
注释 —— NavigableString的一种特殊类型

当我们查看request.get()输出时,还有更多要考虑的问题。我只使用page.text()将请求的页面转换为可读的内容,但是还有其他输出类型:

page.text()用于文本(最常见)
page.content()用于逐字节输出
JSON对象的page.json()
page.raw()用于原始套接字响应

我只在使用拉丁字母的纯英语网站上工作。为此,请求中的默认编码设置可以正常工作。但是,除了纯英语网站之外,还有一个丰富的互联网世界。为了确保请求正确解析内容,可以设置文本的编码:

8.png

仔细研究BeautifulSoup标签,我们看到:

bs4元素标签正在捕获HTML标签
它具有名称和属性,可以像字典一样访问:tag ['someAttribute']
如果标签具有多个具有相同名称的属性,则仅访问第一个实例
可以通过tag.contents访问标签的子级
可以使用tag.contents访问所有标记后代
你始终可以使用re.compile(“ your_string”)作为字符串访问全部内容,而不用浏览HTML树

确定如何提取相关内容
警告:此过程可能令人沮丧。

web抓取期间的提取可能是一个令人畏惧的过程,其中充满了错误。我认为解决此问题的最佳方法是从一个有代表性的示例开始,然后进行扩展(此原则适用于任何编程任务)。查看页面的HTML源代码至关重要。有很多方法可以做到这一点。
您可以在终端中使用Python查看页面的整个源代码(不建议使用)。运行此代码需要您自担风险:

9.png

虽然打印出页面的整个源代码可能适用于某些教程中显示的玩具示例,但大多数现代网站的任何页面上都有大量内容。甚至404页面也可能充满了页眉,页脚等代码。

通常最简单的方法是在您喜欢的浏览器中通过“ 查看页面源代码”浏览源代码(单击鼠标右键,然后选择“查看页面源代码”)。这是找到目标内容的最可靠方法(稍后我将解释原因)。

10.png

在这种情况下,我需要在广阔的HTML海洋中找到我的目标内容-地址,城市,州和邮政编码。通常,对页面源(ctrl + F)的简单搜索将产生目标位置所在的部分。一旦我可以实际看到目标内容的示例(至少一个商店的地址),便会寻找将该内容与其他内容区分开的属性或标签。

看来,首先,我需要通过Family Dollar商店收集爱达荷州不同城市的网址,并访问这些网站以获取地址信息。这些网址似乎都包含在href标签中。大!我将尝试使用find_all命令进行搜索:

11.png

该死的,搜索href没有产生任何结果。这可能已失败,因为href嵌套在类itemlist中。对于下一次尝试,请搜索item_list。因为“ class”是Python中的保留字,所以使用class_代替。bs4函数soup.find_all()原来是bs4函数的瑞士军刀。

12.png

有趣的是,我发现搜索特定的课程通常是一种成功的方法。我们可以通过找到对象的类型和长度来了解更多有关该对象的信息。

13.png

可以使用.contents提取此BeautifulSoup“ ResultSet”中的内容。这也是创建单个代表性示例的好时机。

14.png

使用.attr查找该对象的内容中存在哪些属性。注意:.contents通常返回正好一个项目的列表,因此第一步是使用方括号符号为该项目建立索引。

15.png

现在,我看到href是一个属性,可以像字典项一样提取它:

16.png

所有的探索为我们提供了前进的道路。这是上面我们弄清楚的逻辑的清理版本。

17.png

输出在爱达荷州要抓取的Family Dollar商店的URL的列表。

也就是说,我仍然没有地址信息!现在,需要抓取每个城市的URL以获得此信息。因此,我们使用一个具有代表性的示例重新开始该过程。

18.png


19.png

地址信息嵌套在type =“ application / ld + json”中。经过大量的地理位置抓取之后,我开始认识到这是用于存储地址信息的通用结构。幸运的是,soup.find_all()还可启用对type的搜索。

20.png

地址信息在第二个列表成员中.最后!

我使用.contents(从第二个列表项中)提取了内容(这是过滤后的一个很好的默认操作)。由于内容的输出是一个列表,因此我索引了该列表项:

21.png

看起来不错。此处显示的格式与JSON格式一致(而且,该类型的名称中确实包含“ json ”)。JSON对象的作用类似于内置嵌套字典的字典。一旦熟悉它,它实际上就是一种不错的格式(当然,它比一长串RegEx命令更容易编程)。尽管从结构上看这看起来像一个JSON对象,但它仍然是bs4对象,需要通过正式的编程转换为JSON才能作为JSON对象进行访问:

22.png

23.png

在该内容中,有一个称为地址的关键字,该关键字在较小的嵌套字典中具有所需的地址信息。可以这样检索:

24.png

现在,可以遍历爱达荷州的列表存储URL:

25.png

使用pandas清除我们的网页抓取结果

我们在词典中有大量数据,但是我们还有一些额外的缺点,这将使重用我们的数据比实际需要的更为复杂。为了完成一些最终的数据组织步骤,我们将转换为pandas数据框,删除不需要的列“ @type ”和“ country ”),并检查前五行以确保一切正常。

26.png

确保保存结果!!

27.png

我们做到了!所有爱达荷州Family Dollar商店都有一个逗号分隔的列表。

简单介绍一下Selenium和数据抓取
Selenium是用于与网页自动交互的常用实用程序。为了解释为什么有时必须使用它,让我们来看一个使用Walgreens网站的示例。Inspect Element提供了浏览器中显示的代码:

28.png


而视图页源提供了什么请求将获得的代码:

29.png

如果这两个不同意,则有一些插件可以修改源代码,因此,应在将页面加载到浏览器中之后对其进行访问。请求不能做到这一点,但是Selenium可以做到。

Selenium需要Web驱动程序来检索内容。实际上,它会打开Web浏览器,并收集此页面的内容。Selenium功能强大-它可以通过多种方式与加载的内容进行交互(请阅读文档)。使用Selenium获取数据后,继续像以前一样使用BeautifulSoup:

30.png

对于Family Dollar,我不需要Selenium,但是当呈现的内容与源代码不同时,我确实会保留Selenium。

最后
总之,使用网络抓取来完成有意义的任务时:
耐心一点、查阅手册(这些非常有用)

31.png

如果您对答案感到好奇,美国有很多Family Dollar商店

完整的源代码是:

32.png

33.png

英文原文:https://opensource.com/article/20/5/web-scraping-python
译者: Yang