放假這段時間好好的思考了一下關於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
總結:本次主要多三個方向來解決連續爬取文章內容,並將獲得內容保存的問題,不過文中主要介紹的,還是以定向為基礎的爬取,和以規則來構建的爬蟲還是有區別,下篇文章將介紹。