zoukankan      html  css  js  c++  java
  • 利用scrapy和MongoDB来开发一个爬虫

    今天我们利用scrapy框架来抓取Stack Overflow里面最新的问题(问题标题和网址),并且将这些问题保存到MongoDb当中,直接提供给客户进行查询。

    安装

    在进行今天的任务之前我们需要安装二个框架,分别是Scrapy (1.1.0)和pymongo (3.2.2).

    scrapy

    如果你运行的的系统是osx或者linux,可以直接通过pip进行安装,而windows需要另外安装一些依赖,因为电脑的原因不对此进行讲解。

    $ pip install Scrapy

    一旦安装完成之后你可以直接在python shell当中输入下面的命令,倘若没有出现错误的话,说明已安装完成

    >>> import scrapy
    >>>

    安装PyMongo和mongodb

    因为系统是osx的,所以直接通过下面的语句就可以安装。

    brew install mongodb

    运行mongodb同样特别的简单,只需要在终端下面输入下面的语法:

    mongod --dbpath=.

    --dbpath是指定数据库存放的路径,运行之后会在该路径下面生成一些文件
    屏幕快照 2016-05-22 下午9.45.50

    下一步我们就需要安装PyMongo,同样采用pip的方式

    $ pip install pymongo

    Scrapy 项目

    我们来创建一个新的scrapy的项目,在终端输入下面的语法

    $ scrapy startproject stack

    屏幕快照 2016-05-22 下午9.48.22
    一旦上面的命令完成之后,scrapy会直接创建相应的文件,这些文件包含了基本的信息,便于你来修改相应的内容。
    屏幕快照 2016-05-22 下午9.48.50

    定义数据

    items.py文件用于我们定义需要抓取对象的存储的“容器“
    有关StackItem()预定义时并让其继承于scrapy.Item

    # -*- coding: utf-8 -*-
    
    # Define here the models for your scraped items
    #
    # See documentation in:
    # http://doc.scrapy.org/en/latest/topics/items.html
    
    import scrapy
    
    class StackItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        pass
    
    
    

    这里我们需要在里面添加两个字段,分别用来存放抓取到的标题以及链接

    
    from scrapy.item import Item,Field
    
    class StackItem(Item):
        # define the fields for your item here like:
        title=Field()
        url=Field()
    

    创建爬虫

    我们需要在spider文件夹下面创建一个stack_spider.py的文件,这个里面包容我们爬虫进行抓取时的行为。就是告诉爬虫我们需要抓取哪些内容以及内容的来源。

    from scrapy import Spider
    from scrapy.selector import Selector
    from stack.items import StackItem
    
    class StackSpider(Spider):
        name="stack"
        allowed_domains=['stackoverflow.com']
        start_urls = [
            "http://stackoverflow.com/questions?pagesize=50&sort=newest",
        ]
    
    
    • name 是定义爬虫的名称
    • allowed_domains 指定爬虫进行爬取的域地址
    • start_urls 定义爬虫需要抓取的网页的url地址

    XPath 选择

    scrapy使用XPath来进行匹配相应的数据的来源,html是一种标记的语法,里面定义了很多的标签和属性,比如说我们定义一个下面的这样的一个标签,这里我们就可以通过'//div[@class="content"]'来找到这个标记,找到之后我们可以取出其中的属性或者它的子节点

    <div class='content'>

    下面我们通过chrome来讲解如果找到xpath的路径 ,在进行操作之前我们需要打开开发者工具,可以点击菜单栏上面的视图->开发者->开发者工具来打进入开发者模式,或者可以根据快捷捷来进行打开。
    屏幕快照 2016-05-22 下午10.08.15

    打开之后我们在需要的内容上面点击右击会弹出一个菜单,这里我们可以选择检查来找到当前的内容在html相应的位置
    屏幕快照 2016-05-22 下午10.05.54
    这里chrome会自动帮助我们找到相应的位置,通过下面的分析,我们知道标题的路径是包含在一个

    下面的h3标记当中。
    屏幕快照 2016-05-22 下午10.06.02

    现在我们来更新相应的stack_spider.py脚本

    from scrapy import Spider
    from scrapy.selector import Selector
    from stack.items import StackItem
    
    class StackSpider(Spider):
        name="stack"
        allowed_domains=['stackoverflow.com']
        start_urls = [
            "http://stackoverflow.com/questions?pagesize=50&sort=newest",
        ]
        def parse(self,response):
            questions=Selector(response).xpath('//div[@class="summary"]/h3')
            
    
    

    提取数据

    创建抓取的规约之后,我们需要与刚才创建的items实体进行关联,我们继续修改stack_spider.py文件

    from scrapy import Spider
    from scrapy.selector import Selector
    from stack.items import StackItem
    
    class StackSpider(Spider):
        name="stack"
        allowed_domains=['stackoverflow.com']
        start_urls = [
            "http://stackoverflow.com/questions?pagesize=50&sort=newest",
        ]
        def parse(self,response):
            questions=Selector(response).xpath('//div[@class="summary"]/h3')
            for question in questions:
                item=StackItem()
                item['title'] = question.xpath(
                    'a[@class="question-hyperlink"]/text()').extract()[0]
                item['url'] = question.xpath(
                    'a[@class="question-hyperlink"]/@href').extract()[0]
                yield item
    

    通过遍历所有的符合//div[@class="summary"]/h3的元素,并且从中找到我们真正需要爬取的元素内容

    测试

    现在我们进行测试,只要在项目的目录下面运行以下的脚本就可以进行测试 。

    scrapy crawl stack

    现在我们需要将爬取到的所有的信息保存到一个文件当中,可以在后面添加二个参数-o和-t

    scrapy crawl stack -o items.json -t json

    下面是实际保存的文件的内容分别包含了title和url
    屏幕快照 2016-05-22 下午10.24.21

    将元素存放入MongoDB

    这里我们需要将所有的元素保存到Mongodb collection当中。
    在进行操作之前我们需要在setinngs.py指定相应的pipeline和添加一些数据库的参数

    ITEM_PIPELINES = {
       'stack.pipelines.MongoDBPipeline': 300,
    }
    MONGODB_SERVER = "localhost"
    MONGODB_PORT = 27017
    MONGODB_DB = "stackoverflow"
    MONGODB_COLLECTION = "questions"
    

    pipeline 管理

    在之前的步骤里面我们分别已经完成了对html的解析,以及指定数据的存储。但是这时所有的信息都在内存当中,我们需要将这些爬取到数据存储到数据库当中,这里就轮到pipelines.py上场了,这玩意就负责对数据的存储的。
    在上面我们已经定义了数据库的参数,现在我们终于派上用场了。

    import pymongo
    from scrapy.conf import settings
    from scrapy.exceptions import DropItem
    from scrapy import log
    
    class MongoDBPipeline(object):
        def __init__(self):
            connection=pymongo.MongoClient(
                settings['MONGODB_SERVER'],
                settings['MONGODB_PORT']
            )
            db=connection[settings['MONGODB_DB']]
            self.collection=db[settings['MONGODB_COLLECTION']]
    
    

    上面的代码是我们创建了一个MongoDBPipeline()的类,以及定义初始化函数,用来读取刚才的参数来创建一个Mongo的连接。

    数据处理

    下一步我们需要定义一个函数来处理解析的数据

    # -*- 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 pymongo
    from scrapy.conf import settings
    from scrapy.exceptions import DropItem
    from scrapy import log
    
    class MongoDBPipeline(object):
        def __init__(self):
            connection=pymongo.MongoClient(
                settings['MONGODB_SERVER'],
                settings['MONGODB_PORT']
            )
            db=connection[settings['MONGODB_DB']]
            self.collection=db[settings['MONGODB_COLLECTION']]
        def process_item(self,item,spider):
            valid=True
            for data in item:
                if not data:
                    valid=False
                    raise DropItem('Missing{0}!'.format(data))
            if valid:
                self.collection.insert(dict(item))
                log.msg('question added to mongodb database!',
                        level=log.DEBUG,spider=spider)
            return item
    
    

    上面已经完成了对数据的连接,以及相应数据的存储

    测试

    我们同样在stack目录当中运行下面的命令

    $ scrapy crawl stack

    当内容执行完成之后没有出现任何的错误的提示,恭喜你已经将数据正确的存入到mongodb当中。
    这里我们通过Robomongo来访问数据库的时候发现创建了一个stackoverflow的数据库,下面已经成功创建了一个名为questions的Collections.并且已经存入了相应的数据了。
    屏幕快照 2016-05-22 下午10.37.33

  • 相关阅读:
    NHibernate从入门到精通系列(3)——第一个NHibernate应用程序
    你真的了解Ioc与AOP吗?(1)
    C#网络编程TCP通信的粘包问题讨论
    开源框架完美组合之Spring.NET + NHibernate + ASP.NET MVC + jQuery + easyUI 中英文双语言小型企业网站Demo
    NHibernate从入门到精通系列(1)——NHibernate概括
    Spring.NET框架简介及模块说明
    C#|.NET从控制反转(依赖注入)想到事件注入 (非AOP)
    MVC3使用Unity实现接口自动注册
    编写更好的C#代码
    解构控制反转(IoC)和依赖注入(DI)
  • 原文地址:https://www.cnblogs.com/tianyake/p/5518200.html
Copyright © 2011-2022 走看看