今天咱們利用scrapy框架來抓取Stack Overflow裏面最新的問題(問題標題和網址),而且將這些問題保存到MongoDb當中,直接提供給客戶進行查詢。html
在進行今天的任務以前咱們須要安裝二個框架,分別是Scrapy (1.1.0)和pymongo (3.2.2).python
若是你運行的的系統是osx或者linux,能夠直接經過pip進行安裝,而windows須要另外安裝一些依賴,由於電腦的緣由不對此進行講解。linux
$ pip install Scrapymongodb
一旦安裝完成以後你能夠直接在python shell當中輸入下面的命令,假若沒有出現錯誤的話,說明已安裝完成chrome
>>> import scrapy
>>>shell
由於系統是osx的,因此直接經過下面的語句就能夠安裝。數據庫
brew install mongodbjson
運行mongodb一樣特別的簡單,只須要在終端下面輸入下面的語法:windows
mongod --dbpath=.框架
--dbpath是指定數據庫存放的路徑,運行以後會在該路徑下面生成一些文件

下一步咱們就須要安裝PyMongo,一樣採用pip的方式
$ pip install pymongo
咱們來建立一個新的scrapy的項目,在終端輸入下面的語法
$ scrapy startproject stack

一旦上面的命令完成以後,scrapy會直接建立相應的文件,這些文件包含了基本的信息,便於你來修改相應的內容。

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", ]
scrapy使用XPath來進行匹配相應的數據的來源,html是一種標記的語法,裏面定義了不少的標籤和屬性,好比說咱們定義一個下面的這樣的一個標籤,這裏咱們就能夠經過'//div[@class="content"]'來找到這個標記,找到以後咱們能夠取出其中的屬性或者它的子節點
<div class='content'>
下面咱們經過chrome來說解若是找到xpath的路徑 ,在進行操做以前咱們須要打開開發者工具,能夠點擊菜單欄上面的視圖->開發者->開發者工具來打進入開發者模式,或者能夠根據快捷捷來進行打開。

打開以後咱們在須要的內容上面點擊右擊會彈出一個菜單,這裏咱們能夠選擇檢查來找到當前的內容在html相應的位置

這裏chrome會自動幫助咱們找到相應的位置,經過下面的分析,咱們知道標題的路徑是包含在一個
如今咱們來更新相應的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

這裏咱們須要將全部的元素保存到Mongodb collection當中。
在進行操做以前咱們須要在setinngs.py指定相應的pipeline和添加一些數據庫的參數
ITEM_PIPELINES = { 'stack.pipelines.MongoDBPipeline': 300, } MONGODB_SERVER = "localhost" MONGODB_PORT = 27017 MONGODB_DB = "stackoverflow" MONGODB_COLLECTION = "questions"
在以前的步驟裏面咱們分別已經完成了對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.而且已經存入了相應的數據了。