Scrapy结构

http://scrapy-chs.readthedocs.io/zh_CN/1.0/intro/overview.html

scrapy 使用Twisted 这个异步网络库来处理网络通信,使用python写的爬虫框架。

scrapy的构造

Scrapy引擎(Engine):                           负责控制数据流在系统的所有组件中流动,并在相应的动作发生时出发事件。

Scheduler 调度器:                                 从引擎接收Request并将它们入队,以便之后引擎请求request是提供给引擎。

Donwnloader 下载器:                            负责获取页面数据并提供给引擎,而后提供给Spider,或额外跟进的URL的类。每个Spider负责处理一个(或一些)特定网站。

Item Pipeline 数据传递管道:                  负责处理被Spider提出出来的item。典型的处理有清理验证及持久化(例存储到数据库中)。

Downloader middlewares 下载器中间件: 是一个在引擎和下载器中间的特定钩子(specific hook ),处理Downloader传递给引擎的Response。中间件通过插入自定义代码,扩展Scrapy的功能

Spider middlewares Spider中间件:        是一个在引擎和Spider中间的特定钩子,处理spider的输入(response)和输出(Item及request )

Spider :                                                      包含初始的URL,解析相应的response,提取目标items和requests.

scrapy中的数据流程

1) 引擎打开一个网站,找到该网站的Spider并向该Spider请求第一个要爬取的URL。

2) 引擎从spider中获取初始要爬取的URL ,并传给调度器(sheduler)处理验证筛选URL的规则。

3) 引擎向调度器请求下一个要爬取的URL

4) 调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求request 方向)转发给下载器

5) 下载器下载完页面,返回response,通过下载中间件(返回response方向)发送给引擎

6) 引擎从下载器中接收到Response并通过spider中间件(输入方向)发送给spider处理

7)spider处理response并返回提出的item及新的request给引擎

8)引擎 将spider返回的item和request分别发给item pipeline 和调度器sheduler 处理

9)重复第3步,直到调度器中没有更多的request,引擎关闭网站。 

在命令行中移动到想创建项目的目录下,输入指令 scrapy startproject cnblogSpider 就可创建一个名为cnblogSpider的项目。创建后会出现如下目录文件

scrapy.cfg:项目部署文件

cnblogSpiders/:该项目的Python模块,之后可在此加入代码

cnblogSpiders/settings.py: 项目的配置文件

cnblogSpider/spiders/:放置spider代码的目录

创建spider类,将脚本放在cnblogSpider/spiders/目录下,命名为cnblogs_spider.py

 该类需要继承scrapy.Spider,并定义三个属性 name(爬虫的名字,具有唯一性),start_urls(初始URL列表),parse(response)(解析传入的response,返回提取的目标数据)。

import  scrapy

from cnblogSpider.items import CnblogspiderItem

from scrapy.selector import Selector

class CnblogsSpider(scrapy.Spider):

    name="cnblogs"

    allowed_domains=["cnblogs.com"]

    start_urls=["http://www.cnblogs.com/qiyeboy/default.html?page=1"]

    def parse(self,response):

        papers=response.xpath('//*[@id="mainContent"]/div/div[@class="day"]')

        print('*'*15,len(papers),'-'*30)

        mm=0

        for paper in papers :

            mm =mm + 1

            print(mm)

            url = paper.xpath(".//*[@class='postTitle']/a/@href").extract()[0]

            title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()[0]

            time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()[0]

            content=paper.xpath(".//*[@class='postCon']/div/text()").extract()[0]

            item = CnblogspiderItem(url=url,title=title,time=time,content=content)

            yield item

        next_page=Selector(response).re(u'<a href="(S*)">下一页</a>')

        if next_page:

            yield scrapy.Request(url=next_page[0],callback=self.parse)

选择器Selector ,scrapy自有的数据提取机制构建与lxml库之上,通过特定的xpath,css表达式选择html文件中的某个部分。

创建一个selector对象,a=Selector(response),就可以对其调用方法a.xpath(query),a.css(query),a.extract()(序列化该节点为Unicode字符串并返回list列表),a.re(regex)(regex可以是原始正则表达式或已被re.compile()编译的正则对象,返回Unicode字符串列表) 。 response可直接调用xpath(),css()方法。

在命令行中输入 scrapy 

这时在命令行  进入到项目的根目录cnblogSpider/下  输入 scrapy crawl cnblogs ,就可以看到解析的数据了。

通过yield 返回item ,将parse方法打造成一个生成器。

next_page 使页面翻页,获取下一页的URL列表

定义Item   cnblogSpider/items.py

import scrapy

class CnblogspiderItem(scrapy.Item):

    # define the fields for your item here like:

    # name = scrapy.Field()

    url=scrapy.Field()

    time=scrapy.Field()

    title=scrapy.Field()

    content = scrapy.Field()

这个类需要继承scrapy.Item,CnblogspiderItem的类实例对象,对其里面的键值对,具有和字典一样的使用方式

创建一个CnblogspiderItem对象,a=CnblogspiderItem(title='python爬虫',content='爬虫开发')

print(a.items(),a.keys(),a['title'],a.get('content','ahsdkahdkabdkabnka'))

print(dict(a)) 

输出:

ItemsView({'content': '爬虫开发', 'title': 'python爬虫'}) dict_keys(['content', 'title']) python爬虫 爬虫开发

{'content': '爬虫开发', 'title': 'python爬虫'}

构建Item Pipeline  cnblogSpider/pipeline.py

实现数据的的持久化存储。一般具有下面几种功能:清理HTML数据,验证爬取数据的合法性(检查item是否包含某些字段),查重并去重,将爬取结果保存到文件或数据库中。

import json

from scrapy.exceptions import DropItem

class CnblogspiderPipeline(object):

    def __init__(self):

        self.file=open('papers.json','wb')

    def process_item(self, item, spider):

        if item['title']:

            line=json.dumps(dict(item))+' '

            self.file.write(line.encode())

            return item

        else:

            raise DropItem('Missing title in %s' % item)

此段代码主要是检查了item中是否包含title字段,有就写入json文件,没有就抛出错误。

创建完Item Pipeline后还需在配置文件cnblogSpider/settings.py里将item pipeline的类添加到ITEM_PIPELINES变量中。

ITEM_PIPELINES={'cnblogSpider.pipelines.CnblogspiderPipeline':300,}

ITEM_PIPELINES变量中可配置多个Item Pipeline组件,分配给每个类的整型值确定了它们的运行顺序,item按数字从小到大的

顺序通过 Item Pipeline.通常数字的范围是0~1000.

从程序内启动spider:

在cnblogs_spider.py 中添加如下代码:

if __name__=='__main__':

    process=CrawlerProcess({

        'USER_AGENT':'Mozilla/4.0 (compatible;MSIE 7.0; Windows NT 5.1)'

    })

    process.crawl(CnblogsSpider)

    process.start()

'''

if __name__=='__main__':

    configure_logging({'LOG_FORMAT':'%(levelname)s:%(message)s'})

    runner=CrawlerRunner()

    d=runner.crawl(CnblogsSpider)

    d.addBoth(lambda _:reactor.stop())

    reactor.run()

'''

'''

class MySpider1(scrapy.Spider):

    #your first spider definition

    ...

class MySpider2(scrapy.Spider):

    #Your second spider definition

    ...

#在一个进程中启动多个爬虫

#第一种方法

process=CrawlerProcess()

process.crawl(MySpider1)

process.crawl(MySpider2)

process.start()

#第二种方法

configure_logging()

runner=CrawlerRunner()

runner.crawl(MySpider1)

runner.crawl(MySpider2)

d=runner.join()

d.addBoth(lambda _: reactor.stop())

reactor.run()

#第三种方法

configure_logging()

runner=CrawlerRunner()

@defer.inlineCallbacks

def crawl():

    yield runner.crawl(MySpider1)

    yield runner.crawl(MySpider2)

    reactor.stop()

crawl()

reactor.run()

'''

原文地址:https://www.cnblogs.com/Ting-light/p/9547365.html