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

  • 相关阅读:
    Java 简单算法--打印乘法口诀(只使用一次循环)
    Java简单算法--求100以内素数
    ubuntu 16.04 chrome flash player 过期
    java 网络API访问 web 站点
    java scoket (UDP通信模型)简易聊天室
    leetcode1105 Filling Bookcase Shelves
    leetcode1140 Stone Game II
    leetcode1186 Maximum Subarray Sum with One Deletion
    leetcode31 Next Permutation
    leetcode834 Sum of Distances in Tree
  • 原文地址:https://www.cnblogs.com/tianyake/p/5518200.html
Copyright © 2011-2022 走看看