zoukankan      html  css  js  c++  java
  • 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()

    '''

  • 相关阅读:
    loaded the "*****" nib but the view outlet was not set 错误的解决办法。
    IBOutlet和IBAction
    initWithNibName 和 loadNibNamed 的区别
    iOS 应用是如何创建的
    Objective C中NULL、Nil、nil、NSNull 的区别
    Objective C数组的内存管理
    XCode 调试1
    META httpequiv 大全
    基于GoogleMap,Mapabc,51ditu,VirtualEarth,YahooMap Api接口的Jquery插件的通用实现(含源代码下载) 转
    SELECT 語法中,如何動態組合查詢條件(转)
  • 原文地址:https://www.cnblogs.com/Ting-light/p/9547365.html
Copyright © 2011-2022 走看看