Scrapy使用简记

1.安装scrpy

关于名字,Scrapy = S + crawl +py ???.
基于Python3.x的scrapy使用,首先配置virtualenv配置python虚拟环境,详见.
在虚拟环境中安装scrapy,使用国内豆瓣源安装:

pip install -i https://pypi.douban.com/simple scrapy
如果安装或编译出错,则使用这里已经编译好的包进行安装,同样使用pip命令安装本地文件。

安装完成之后,使用scrapy startproject jobbole命令创建jobbole项目,目录结构中spiders包下存放的是初始化生成的爬虫模板文件。

2. Scrapy框架的组成

首先上一张图
Scrapy使用简记_第1张图片

简单的来说,Scrapy由以下几部分组成:
(1)任务调度器Scheduler,调度多个异步请求任务。
(2)下载器downloader,提供专用的图片、文件下载器。
(3)数据后处理其ItemPipline.

scrapy标准的爬虫文件中有一个scrapy.Spider子类,与爬虫相关的类和方法包括Request,Response,parse,Item,ItemLoader,settings,pipeline。一个完整的爬虫流程如下:
Scrapy使用简记_第2张图片

  • 从start_urls开始,通过Request发请求。标准的Request如下:
    from url import parse
    final_url =  parse.urljoin(response.url, url)
    // 发送新的请求
    yield Request(url=final, callback=self.parse_detail, meta={})

url可以通过parse可以处理那些无域名的相对路径
callback制定另一个类成员函数进行处理
meta可以将任意数据通过dict的形式传入response中,向下传递

  • 通过yield Request可发送新的请求

  • 自定义解析函数时,函数的参数签名为(self, response)

  • 可以通过response.xpath() 、response.css()和response.re()手动获取页面内容。推荐的做法是使用scrapy提供的ItemLoader,ItemLoader会自动解析提取的值,而不用手动extrac()[0]。

  • 与ItemLoader配合的是Item,Item定义时可以设置input_processor和output_processor。Item的定义只是通过Filed()进行声明即可。

// 预置processor的种类
from scrapy.loader.processors import  Join, MapCompose, Compose,TakeFirst, Identity, MergeDict, SelectJmes


class JobboleItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field(output_processor = TakeFirst())  # TakeFirst() 返回取第一个值的函数
    post_time = scrapy.Field(output_processor = Compose(TakeFirst(), lambda x: x.strip([''])))
    tags = scrapy.Field()
    source_url = scrapy.Field(output_processor=TakeFirst())
    upvote_count = scrapy.Field(output_processor=TakeFirst())

最后在爬虫类中通过yield item将item交给ItemPipeline处理,且在item传入pipeline做进一步处理之前,会读取settings中的设置。

3. 各个模块标准化写法

(1)spider主要实现爬去任务的发送、接收response进行解析处理。主要集成scrapy.Spider去实现一些方法。

from scapy import Spider
from url import parse
from MyPackage import MyItem

class MySpider(Spider):

    name = "myspider"
    allow_domains = ['www.xxoo.com']
    start_urls = ['www.xxoo.com']

    def parse(self, response):
        value = response.xpath('//div/text()').extract()[0]
        next_url = response.xpath('//a[1]/text').extract()

        yield Request(url=parse.urljoin(response.url, next_url),callback=parse_detail, meta={extradata:'xxx'})



    def parse_detail(self, response):
        value = response.meta.extradata; // 获取额外信息
        value2 = reponse.xpath('//div//text').extract()[0]

        // 不直接通过xpath的方式进行解析,而是通过ItemLoader自动解析
        item_loader = ItemLoader(MyItem(), response=response);
        item_loader.add_xpath('id', '//div')
        item_loader.add_css('name', '.selector')
        item_loader.add_value('age', response.url)

        final_item = item_loader.load_item()
        yield final_item

(2) Item是数据容器,类似于dict但不是dict类型(可通过dict(item)的形式转换为字典类型).Item的定义只需要通过scrapy.Field定义即可,必要时可以在Field定义是添加input_processor=,或者output_processor=,接收函数,用于处理传入字段的值,配合ItemLoader使用


    from scrapy import Field,Item
    // 内置的processor,用于配合ItemLoader
    from scrapy.loader.processors import  Join, MapCompose, Compose,TakeFirst, Identity, MergeDict, SelectJmes

    def stripA(value):
        return value.strip('A')

    class MyItem(Item):
        id = Field(output_processor=stripA)
        name = Field(input_processor=TakeFirst())
        age = Field(input_processor=TakeFirst(),
        output_processor=Compose(stripA, int))
# Compose用于将函数组合起来,item中的值被compose中的函数逐一执行。
# TakeFirst()生成取首元素的函数

(3)ItemLoader用于处理response解析出的值,ItemLoader加载出来的值传入Item,会执行对应Field的output_processor/input_processor。实际上,在ItemLoader中也可以通过加入processor来对item值做处理,通常的做法是input_processor写在ItemLoader中,output_processor写在Item的Field中。


# 继承ItemLoader,重写部分方法

from scrapy.Loader import ItemLoader

class MyItemLoader(ItemLoader):

    input_processor = TakeFirst()

# 通过以上的设置,在解析所有的Item Field前都会调用TakeFirst()

(4)Pipeline是数据最终被加工的场所,可以在Pipeline中完成数据的导出、数据库存储、图片/文件自动下载,Pipeline执行前会读取setting中相关设置。可以定义普通对象的Pipeline,也可以通过重写已有的Pipeline完成特定的功能。Pipeline有特定的生命周期,通过定义生命周期函数来进行处理。


class MyPipeline(object):

    def from_settings(cls, settings):
        # 通过settings获取settings.py中的设置
        db = DbSettings.DbSettings
        return cls(db) # 生成对象之前执行,对象的初始化参数为url


    def __init__(self, db):
        self.db = db
        self.conn = pymysql.connect(db)
        self.cursor = self.conn.cursor()

    def open_spider(self,spider):
        pass

    def process_item(self, item, spider):
        # 核心处理函数
        pass

    def close_spider(self, spider):
        self.conn.commit()
        self.cursor.close()
        self.conn.close()

除了自定义的对象,scrapy提供了一系列的exporter将item导出成csv、json、xml等格式的文件,详见

from scrapy.exporters import JsonItemExporter
# 通过exporer可以导出文件,在pipeline中使用

除了手动编写自己的Pipeline进行处理,scrapy提供了一些列特殊功能的Pipeline,例如自动下载图片的ImagesPipeline和自动下载文件的FilePipeline。可以直接配置settings使用这些pipeline,也可以重写这些pipeline实现自己的需求

from scrapy.pipelines.images import ImagesPipeline

class DeriveImagesPipeline(ImagesPipeline):

    def item_completed(self, results, item, info):
        for status, value in results:
            item['face_url_path'] = value["path"]
        return super(DeriveImagesPipeline, self).item_completed(results, item, info)  # python中调用父类方法的方式

# 在自定义Pipeline中只需要关注两个方法:
# get_media_requests(self, item, info),返回一个Request对象
# item_completed(self, results, item, info),当上门的Request下载完成后回调这个方法,然后填充files或images字段

(5)settings.py文件

Pipeline的使用必须在settings.py文件中配置.

# 可以配置多个pipeline,数字越小表示执行的优先级越高.

ITEM_PIPELINES = {
   'jobbole.pipelines.JobbolePipeline': 300,
   #'jobbole.pipelines.JsonExporterPipline': 200,
   #'jobbole.pipelines.MyJsonPipeline': 200,
   #'jobbole.pipelines.DeriveImagesPipeline': 1
   #'jobbole.pipelines.MysqlPoolPipeline': 200
   #'jobbole.pipelines.MySqlDbPipeline': 200
}

settings中有一些特殊的字段,有特殊的用途,例如设定


# 设定Item中face_url字段自动下载图片
# 这里需要注意的是图片下载的字段必须是一个列表形式,否则会报错
# 原因是ImagesPipeline中会对指定images_url_field的字段进行列表遍历,然后逐个下载.
IMAGES_URLS_FIELD = 'face_url'

# 设定下载图片的本地保存路径
IMAGES_STORE = save_path

# 设置文件下载的路径
file_urls = 


# 更多的字段设置,可以打开ImagesPipeline源码,查看哪些字段被读取。

4. 未完成…

你可能感兴趣的:(数据采集)