超级易懂爬虫系列之爬虫框架scrapy

栏目: 编程工具 · 发布时间: 7年前

内容简介:超级易懂爬虫系列之爬虫框架scrapy

在前面的文章中,我带领大家一步一步从学习了爬虫的理论知识,相信大家为了心仪的妹纸都已经学会了,最后也动手写了一个简单的爬虫架构,之所以抽象出一个简单的架构就是为了让大家能够更好的理解爬虫框架,正所谓‘不要重复造轮子’,一个成熟框架是经过很多场景使用的考验的,其稳定性和功能的强大性远比我们自己写一个爬虫程序要好的多,因此本节就带领大家玩一下常见的爬虫框架scrapy。

python常见的爬虫架构一般包括pyspider和scrapy,前者是国人搞的,容易上手,但是在对windows的支持性不是很好,在win下很容易出现一些奇怪的bug,如很容易出现‘python已停止运行’这样的错误,因此本节以scrapy框架为例向大家讲解。

环境的搭建

首先需要安装scrapy,因为本人使用的是windows操作系统,因此以windows为例,打开cmd,然后输入如下命令

pip install Scrapy

输入该命令后就可以看到会自动下载scrapy相关组件,如图:

超级易懂爬虫系列之爬虫框架scrapy

出现如上图所示即表示正在下载相关组件,我们只需要等待即可,当命令行窗口出现Successfully installed字样就表示安装成功,如图

超级易懂爬虫系列之爬虫框架scrapy

如图即表示安装成功,我们还可以验证下,命令行输入scrapy,出现如下内容就表示确实安装成功。

超级易懂爬虫系列之爬虫框架scrapy

scrapy的使用

这是官方文档: https://doc.scrapy.org/en/latest/index.html

既然是学习框架的使用,那么我们首先来看一下官方给出的架构图了解下整个框架的执行流程大概是怎样的。

超级易懂爬虫系列之爬虫框架scrapy

整个架构最核心的是当中的ENGINE,即执行引擎,主要用来负责控制系统所有组件之间的数据流,这些组件主要包括:

  • scheduler主要用来接收来自引擎的requests请求,然后将其入队,等到需要的时候在将队列中的Requests对象传递给引擎,这就类似于我们自己写的爬虫架构的url管理器的部分角色。只不过我们的那个架构较为简单,只是把url放到集合中,而此处是把Request对象放到队列中
  • downloader负责抓取网页,然后将抓取到的结果Response对象传递给引擎,然后引擎将其传递给spider处理,这和我们自己写的爬虫架构中的网页下载器功能类似
  • spider 该组件是用户自定义的类,通常继承于scrapy.Spider。用来解析Response对象,然后从中提取出item(scrapy中的组件,实质上是用来保存数据),这和我们自定义组件中的spider_main功能类似
  • item pipelines:用来处理spider组件获取的items,如去重,持久化等,主要用来保存数据。这个和我们前面自定义架构中提到的output_data模块类似。

通过对这些组件的介绍,我们可以看到这和我们前面自定义的爬虫架构基本类似,只不过我们那个很简单而已,这也是为何前面要总结一下爬虫架构的原因,因为这样能够帮助我们更容易去理解复杂的框架。

介绍完了该框架的核心组件,接下来看下这些组件之间是如何协同工作的,即数据流是如何传递的。我们仔细看上面的架构图,会发现上面标注着一下数字和箭头,这就是整个框架的数据流的流程图。因此整个框架的工作原理如下:

  1. 引擎从spider组件中获取一个初始Request请求
  2. 引擎调度Request将其入队到Scheduler组件中,同时获取下一个待爬取的请求
  3. Scheduler组件返回下一个带爬取的Request请求给引擎
  4. 引擎将获取到的Request请求传递给downloader组件
  5. downloader组件获取到请求之后会下载该页面,下载完成之后会生成一个Response对象,然后将其返回给引擎
  6. 引擎从downloader组件中接收返回的Response对象,然后将其传递给Spider组件处理
  7. Spider组件处理接收到的Response对象,从中解析出item和新的Request请求,然后将其返回给引擎
  8. 引擎将Spider组件解析的item传递给item pipelines组件,同时将解析的Request请求传递给Scheduler组件入队,然后从Scheduler组件中获取下一个待爬取的Request请求。
  9. 重复上述过程,直至Scheduler组件中无Request请求为止

从这个执行过程可以看到,引擎起到调度作用,整个执行流程和我们自定义爬虫架构的执行流程几乎一模一样,只不过没这个复杂而已。

更多详细内容大家可以去官网看: https://doc.scrapy.org/en/latest/topics/architecture.html

Request

在前面的数据流程图中反复提到了Request对象,这个是scrapy内部自己定义的对象,该对象代表一个http请求。其定义如下:

class scrapy.http. Request ( url [ , callback , method=’GET’ , headers , body , cookies , meta , encoding=’utf-8′ , priority=0 , dont_filter=False , errback ] )

参数很多,其中我们比较关心的是url参数和callback参数,url参数用来表示请求的url,callback参数表示回调函数,当该url被downloader组件下载完成后会生成一个Response对象,且会将其以第一个参数的形式自动传递给该回调函数。

其常用代码如下:

def parse(self, response):
    print response.text
 
Request('http://www.baidu.com', parse)#回调parse函数

其余各个参数的详细意义,大家感兴趣的话可以看: https://doc.scrapy.org/en/latest/topics/request-response.html#scrapy.http.Request

scrapy框架介绍的差不多了,接下来看看如何使用,首先打开cmd,切换到我们想创建工程的目录下,执行如下命令:

<span class="n">scrapy</span> <span class="n">startproject</span> <span class="n">myproject</span> <span class="p">[</span><span class="n">project_dir</span><span class="p">]</span>

该命令会在project_dir目录下自动创建一个名为myproject的scrapy工程,如果不指定project_dir则project_dir会和myproject一样,通常我们不需要指定该参数。如图

超级易懂爬虫系列之爬虫框架scrapy

然后我们在对应的工程下会看到scrapy为我们自动创建了如下文件:

超级易懂爬虫系列之爬虫框架scrapy

这些文件和我们前面提到的scrapy组件基本一一对应。我们只需要在spiders中自定义spider组件重写scrapy为我们自动生成的parse函数的逻辑即可,注意settings.py是整个scrapy为我们的工程生成的配置文件,如果是自动生成的,里头很多配置属性都注释起来了,其中的ITEM_PIPELINES如果我们要在pipelines.py中处理我们的item的话需要我们将注释去掉,不然框架是不会执行我们在pipelines.py中写的代码的。这一点需要注意。

好了现在我们就开始用scrapy框架来改写前面我们写的爬取妹纸图的程序,为了让大家超级易懂,还是先易后难,一步一步扩充其功能。

spider.py

首先打开工程的spiders目录下的spider.py,这个就是需要我们自定义的类,即框架中的spider组件。代码如下:

# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
import scrapy
from scrapy_study.items import ImageItem
 
#定义spider组件,继承自scrapy.Spider
class Spider(scrapy.Spider):
    print 'enter spider'
 
    name = "spider_girl"
    allowed_domains = ["iyangzi.com"]
    start_urls = ["http://iyangzi.com/?p=21"] #指定需要爬取的起始url
 
 
     #只需要重写该函数即可,框架会自动回调该函数
    def parse(self, response):
        print 'start parse'
        soup = BeautifulSoup(response.text, 'html.parser', from_encoding='utf-8')
        all_img = soup.find('div', class_='post-content').find_all('img')
 
        img_items=[]
        for img in all_img:
            src = img['src']
            item=ImageItem()  #实例化item对象,该对象是我们在items.py中定义的
            item['img_src']=src
            img_items.append(item)
        return img_items

代码注释很详细,需要注意的是name,start_urls这两个字段是必须这么写的,当然也可以不这么写,这个我们在后面再讲,免得搞复杂了。主要就是重写parse函数,该函数的第一个参数response就是框架返回的Response对象。然后通过解析器对该response进行解析,此处为了和前面的内容衔接使用的是BeautifulSoup。

需要注意的是scrapy默认不能在IDE中调试,如果要在IDE中运行,可以在项目的根目录下创建一个entry.py模块,然后在该文件中添加如下代码:

from scrapy.cmdline import execute
execute(['scrapy', 'crawl', 'spider_girl'])

execute函数[]参数的第三个值即是我们自定义的spider组件中的name字段的值,必须一一对应,然后运行时直接run entry.py即可。当然如果是pycharm的话还可以在run配置中配置一下即可,具体操作请自行百度解决。

如果程序运行时出现win32 error错误是因为未安装pywin32模块,只需要下载安装即可,下载地址: https://sourceforge.net/projects/pywin32/files/pywin32/Build%20221/

items.py

接下来就是items.py

import scrapy
 
#定义item组件,继承自scrapy.Item
class ImageItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    img_src=scrapy.Field()

定义item组件,继承自scrapy.Item即可,这样做的好处是,当我们在spider组件的parse函数中实例化item然后返回时框架会直接讲其传递给pipelines组件处理。这样就达到了讲数据抓取与处理分离的目的。如果不这么做,需要我们自己处理,这么做之后框架会替我们完成这个步骤

pipelines.py

然后就是pipelines.py,代码如下:

# -*- coding: utf-8 -*-
 
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
import os
import urllib2
 
from items import ImageItem
class ScrapyStudyPipeline(object):
    print 'enter pipelines'
    
    count=1
    girl_dir = 'C:\Users\htq\Desktop\girl_'
    if not os.path.exists(girl_dir):
        os.mkdir(girl_dir)
    os.chdir(girl_dir)
 
    def process_item(self, item, spider):
        if isinstance(item,ImageItem):
            src=item['img_src']
            name = 'iyangzi_' + str(self.count)
            with open(name + '.jpg', 'ab') as img_object:
                img_content = urllib2.urlopen(src).read()
                img_object.write(img_content)
                img_object.flush()
            self.count+=1
        return item

可以看到和前面不同的是该类没有继承scrapy框架的某个类,既然没继承,那框架怎么能够回调process_item函数呢?答案就是在setting.py中进行配置,注释中也提醒了我们需要在配置文件中进行配置

Don't forget to add your pipeline to the ITEM_PIPELINES setting

如果我们使用的是scrapy自动为我们生成的整个工程结构的话,该配置默认是注释掉的,需要我们把注释去掉使得该配置生效。如下是去掉注释后的代码:

# Configure item pipelines
# See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
    'scrapy_study.pipelines.ScrapyStudyPipeline': 300,
}

这样scrapy框架就可以回调process_item函数,我们只需要在该函数中处理item即可。该函数默认定义如下:

def process_item(self, item, spider):

其中的item我们期望是在items中定义的item组件类型,如此处的ImageItem,spider期望是我们自定义的spider对象类型。所以在使用前可以使用isinstance判断下。

好了整个工程就用scrapy框架改写好了,是不是so easy,因为很多事情框架都为我们做好了,接下来运行下程序,可以看到在磁盘的C:\Users\htq\Desktop\girl_目录下已经自动为我们下载好了妹纸图,和之前不使用框架的效果一样。如图:

超级易懂爬虫系列之爬虫框架scrapy

是不是很简单,而且可以明显的感觉到使用框架速度比之前我们自己写的爬取妹纸图的程序速度更快。基本上几秒搞定。

这样我们就基本学会了scrapy框架如何使用,其它更多复杂功能将会以超级易懂爬虫系列的形式讲解,更多关于爬虫的干货,请继续关注超级易懂爬虫系列!

注:本文首次发表于www.huqi.tk,谢绝转载,如需转载,请注明出处:www.huqi.tk


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learn Python 3 the Hard Way

Learn Python 3 the Hard Way

Zed A. Shaw / Addison / 2017-7-7 / USD 30.74

You Will Learn Python 3! Zed Shaw has perfected the world’s best system for learning Python 3. Follow it and you will succeed—just like the millions of beginners Zed has taught to date! You bring t......一起来看看 《Learn Python 3 the Hard Way》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

SHA 加密
SHA 加密

SHA 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具