一些使用Scrapy的經驗

2021-07-04 14:25:00 字數 4537 閱讀 7801

首先,新建乙個專案叫dmoz:

這裡參考scrapy tutorial裡面的例子做說明,抓取open directory project(dmoz)上的資料。

scrapy startproject dmoz
將會建立乙個叫dmoz的目錄,結構如下:

dmoz/

scrapy.cfg

dmoz/

__init__.py

items.py

pipelines.py

settings.py

spiders/

__init__.py

...

然後,在items.py裡面定義我們要抓取的資料:

from scrapy.item import item, field

class dmozitem(item):

title = field()

link = field()

desc = field()

這裡我們需要獲取dmoz頁面上的標題,鏈結,描述,所以定義乙個對應的items結構,不像django裡面models的定義有那麼多種類的field,這裡只有一種就叫field(),再複雜就是field可以接受乙個default值。

接下來,開始寫spider:

spider只是乙個繼承字scrapy.spider.basespider的python類,有三個必需的定義的成員

所以在spiders目錄下新建乙個spider,dmoz_spider.py:

class dmozspider(basespider):

name = "dmoz.org"

start_urls = [

"",""

]def parse(self, response):

filename = response.url.split("/")[-2]

open(filename, 'wb').write(response.body)

下一步,提取資料到items裡面,這裡主要用到xpath提取網頁資料:

scrapy有提供兩個xpath選擇器,htmlxpathselector和xmlxpathselector,乙個用於html,乙個用於xml,xpath選擇器有三個方法

一種很好的方法是在shell裡面對xpath進行測試:

scrapy shell
現在修改parse()方法看看如何提取資料到items裡面去:

def parse(self, response):

hxs = htmlxpathselector(response)

sites = hxs.select('//ul/li')

items =

for site in sites:

item = dmozitem()

item['title'] = site.select('a/text()').extract()

item['link'] = site.select('a/@href').extract()

item['desc'] = site.select('text()').extract()

return items

最後,儲存抓取的資料:

scrapy提供了幾個選項,可以將資料儲存為json,csv或者xml檔案,下面開始放出定義的dmoz_spider(注意他的name是dmoz.org),並將抓取的資料儲存為json,在dmoz目錄下執行命令

scrapy crawl dmoz.org --set feed_uri=items.json --set feed_format=json
如果需要對items資料進一步處理,比如直接儲存到資料庫,就要用到pipelines

不斷的抓取下乙個鏈結如何實現,items如何儲存?

這裡需要解釋一下parse()方法,parse可以返回request列表,或者items列表,如果返回的是request,則這個request會放到下一次需要抓取的佇列,如果返回items,則對應的items才能傳到pipelines處理(或者直接儲存,如果使用預設feed exporter)。那麼如果由parse()方法返回下乙個鏈結,那麼items怎麼返回儲存? request物件接受乙個引數callback指定這個request返回的網頁內容的解析函式(實際上start_urls對應的callback預設是parse方法),所以可以指定parse返回request,然後指定另乙個parse_item方法返回items:

def parse(self, response):

# dosomething

return [request(url, callback=self.parse_item)]

def parse_item(self, response):

# item['key'] = value

return [item]

關於解析函式的返回值,除了返回列表,其實還可以使用生成器,是等價的:

def parse(self, response):

# dosomething

yield request(url, callback=self.parse_item)

def parse_item(self, response):

yield item

如何在解析函式之間傳遞值?

一種常見的情況:在parse中給item某些字段提取了值,但是另外一些值需要在parse_item中提取,這時候需要將parse中的item傳到parse_item方法中處理,顯然無法直接給parse_item設定而外引數。 request物件接受乙個meta引數,乙個字典物件,同時response物件有乙個meta屬性可以取到相應request傳過來的meta。所以解決上述問題可以這樣做:

def parse(self, response):

# item = itemclass()

yield request(url, meta=, callback=self.parse_item)

def parse(self, response):

item = response.meta['item']

item['field'] = value

yield item

pipelines.py如何使用?

具體參考:只需要在settings.py中啟用定義的pipelines元件即可,可能困惑的地方在於如果指定了預設的feed exporter,piplelines會對item處理的流程會有什麼影響,答案是pipelines會取代預設的feed exporter,專案中所有spider返回的item(比如parse_item)最後都會傳入pipelines中定義的proccess_item()方法進一步處理。

如何處理extract()返回為空列表的情況?

因為extract()方法返回的是字串列表,如果選擇器沒有獲取到某個節點的內容,則是乙個空列表,所以經常會遇到這種處理:

item['field'] = ex_data[0].strip() if len(ex_data) > 0 else ''
一種更好的處理方式:

item['field'] = ''.join(ex_data).strip()
如何給xpath選取內容設定預設值?

xpath選取節點內的文字時,如果節點內容為空,xpath不會返回乙個空字串,而是什麼都不返回,對應到列表就是對應的列表項少一項,有時候需要這樣的空字串當預設值。xpath中有乙個concat函式可以實現這種效果:

text = hxs.select(『concat(//span/text(), 「」)』).extract()
對於空span會返回乙個空字串

scrapy.log是很好用的除錯工具

需要先在settings.py中指定log_level,預設為『debug』,所以抓取的時候每個item獲取的內容都會輸出到螢幕,如果抓取的內容太多,有時候會把一些異常資訊淹沒。所以有時候需要設定高一點的級別,比如『warning』,這樣在spider中可以在需要的地方使用log.msg('info', log.warning)輸出一些有用的資訊。

另一種方便的除錯方法,在spider中呼叫互動shell環境

在需要中斷除錯的地方插入:

from scrapy.shell import inspect_response

inspect_response(response)

這時候會打斷抓取,進入乙個shell,response為當前抓取的url內容。

zTree使用的一些經驗

筆者目前所知ztree已經發展到3.5的版本了,偶然的機會接觸了這個框架,感覺非常好用,於是欣然收藏之。現在筆者有一些自己的看法,願意與大家分享,也希望大家能多提寶貴意見,共同進步。1.ztree主要的js和css 在v3.x中有3個比較重要的js 乙個 核心包 jquery.ztree.core ...

AND一些經驗

目錄 一 參考 1 程式設計師2020工作規範范文 總結 good 適合多看,程式設計師每天 每月做的事情總結了 一 目的 1 在公司來了很久了,有時候一些經驗想把記錄下來,專案 做人 等等 一 專案 1 板卡 pci2012a分為支援和不支援音效卡的 一 做人 1 不要過度依賴別人 1 有問題立馬...

TestDirector使用的一些經驗(二)

6 自定義列表內容 customize customize project lists中可以設定列表內容。一些預設的列表欄位是不可修改的,比如statue列表。列表的專案儲存在資料庫中的all lists表,我曾經嘗試著修改資料庫,但使用過程中,預設的取值還是原來的而不是修改的。7 新增新字段 cu...