利用scrapy和MongoDB来开发一个爬虫

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

安装

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

scrapy

若是你运行的的系统是osx或者linux,能够直接经过pip进行安装,而windows须要另外安装一些依赖,由于电脑的缘由不对此进行讲解。linux

$ pip install Scrapymongodb

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

>>> import scrapy
>>>shell

安装PyMongo和mongodb

由于系统是osx的,因此直接经过下面的语句就能够安装。数据库

brew install mongodbjson

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

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

相关文章
相关标签/搜索