Python中的Web Scraping 101
在这篇文章中,可以阅读作为我们最终网络抓取指南的后续内容,我们将介绍Python为您提供的几乎所有工具。我们将从更基础的到最先进的,并将涵盖每个的优点和缺点。当然,我们将无法涵盖我们讨论的每个工具的所有方面,但是这篇文章应该足以让我们知道哪些工具做什么,何时使用哪个。
注意:当我在这篇博文中谈论Python时,你应该假设我谈论Python3。
表中的内容:
- 0)Web基础知识
- 1)手动打开套接字并发送HTTP请求
- 2)urllib3和LXML
- 3)要求和BeautifulSoup
- 4)Scrapy
- 5)Selenium&Chrome -headless
- 结论
0)Web基础知识
互联网非常复杂:在浏览器中查看简单网页涉及许多基础技术和概念。我没有解释所有内容的自负,但我会向您展示您需要了解的最重要的事情,以便从网络中提取数据。
超文本传输协议
HTTP使用客户端/服务器模型,其中HTTP客户端(浏览器,您的Python程序,curl,Requests …)打开连接并向HTTP发送消息(“我希望看到该页面:/ product”)服务器(Nginx,Apache ……)。
然后服务器以响应(例如HTML代码)回答并关闭连接。 HTTP被称为无状态协议,因为每个事务(请求/响应)都是独立的。例如,FTP是有状态的。
基本上,当您在浏览器中键入网站地址时,HTTP请求如下所示:
在此请求的第一行,您可以看到多个事物:
- 正在使用的GET动词或方法,这意味着我们从特定路径请求数据:
/product/
。还有其他HTTP动词,你可以在这里看到完整列表。 - HTTP协议的版本,在本教程中我们将重点介绍HTTP 1。
- 多个标题字段
以下是最重要的标题字段:
- 主机:服务器的域名,如果没有给出端口号,则假定为80 *。*
- User-Agent:包含有关发起请求的客户端的信息,包括操作系统信息。在这种情况下,它是我在OSX上的网络浏览器(Chrome)。此标头很重要,因为它用于统计(有多少用户访问我的网站在Mobile和桌面上)或防止机器人的任何违规。因为这些头文件是由客户端发送的,所以它可以被修改(它被称为“Header Spoofing”),这正是我们将对我们的刮刀进行的操作,使我们的刮刀看起来像普通的Web浏览器。
- 接受:作为响应可接受的内容类型。有很多不同的内容类型和子类型:text / plain,text / html,image / jpeg,application / json …
- Cookie:name1 = value1; name2 = value2 …此标头字段包含名称 – 值对的列表。它被称为会话cookie,它们用于存储数据。 Cookie是网站用于对用户进行身份验证和/或在浏览器中存储数据的方式。例如,当您填写登录表单时,服务器将检查您输入的凭据是否正确,如果是,它将重定向您并在浏览器中注入会话cookie。然后,您的浏览器将随每个后续请求发送此cookie到该服务器。
- Referrer:Referrer标头包含从中请求实际URL的URL。此标头很重要,因为网站使用此标头根据用户来自何处更改其行为。例如,许多新闻网站都有付费订阅,让您只能查看帖子的10%,但如果用户来自Reddit等新闻聚合器,他们会让您查看完整内容。他们使用引荐来检查这一点。有时我们必须欺骗这个标题以获取我们想要提取的内容。
列表继续……你可以在这里找到完整的标题列表。
服务器会响应这样的事情:
在第一行,我们有一条新的信息,即HTTP代码 200 OK
。这意味着请求已成功。至于请求标头,有很多HTTP代码,分为四个公共类,2XX表示成功请求,3XX表示重定向,4XX表示不良请求(最著名的是404 Not found),5XX表示服务器错误。
然后,如果您使用Web浏览器发送此HTTP请求,浏览器将解析HTML代码,获取所有最终资产(Javascript文件,CSS文件,图像……),并将结果呈现到主窗口中。
在接下来的部分中,我们将看到使用Python执行HTTP请求的不同方法,并从响应中提取我们想要的数据。
1)手动打开套接字并发送HTTP请求
插座
在Python中执行HTTP请求的最基本方法是打开套接字并手动发送HTTP请求。
现在我们有了HTTP响应,从中提取数据的最基本方法是使用正则表达式。
常用表达
正则表达式(RE或Regex)是字符串的搜索模式。使用正则表达式,您可以在更大的文本体内搜索特定的字符/单词。
例如,您可以识别网页中的所有电话号码。您也可以替换项目,例如,您可以使用小写格式替换格式不正确的HTML中的所有大写标记。您还可以验证一些输入……
正则表达式使用的模式从左到右应用。每个源角色仅使用一次。您可能想知道为什么在进行网络抓取时了解正则表达式很重要?
毕竟,有各种不同的Python模块来解析HTML,使用XPath,CSS选择器。
在理想的语义世界中,数据易于机器读取,信息嵌入相关HTML元素内,具有有意义的属性。
但是现实世界很乱,你经常会在p元素中找到大量的文本。当您想要在这个巨大的文本中提取特定数据时,例如,价格,日期,名称……您将不得不使用正则表达式。
注意:这是一个很棒的网站来测试你的正则表达式:https://regex101.com/和一个很棒的博客,以了解更多关于它们,这篇文章将只涵盖你可以用regexp做的一小部分。
当您拥有此类数据时,正则表达式非常有用:
Price : 19.99$
我们可以用Xpath表达式选择这个文本节点,然后使用这种正则表达式来提取价格:
^Prices:s(d+.d{2})$
要在HTML标记内提取文本,使用正则表达式很烦人,但可行:
正如您所看到的,可以使用套接字手动发送HTTP请求,并使用正则表达式解析响应,但它很复杂,并且有更高级别的API可以使此任务更容易。
2)urllib3和LXML
免责声明:很容易迷失在Python的urllib世界中。你有urllib和urllib2是标准库的一部分。你也可以找到urllib3。 urllib2在Python 3中分为多个模块,urllib3不应该很快成为标准库的一部分。这整个令人困惑的事情将成为博客文章的主题。在这一部分中,我选择只讨论urllib3,因为它在Python世界中广泛使用,由Pip和请求仅命名它们。
Urllib3是一个高级软件包,允许您通过HTTP请求执行任何操作。它允许用更少的代码行完成我们在socket上做的事情。
比套接字版本简洁得多。不仅如此,API也很简单,您可以轻松完成许多工作,例如添加HTTP标头,使用代理,POST表单……
例如,如果我们决定设置一些标头并使用代理,我们只需要这样做。
看到?然而,完全相同的行数,urllib3有些东西不能轻易处理,例如,如果我们想要添加cookie,我们必须手动创建相应的标题并将其添加到请求中。
还有urllib3可以做的事情,请求不能,矿池和代理矿池的创建和管理,例如重试策略的控制。
简单地说,urllib3在请求和套接字之间就抽象而言,尽管比socket更接近请求。
这次,为了解析响应,我们将使用lxml包和XPath表达式。
XPath的
Xpath是一种使用路径表达式选择XML文档(或HTML文档)中的节点或节点集的技术。与文档对象模型一样,Xpath是自1999年以来的W3C标准。即使Xpath本身不是编程语言,它也允许您编写可以直接访问特定节点或特定节点集的表达式,而无需遍历整个HTML树(或XML树)。
将XPath视为regexp,但专门针对XML / HMTL。
要使用XPath从HTML文档中提取数据,我们需要3件事:
- 一个HTML文档
- 一些XPath表达式
- 一个将运行这些表达式的XPath引擎
首先,我们将使用我们得到的HTML感谢urllib3,我们只想从Google主页中提取所有链接,以便我们使用一个简单的XPath表达式: //a
我们将使用LXML来运行它。 LXML是一个支持XP新高的快速且易于使用的XML和HTML处理库。
安装:
pip install lxml
以下是上一段代码之后的代码:
输出应该如下所示:
你必须要记住,这个例子非常简单,并没有真正向你展示XPath的强大功能(注意:这个XPath表达式应该已经改为 //a/@href
避免不得不迭代 links
得到他们的 href
)。
如果您想了解有关XPath的更多信息,可以阅读这篇优秀的介绍。 LXML文档也写得很好,是一个很好的起点。
像regexp这样的XPath表达非常强大,是从HTML中提取信息的最快方法之一,就像正则表达式一样,XPath很快就会变得混乱,难以阅读和难以维护。
3)要求和BeautifulSoup
请求是python包的王者,下载量超过11 000 000,它是Python最常用的包。
安装:
pip install requests
使用请求(无评测)发出请求非常简单:
使用请求,可以轻松执行POST请求,处理cookie,查询参数……
对黑客新闻的身份验证
假设我们想要创建一个工具来自动将我们的博客帖子提交给Hacker新闻或任何其他论坛,比如Buffer。我们需要在发布链接之前对这些网站进行身份验证。这就是我们要求的Requests和BeautifulSoup
这是Hacker News登录表单和相关的DOM:
有三种 这个表单上的**标签,第一个隐藏了一个名为“goto”的类型,另外两个是用户名和密码。
如果您在Chrome浏览器中提交表单,您会看到有很多内容:正在设置重定向和Cookie。 Chrome会在每个后续请求中发送此Cookie,以便服务器知道您已通过身份验证。
使用请求执行此操作非常简单,它将自动为我们处理重定向,并且可以使用Session对象处理cookie。
接下来我们需要的是BeautifulSoup,这是一个Python库,可以帮助我们解析服务器返回的HTML,以确定我们是否登录。
安装:
pip install beautifulsoup4
因此,我们所要做的就是使用我们的凭据将这三个输入POST到/ login端点,并检查是否存在仅在登录后显示的元素:
为了了解有关BeautifulSoup的更多信息,我们可以尝试提取主页上的每个链接。
顺便说一句,Hacker News提供了一个功能强大的API,所以我们这样做就是一个例子,但你应该使用API而不是抓它
我们需要做的第一件事是检查Hacker News的主页,以了解我们必须选择的结构和不同的CSS类:
我们可以看到所有帖子都在一个内部
links = soup.findAll('tr', class_='athing')
然后,对于每个链接,我们将提取其ID,标题,网址和排名:
如您所见,Requests和BeautifulSoup是通过发布表单来提取数据和自动化不同内容的绝佳库。如果你想进行大规模的网络抓取项目,你仍然可以使用请求,但你需要自己处理很多事情。
当你需要刮掉很多网页时,你需要注意很多事情:
- 找到一种并行化代码的方法,使其更快
- 处理错误
- 存储结果
- 过滤结果
- 限制您的请求,以免您过度加载服务器
对我们来说幸运的是,存在可以为我们处理这些事情的工具。
4)Scrapy
Scrapy是一个功能强大的Python Web抓取框架。它提供了许多功能,可以异步下载,处理和保存网页。它处理多线程,爬行(从链接到链接以查找网站中的每个URL),站点地图爬行等等。
Scrapy还有一种称为Scrapy Shell的交互模式。使用Scrapy Shell,您可以非常快速地测试抓取代码,例如XPath表达式或CSS选择器。
Scrapy的缺点是学习曲线陡峭,需要学习很多东西。
为了跟进我们关于黑客新闻的例子,我们将编写一个Scrapy Spider,它可以删除前15页的结果,并将所有内容保存在CSV文件中。
您可以使用pip轻松安装Scrapy:
pip install Scrapy
然后,您可以使用scrapy cli为我们的项目生成样板代码:
scrapy startproject黑客_news_scraper
内 hacker_news_scraper/spider
我们将使用Spider的代码创建一个新的python文件:
Scrapy中有很多约定,这里我们定义一个起始URL数组。属性名称将用于使用Scrapy命令行调用我们的Spider。
将在每个URL上调用parse方法 start_urls
排列
然后我们需要稍微调整Scrapy,以便我们的Spider能够很好地对抗目标网站。
# Enable and configure the AutoThrottle extension (disabled by default) # See https://doc.scrapy.org/en/latest/topics/autothrottle.html AUTOTHROTTLE_ENABLED = True # The initial download delay AUTOTHROTTLE_START_DELAY = 5
您应该始终打开它,它将通过分析响应时间和调整并发线程数来确保目标网站不会被您的蜘蛛减速。
您可以使用Scrapy CLI以不同的输出格式(CSV,JSON,XML …)运行此代码:
scrapy crawl黑客-news -o links.json
就是这样现在,您将在格式良好的JSON文件中拥有所有链接。
5)Selenium&Chrome -headless
Scrapy非常适合大规模的Web抓取任务,但如果您需要使用Javascript框架编写单页面应用程序,这是不够的,因为它无法呈现Javascript代码。
刮掉这些SPA可能很有挑战性,因为通常会涉及大量的AJAX调用和websockets连接。如果性能是一个问题,您应该始终尝试重现Javascript代码,这意味着使用浏览器检查器手动检查所有网络调用,并复制包含有趣数据的AJAX调用。
在某些情况下,涉及到太多的异步HTTP调用来获取所需的数据,并且可以更容易地在无头浏览器中呈现页面。
另一个很好的用例是截取页面的截图,这就是我们将要对黑客新闻主页做的事情(再次)
您可以使用pip安装selenium包:
pip install selenium
你还需要Chromedriver:
brew install chromedriver
然后我们只需从selenium包导入Webdriver,使用headless = True配置Chrome并设置窗口大小(否则它非常小):
你应该得到一个很好的主页截图:
您可以使用Selenium API和Chrome执行更多操作,例如:
- 执行Javascript
- 填写表格
- 单击元素
- 使用CSS选择器/ XPath表达式提取元素
无头模式下的Selenium和Chrome实际上是刮掉任何你想要的东西的终极组合。您可以使用常规Chrome浏览器自动执行任何操作。
最大的缺点是Chrome需要大量的内存/ CPU能力。通过一些微调,您可以将每个Chrome实例的内存占用减少到300-400mb,但每个实例仍需要1个CPU内核。
如果您想同时运行多个Chrome实例,则需要功能强大的服务器(成本快速上涨)和持续监控资源。
结论:
以下是我们在此讨论的每种技术的快速回顾表。如果你知道一些你认为在这里有自己位置的资源,请不要犹豫在评论中告诉我们。
我希望这个概述将帮助您最好地选择您的Python抓取工具,并且您已经学习了阅读这篇文章的内容。
我在这篇文章中谈到的每一个工具都将成为未来特定博客文章的主题,我将深入探讨细节。
我在这篇文章中谈到的所有内容都是我用来构建ScrapingNinja的东西,ScrapingNinja是最简单的网络抓取API。如果您不想浪费太多时间设置所有内容,请不要犹豫,测试我们的解决方案,第一个1k API调用就在我们身上?。
请不要犹豫,在评论中告诉您有关抓取的内容,我将在下一篇文章中讨论。
快乐的刮痧