(3)分布式下的爬蟲Scrapy應該如何做-遞歸爬取方式,數據輸出方式以及數據庫鏈接


  放假這段時間好好的思考了一下關於Scrapy的一些常用操作,主要解決了三個問題:

  1.如何連續爬取

  2.數據輸出方式

  3.數據庫鏈接

 

一,如何連續爬取:

 

   思考:要達到連續爬取,邏輯上無非從以下的方向着手

   1)預加載需要爬取的列表,直接到這個列表都處理完,相應的爬取工作都已經完成了。

   2)從第一頁開始爬取,遇到有下一頁標簽的,那繼續爬取,如果沒有下一頁類似的標簽,那表示已經爬到最后一頁

   3)分析當前頁面的所有鏈接,對於鏈接符合某種特定規則的,繼續爬取,如果沒有那表示爬取工作完成(此時需要建立已經爬取列表,防止重復操作)

 

   一般會於定向的爬蟲,比如爬取某寶或者某東的數據時,可以采用方式一,二,寫好規則就可以了,也方便維護。

   1.1對於預加載的列表,那根據需要生成列表就可以了。

   在start_urls 里面生成相應的列表就可以,這里引入一個概念,列表推導式。

   我們將代碼變換成如下:

   

from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from cnblogs.items import CnblogsItem

class CnblogsSpider(BaseSpider):
    name = "cnblogs"
    allowed_domains = ["cnblogs.com"]
    start_urls = [
        'http://www.cnblogs.com/#p%s' % p for p in xrange(1, 11)
        ]

    def parse(self, response):
        self.log("Fetch douban homepage page: %s" % response.url)
        hxs = HtmlXPathSelector(response)

        # authors = hxs.select('//a[@class="titlelnk"]')

        items = hxs.select('//a[contains(@class, "titlelnk")]')

        listitems = []

        for author in items:
            # print author.select('text()').extract()
            item = CnblogsItem()
            # property
            item['Title'] = ''.join(author.select('text()').extract())
            item['TitleUrl'] = author.select('@href').extract()
            listitems.append(item)

        return listitems


在這里,start_urls里面使用列表推導式,爬出了一共10頁的數據。

1.2對於爬取下一頁實現全趴取的過程,就需要使用yield關鍵字


我們就蟲師的博客來進行測試實驗:

http://www.cnblogs.com/fnng/default.aspx?page=1

 

這里介紹一個scrapy 一個非常有用的技巧,scrapy shell ,因為使用 xpath 可以幫助我們調試xpath語法(或者使用firebug又或者是chrome都可以)

語法:scrapy shell http://你要調試xpath的網址

 

這里我就不繼續講xpath的語法了,自己去搜一下,相比正則要相對簡單好理解。

 

相應的Spider可以這樣編寫:

 

# -*- coding: utf-8 -*-
from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from cnblogs.items import CnblogsItem
from scrapy.http import Request
from scrapy import log
# please pay attention to the encoding of info,otherwise raise error of decode 
import sys
reload(sys)
sys.setdefaultencoding('utf8')

class BlogsSpider(BaseSpider):
    name = "cnblogs_blogs"
    allowed_domains = ["cnblogs.com"]
    start_urls = [
        'http://www.cnblogs.com/fnng/default.aspx?page=1'
        ]

    def parse(self, response):
        hxs = HtmlXPathSelector(response)
        # authors = hxs.select('//a[@class="titlelnk"]')
        # sel.xpath('//a[@class="PostTitle"]').xpath('text()')
        items = hxs.select('//a[@class="PostTitle"]')
        a_page = hxs.select('//div[@id="pager"]/a')
        for a_item in items:
            item = CnblogsItem()
            # property
            item['Title'] = ''.join(a_item.xpath('text()').extract())
            item['TitleUrl'] = a_item.xpath('@href').extract()
            yield item

        # get the page index
        log.msg(len(a_page))
        if len(a_page) > 0:
            for a_item in a_page:
                page_text = ''.join(a_item.xpath('text()').extract())
                if page_text == '下一頁'.encode('utf-8') or 'Next' in page_text:
                    next_url = ''.join(a_item.xpath('@href').extract())
                    log.msg(next_url)
                    yield Request(next_url, callback=self.parse)
                    break

 

我們來運行看看效果如何:

 

所有的數據完整,效果還是不錯的。

關於第三種,以規則來規划爬蟲的機制,在以后會介紹 :)

 

二,數據輸出的方式:

 

   上面的scrapy命令是:scrapy crawl cnblogs_blogs --nolog -o cnblogs_blogs.json -t json

   那結果輸出的就是json格式的文件,-t 指的是輸出文件格式,json ,-t 支持下列參數:    

   xml
   csv
   json
   jsonlines
   jl
   pickle
   marshal

   一般選擇xml ,csv,json三種格式就夠了,這樣可以很方便的導入各種數據庫。

   更多的參考:http://doc.scrapy.org/en/latest/topics/feed-exports.html 

三,數據庫連接:

 

   數據保存為文件的形式然后導入是一個不錯的選擇,不過一般都會有一定的IO開銷,一般可以將Item直接保存到數據庫中,這個時候就要引入pipelines這個部件了。

   在我們項目的根目錄下有一個名為:pipelines.py文件,我們在設置里面首先啟用這個文件,在啟用之后,spider得到的item都會傳入到這個部件中進行二次處理,

   3.1在settings.py中啟用pipelines

   

ITEM_PIPELINES = {
    'cnblogs.pipelines.CnblogsPipelineobj': 300,
}

   注意命名方式:botname.moudlename.classname 要不然會找不到指定的模塊。

   3.2 編寫pipelines

# -*- coding: utf-8 -*-


import MySQLdb
import MySQLdb.cursors
import logging
from twisted.enterprise import adbapi

class CnblogsPipelineobj(object):
    def __init__(self):
        self.dbpool = adbapi.ConnectionPool(
                dbapiName ='MySQLdb',
                host ='127.0.0.1',
                db = 'cnblogs',
                user = 'root',
                passwd = '密碼',
                cursorclass = MySQLdb.cursors.DictCursor,
                charset = 'utf8',
                use_unicode = False
        )

    # pipeline dafault function
    def process_item(self, item, spider):
        query = self.dbpool.runInteraction(self._conditional_insert, item)
        logging.debug(query)
        return item


    # insert the data to databases
    def _conditional_insert(self, tx, item):
        parms = (item['Title'], item['TitleUrl'])
        sql = "insert into blogs values('%s','%s') " % parms
        #logging.debug(sql)
        tx.execute(sql)

  

OK.運行一下看一下效果如何

 

 

 

中文數據得以保存,OK

 

總結:本次主要多三個方向來解決連續爬取文章內容,並將獲得內容保存的問題,不過文中主要介紹的,還是以定向為基礎的爬取,和以規則來構建的爬蟲還是有區別,下篇文章將介紹。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM