网站建设有技术的公司,大同网站建设开发,聚美优品一个专注于做特价的网站,最火的营销方式文章目录 前言Scrapy是什么Scrapy的结构Scrapy的工作原理 Scrapy的用法明确目标与分析过程代码实现——创建项目代码实现——编辑爬虫代码实现——定义数据代码实操——设置代码实操——运行 复习 前言
前两关#xff0c;我们学习了能提升爬虫速度的进阶知识——协程#xf… 文章目录 前言Scrapy是什么Scrapy的结构Scrapy的工作原理 Scrapy的用法明确目标与分析过程代码实现——创建项目代码实现——编辑爬虫代码实现——定义数据代码实操——设置代码实操——运行 复习 前言
前两关我们学习了能提升爬虫速度的进阶知识——协程并且通过项目实操将协程运用于抓取薄荷网的食物数据。
可能你在体验开发一个爬虫项目的完整流程时会有这样的感觉原来要完成一个完整的爬虫程序需要做这么多琐碎的工作。
比如要导入不同功能的模块还要编写各种爬取流程的代码。而且根据不同的项目每次要编写的代码也不同。
不知道你会不会有这样的想法能不能有一个现成的爬虫模板让我们拿来就能套用就像PPT模板一样。我们不需要管爬虫的全部流程只要负责填充好爬虫的核心逻辑代码就好。要是有的话我们编写代码一定会很方便省事。
其实在Python中还真的存在这样的爬虫模板只不过它的名字是叫框架。
一个爬虫框架里包含了能实现爬虫整个流程的各种模块就像PPT模板一开始就帮你设置好了主题颜色和排版方式一样。
这一关我们要学习的就是一个功能强大的爬虫框架——Scrapy。
Scrapy是什么
以前我们写爬虫要导入和操作不同的模块比如requests模块、gevent库、csv模块等。而在Scrapy里你不需要这么做因为很多爬虫需要涉及的功能比如麻烦的异步在Scrapy框架都自动实现了。
我们之前编写爬虫的方式相当于在一个个地在拼零件拼成一辆能跑的车。而Scrapy框架则是已经造好的、现成的车我们只要踩下它的油门它就能跑起来。这样便节省了我们开发项目的时间。 下面我们来了解Scrapy的基础知识包括Scrapy的结构及其工作原理。
Scrapy的结构 上面的这张图是Scrapy的整个结构。你可以把整个Scrapy框架看成是一家爬虫公司。最中心位置的Scrapy Engine(引擎就是这家爬虫公司的大boss负责统筹公司的4大部门每个部门都只听从它的命令并只向它汇报工作。
我会以爬虫流程的顺序来依次跟你介绍Scrapy爬虫公司的4大部门。
Scheduler(调度器)部门主要负责处理引擎发送过来的requests对象即网页请求的相关信息集合包括paramsdatacookiesrequest headers…等会把请求的url以有序的方式排列成队并等待引擎来提取功能上类似于gevent库的queue模块。
Downloader下载器部门则是负责处理引擎发送过来的requests进行网页爬取并将返回的response爬取到的内容交给引擎。它对应的是爬虫流程【获取数据】这一步。
Spiders(爬虫)部门是公司的核心业务部门主要任务是创建requests对象和接受引擎发送过来的responseDownloader部门爬取到的内容从中解析并提取出有用的数据。它对应的是爬虫流程【解析数据】和【提取数据】这两步。
Item Pipeline数据管道部门则是公司的数据部门只负责存储和处理Spiders部门提取到的有用数据。这个对应的是爬虫流程【存储数据】这一步。
Downloader Middlewares下载中间件的工作相当于下载器部门的秘书比如会提前对引擎大boss发送的诸多requests做出处理。
Spider Middlewares爬虫中间件的工作则相当于爬虫部门的秘书比如会提前接收并处理引擎大boss发送来的response过滤掉一些重复无用的东西。 Scrapy的工作原理
你会发现在Scrapy爬虫公司里每个部门都各司其职形成了很高效的运行流程。
这套运行流程的逻辑很简单就是引擎大boss说的话就是最高需求。 上图展现出的也是Scrapy框架的工作原理——引擎是中心其他组成部分由引擎调度。
在Scrapy里整个爬虫程序的流程都不需要我们去操心且Scrapy中的程序全部都是异步模式所有的请求或返回的响应都由引擎自动分配去处理。
哪怕有某个请求出现异常程序也会做异常处理跳过报错的请求继续往下运行程序。
在一定程度上Scrapy可以说是非常让人省心的一套爬虫框架。
Scrapy的用法
现在你已经初步了解Scrapy的结构以及工作原理。接下来为了让你熟悉Scrapy的用法我们使用它来完成一个小项目——爬取豆瓣Top250图书。 明确目标与分析过程
依旧是遵循写代码的三个步骤明确目标、分析过程、代码实现来完成项目。我会在代码实现的步骤重点讲解Scrapy的用法。
首先要明确目标。请你务必打开以下豆瓣Top250图书的链接。
https://book.douban.com/top250
豆瓣Top250图书一共有10页每页有25本书籍。我们的目标是先只爬取前三页书籍的信息也就是爬取前75本书籍的信息包含书名、出版信息和书籍评分。
接着我们来分析网页。既然我们要爬取书籍信息我们就得先判断这些信息被存在了哪里。
判断的方法你应该了然于胸。赶紧右击打开“检查”工具点开Network刷新页面然后点击第0个请求top250看Response.
我们能在里面翻找到书名、出版信息说明我们想要的书籍信息就藏在这个网址的HTML里。 确定书籍信息有存在这个网址的HTML后我们就来具体观察一下这个网站。
你点击翻到豆瓣Top250图书的第2页。 你会观察到网址发生了变化后面多了?start25。我们猜想后面的数字是代表一页的25本书籍。
你可以翻到第3页验证一下我们的猜想是不是正确的。 事实证明我们猜对了。每翻一页网址后面的数字都会增加25说明这个start的参数就是代表每页的25本书籍。
这么一观察我们要爬取的网址的构造规律就出来了。只要改变?start后面的数字翻一页加25我们就能得到每一页的网址。
找到了网址的构造规律我们可以重点来分析HTML的结构看看等下怎么才能提取出我们想要的书籍信息。
仍旧是右击打开“检查”工具点击Elements再点击光标把鼠标依次移到书名、出版信息、评分处就能在HTML里找到这些书籍信息。如下图《追风筝的人》的书籍信息就全部放在table width100%标签里。 很快你就会发现其实每一页的25本书籍信息都分别藏在了一个table width100%标签里。不过这个标签没有class属性也没有id属性不方便我们提取信息。 我们得再找一个既方便我们提取又能包含所有书籍信息的标签。
在table width100%标签下的tr classitem元素刚好都能满足我们的要求既有class属性又包含了书籍的信息。
我们只要取出tr classitem元素下a元素的title属性的值、p classpl元素、span classrating_nums元素就能得到书名、出版信息和评分的数据。 页面分析完毕接着进入代码实现的步骤。
代码实现——创建项目
从这里开始我会带你使用Scrapy编写我们的项目爬虫。其中会涉及到很多Scrapy的用法请你一定要认真地看
如果你想在自己本地的电脑使用Scrapy需要提前安装好它。安装方法Windows在终端输入命令pip install scrapymac在终端输入命令pip3 install scrapy按下enter键
首先要在本地电脑打开终端windowsWinR输入cmdmaccommand空格搜索“终端”然后跳转到你想要保存项目的目录下。
假设你想跳转到E盘里名为Python文件夹中的Pythoncode子文件夹。你需要再命令行输入e:就会跳转到e盘再输入cd Python就能跳转到Python文件夹。接着输入cd Pythoncode就能跳转到Python文件夹里的Pythoncode子文件夹。
然后再输入一行能帮我们创建Scrapy项目的命令scrapy startproject doubandouban就是Scrapy项目的名字。按下enter键一个Scrapy项目就创建成功了。 整个scrapy项目的结构如下图所示 Scrapy项目里每个文件都有特定的功能比如settings.py 是scrapy里的各种设置。items.py是用来定义数据的pipelines.py是用来处理数据的它们对应的就是Scrapy的结构中的Item Pipeline数据管道。
现在或许你还看不懂它们没关系事情将会一点点变清晰。我们来讲解它们。
代码实现——编辑爬虫
如前所述spiders是放置爬虫的目录。我们可以在spiders这个文件夹里创建爬虫文件。我们来把这个文件命名为top250。后面的大部分代码都需要在这个top250.py文件里编写。 先在top250.py文件里导入我们需要的模块。
import scrapy
import bs4导入BeautifulSoup用于解析和提取数据这个应该不需要我多做解释。在第2关、第3关的时候你就已经对它非常熟稔。
导入scrapy是待会我们要用创建类的方式写这个爬虫我们所创建的类将直接继承scrapy中的scrapy.Spider类。这样有许多好用属性和方法就能够直接使用。
接着我们开始编写爬虫的核心代码。
在Scrapy中每个爬虫的代码结构基本都如下所示
class DoubanSpider(scrapy.Spider):name doubanallowed_domains [book.douban.com]start_urls [https://book.douban.com/top250?start0]def parse(self, response):print(response.text)第1行代码定义一个爬虫类DoubanSpider。就像我刚刚讲过的那样DoubanSpider类继承自scrapy.Spider类。
第2行代码name是定义爬虫的名字这个名字是爬虫的唯一标识。name douban’意思是定义爬虫的名字为douban。等会我们启动爬虫的时候要用到这个名字。
第3行代码allowed_domains是定义允许爬虫爬取的网址域名不需要加https://。如果网址的域名不在这个列表里就会被过滤掉。
为什么会有这个设置呢当你在爬取大量数据时经常是从一个URL开始爬取然后关联爬取更多的网页。比如假设我们今天的爬虫目标不是爬书籍信息而是要爬豆瓣图书top250的书评。我们会先爬取书单再找到每本书的URL再进入每本书的详情页面去抓取评论。
allowed_domains就限制了我们这种关联爬取的URL一定在book.douban.com这个域名之下不会跳转到某个奇怪的广告页面。
第4行代码start_urls是定义起始网址就是爬虫从哪个网址开始抓取。在此allowed_domains的设定对start_urls里的网址不会有影响。
第6行代码parse是Scrapy里默认处理response的一个方法中文是解析。
你或许会好奇这里是不是少了一句类似requests.get()这样的代码的确是在这里我们并不需要写这一句。scrapy框架会为我们代劳做这件事写好你的请求接下来你就可以直接写对响应如何做处理我会在后面为你做示例。
了解完爬虫代码的基础结构我们继续来完善爬取豆瓣Top图书的代码。 豆瓣Top250图书一共有10页每一页的网址我们都知道。我们可以选择把10页网址都塞进start_urls的列表里。
但是这样的方式并不美观而且如果要爬取的是上百个网址全部塞进start_urls的列表里的话代码就会非常长。
其实我们可以利用豆瓣Top250图书的网址规律用for循环构造出每个网址再把网址添加进start_urls的列表里。这样代码会美观得多。 完善后的代码如下
class DoubanSpider(scrapy.Spider):name doubanallowed_domains [book.douban.com]start_urls []for x in range(3):url https://book.douban.com/top250?start str(x * 25)start_urls.append(url)我们只先爬取豆瓣Top250前3页的书籍信息。
接下来只要再借助parse方法处理response借助BeautifulSoup来取出我们想要的书籍信息的数据代码即可完成。
我们前面在分析项目过程的时候已经知道书籍信息都藏在了哪些元素里现在可以利用find_all和find方法提取出来。比如书名是元素下元素的title属性的值出版信息在
元素里评分在元素里。 按照过去的知识我们可能会把代码写成这个模样
import scrapy
import bs4
from ..items import DoubanItemclass DoubanSpider(scrapy.Spider):
#定义一个爬虫类DoubanSpider。name douban#定义爬虫的名字为douban。allowed_domains [book.douban.com]#定义爬虫爬取网址的域名。start_urls []#定义起始网址。for x in range(3):url https://book.douban.com/top250?start str(x * 25)start_urls.append(url)#把豆瓣Top250图书的前3页网址添加进start_urls。def parse(self, response):#parse是默认处理response的方法。bs bs4.BeautifulSoup(response.text,html.parser)#用BeautifulSoup解析response。datas bs.find_all(tr,class_item)#用find_all提取tr classitem元素这个元素里含有书籍信息。for data in datas:#遍历datas。title data.find_all(a)[1][title]#提取出书名。publish data.find(p,class_pl).text#提取出出版信息。score data.find(span,class_rating_nums).text#提取出评分。print([title,publish,score])#打印上述信息。
按照过去我们会把书名、出版信息、评分分别赋值然后统一做处理——或是打印或是存储。但在scrapy这里事情却有所不同。
spiders如top250.py只干spiders应该做的事。对数据的后续处理另有人负责。
代码实现——定义数据
在scrapy中我们会专门定义一个用于记录数据的类。
当我们每一次要记录数据的时候比如前面在每一个最小循环里都要记录“书名”“出版信息”“评分”。我们会实例化一个对象利用这个对象来记录数据。
每一次当数据完成记录它会离开spiders来到Scrapy Engine引擎引擎将它送入Item Pipeline数据管道处理。
定义这个类的py文件正是items.py。
我们已经知道我们要爬取的数据是书名、出版信息和评分我们来看看如何在items.py里定义这些数据。代码如下
import scrapy
#导入scrapy
class DoubanItem(scrapy.Item):
#定义一个类DoubanItem它继承自scrapy.Itemtitle scrapy.Field()#定义书名的数据属性publish scrapy.Field()#定义出版信息的数据属性score scrapy.Field()#定义评分的数据属性第1行代码我们导入了scrapy。目的是我们等会所创建的类将直接继承scrapy中的scrapy.Item类。这样有许多好用属性和方法就能够直接使用。比如到后面引擎能将item类的对象发给Item Pipeline数据管道处理。
第3行代码我们定义了一个DoubanItem类。它继承自scrapy.Item类。
第5、7、9行代码我们定义了书名、出版信息和评分三种数据。scrapy.Field()这行代码实现的是让数据能以类似字典的形式记录。你可能不太明白这句话的含义没关系。我带你来体验一下你就能感受到是怎样一回事
import scrapy
#导入scrapy
class DoubanItem(scrapy.Item):
#定义一个类DoubanItem它继承自scrapy.Itemtitle scrapy.Field()#定义书名的数据属性publish scrapy.Field()#定义出版信息的数据属性score scrapy.Field()#定义评分的数据属性book DoubanItem()
# 实例化一个DoubanItem对象
book[title] 海边的卡夫卡
book[publish] [日] 村上春树 / 林少华 / 上海译文出版社 / 2003
book[score] 8.1
print(book)
print(type(book))
运行结果
{publish: [日] 村上春树 / 林少华 / 上海译文出版社 / 2003,score: 8.1,title: 海边的卡夫卡}
class __main__.DoubanItem你会看到打印出来的结果的确和字典非常相像但它却并不是dict它的数据类型是我们定义的DoubanItem属于“自定义的Python字典”。我们可以利用类似上述代码的样式去重新写top250.py。如下所示
import scrapy
import bs4
from ..items import DoubanItem
# 需要引用DoubanItem它在items里面。因为是items在top250.py的上一级目录所以要用..items这是一个固定用法。class DoubanSpider(scrapy.Spider):
#定义一个爬虫类DoubanSpider。name douban#定义爬虫的名字为douban。allowed_domains [book.douban.com]#定义爬虫爬取网址的域名。start_urls []#定义起始网址。for x in range(3):url https://book.douban.com/top250?start str(x * 25)start_urls.append(url)#把豆瓣Top250图书的前3页网址添加进start_urls。def parse(self, response):#parse是默认处理response的方法。bs bs4.BeautifulSoup(response.text,html.parser)#用BeautifulSoup解析response。datas bs.find_all(tr,class_item)#用find_all提取tr classitem元素这个元素里含有书籍信息。for data in datas:#遍历data。item DoubanItem()#实例化DoubanItem这个类。item[title] data.find_all(a)[1][title]#提取出书名并把这个数据放回DoubanItem类的title属性里。item[publish] data.find(p,class_pl).text#提取出出版信息并把这个数据放回DoubanItem类的publish里。item[score] data.find(span,class_rating_nums).text#提取出评分并把这个数据放回DoubanItem类的score属性里。print(item[title])#打印书名。yield item#yield item是把获得的item传递给引擎。在3行我们需要引用DoubanItem它在items里面。因为是items在top250.py的上一级目录所以要用…items这是一个固定用法。
当我们每一次要记录数据的时候比如前面在每一个最小循环里都要记录“书名”“出版信息”“评分”。我们会实例化一个item对象利用这个对象来记录数据。
每一次当数据完成记录它会离开spiders来到Scrapy Engine引擎引擎将它送入Item Pipeline数据管道处理。这里要用到yield语句。
yield语句你可能还不太了解这里你可以简单理解为它有点类似return不过它和return不同的点在于它不会结束函数且能多次返回信息。 如果用可视化的方式来呈现程序运行的过程就如同上图所示爬虫Spiders会把豆瓣的10个网址封装成requests对象引擎会从爬虫Spiders里提取出requests对象再交给调度器Scheduler让调度器把这些requests对象排序处理。
然后引擎再把经过调度器处理的requests对象发给下载器Downloader下载器会立马按照引擎的命令爬取并把response返回给引擎。
紧接着引擎就会把response发回给爬虫Spiders这时爬虫会启动默认的处理response的parse方法解析和提取出书籍信息的数据使用item做记录返回给引擎。引擎将它送入Item Pipeline数据管道处理。
代码实操——设置
到这里我们就用代码编写好了一个爬虫。不过实际运行的话可能还是会报错。
原因在于Scrapy里的默认设置没被修改。比如我们需要修改请求头。点击settings.py文件你能在里面找到如下的默认设置代码
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT douban (http://www.yourdomain.com)# Obey robots.txt rules
ROBOTSTXT_OBEY True请你把USER _AGENT的注释取消删除#然后替换掉user-agent的内容就是修改了请求头。
又因为Scrapy是遵守robots协议的如果是robots协议禁止爬取的内容Scrapy也会默认不去爬取所以我们还得修改Scrapy中的默认设置。
把ROBOTSTXT_OBEYTrue改成ROBOTSTXT_OBEYFalse就是把遵守robots协议换成无需遵从robots协议这样Scrapy就能不受限制地运行。
修改后的代码应该如下所示
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36# Obey robots.txt rules
ROBOTSTXT_OBEY False现在我们已经编写好了spider也修改好了setting。万事俱备只欠东风——运行Scrapy。
代码实操——运行
想要运行Scrapy有两种方法一种是在本地电脑的终端跳转到scrapy项目的文件夹跳转方法cd文件夹的路径名然后输入命令行scrapy crawl doubandouban 就是我们爬虫的名字。 另一种运行方式需要我们在最外层的大文件夹里新建一个main.py文件与scrapy.cfg同级。 我们只需要在这个main.py文件里输入以下代码点击运行Scrapy的程序就会启动。
from scrapy import cmdline
#导入cmdline模块,可以实现控制终端命令行。
cmdline.execute([scrapy,crawl,douban])
#用execute方法输入运行scrapy的命令。第1行代码在Scrapy中有一个可以控制终端命令的模块cmdline。导入了这个模块我们就能操控终端。
第3行代码在cmdline模块中有一个execute方法能执行终端的命令行不过这个方法需要传入列表的参数。我们想输入运行Scrapy的代码scrapy crawl douban就需要写成[‘scrapy’,‘crawl’,‘douban’]这样。
至此Scrapy的用法我们学完啦。
值得一提的是在本关卡中为了教学方便理解先写了爬虫再定义数据。但是在实际项目实战中常常顺序却是相反的——先定义数据再写爬虫。所以流程图应如下 细心的你可能会发现这一关的内容没有涉及到存储数据的步骤。
是的存储数据需要修改pipelines.py文件。这一关的内容已经很充实所以这个知识点我们留到下一关再讲。
复习
最后是这一关的重点知识的复习。
Scrapy的结构—— Scrapy的工作原理—— Scrapy的用法—— 下一关我们准备用Scrapy来实操一个大项目——爬取人气企业的招聘信息。
下关见啦~