2011-03-31 98 views
3

我有一個腳本,我想讀取RSS源中的條目,並將單個條目以JSON格式存儲到CouchDB數據庫中。Python CouchDB無法保存從feedparser條目創建的字典? (沒有屬性'讀')

我的代碼的有趣部分看起來是這樣的:

Feed = namedtuple('Feed', ['name', 'url']) 

couch = couchdb.Server(COUCH_HOST) 
couch.resource.credentials = (COUCH_USER, COUCH_PASS) 

db = couch['raw_entries'] 

for feed in map(Feed._make, csv.reader(open("feeds.csv", "rb"))): 
    d = feedparser.parse(feed.url) 
    for item in d.entries: 
     db.save(item) 

當我嘗試運行代碼,我從db.save(item)以下錯誤:

AttributeError: object has no attribute 'read' 

OK,所以我然後做了一些調試......

for feed in map(Feed._make, csv.reader(open("feeds.csv", "rb"))): 
    d = feedparser.parse(feed.url) 
    for item in d.entries: 
     print(type(item)) 

結果<class 'feedparser.FeedParserDict'> - 啊,所以feedparser正在使用自己的字典類型...好吧,如果我嘗試明確地將其轉換爲dict

for feed in map(Feed._make, csv.reader(open("feeds.csv", "rb"))): 
    d = feedparser.parse(feed.url) 
    for item in d.entries: 
     db.save(dict(item)) 

Traceback (most recent call last): 
    File "./feedchomper.py", line 32, in <module> 
    db.save(dict(item)) 
    File "/home/dealpref/lib/python2.7/couchdb/client.py", line 407, in save 
_, _, data = func(body=doc, **options) 
    File "/home/dealpref/lib/python2.7/couchdb/http.py", line 399, in post_json 
status, headers, data = self.post(*a, **k) 
    File "/home/dealpref/lib/python2.7/couchdb/http.py", line 381, in post 
**params) 
    File "/home/dealpref/lib/python2.7/couchdb/http.py", line 419, in _request 
credentials=self.credentials) 
    File "/home/dealpref/lib/python2.7/couchdb/http.py", line 239, in request 
    resp = _try_request_with_retries(iter(self.retry_delays)) 
    File "/home/dealpref/lib/python2.7/couchdb/http.py", line 196, in _try_request_with_retries 
    return _try_request() 
    File "/home/dealpref/lib/python2.7/couchdb/http.py", line 222, in _try_request 
    chunk = body.read(CHUNK_SIZE) 
AttributeError: 'dict' object has no attribute 'read' 

w-what?這是沒有意義的,因爲下面的作品就好了類型仍然是dict

some_dict = dict({'foo': 'bar'}) 
print(type(some_dict)) 
db.save(some_dict) 

缺少什麼我在這裏?

+1

你可以發佈這些錯誤的堆棧跟蹤? CouchDB模塊中的錯誤可能更深。確實,'dict'對象沒有'read()'方法,但可能是一個紅色的鯡魚。 – kindall 2011-03-31 20:16:21

+0

@kindall - 我發佈了整個堆棧跟蹤...它看起來像CouchDB試圖做一個分塊上載出於某種原因(也許是因爲字典很大)?但是,我無法通過從手構建字典來複制這種行爲(也就是說,如果我用手寫出它,它會節省很多)。 – ashgromnies 2011-03-31 20:21:54

+1

是的,它似乎認爲你的字典出於某種原因是一個文件。很奇怪。 – kindall 2011-03-31 20:57:21

回答

4

我找到了一種方法,將結構序列化爲JSON,然後返回到一個Python字典,我將其傳遞給CouchDB - 然後將其重新串行化爲JSON以保存(是的,奇怪並且不太有利,但它有效? )

我必須爲轉儲執行自定義串行器方法,因爲time_structrepr不能是eval'd。

來源:http://diveintopython3.org/serializing.html

代碼:

#!/usr/bin/env python2.7 

from collections import namedtuple 
import csv 
import json 
import time 

import feedparser 
import couchdb 

def to_json(python_object): 
    if isinstance(python_object, time.struct_time): 
     return {'__class__': 'time.asctime', 
       '__value__': time.asctime(python_object)} 

    raise TypeError(repr(python_object) + ' is not JSON serializable') 

Feed = namedtuple('Feed', ['name', 'url']) 

COUCH_HOST = 'http://mycouch.com' 
COUCH_USER = 'user' 
COUCH_PASS = 'pass' 

couch = couchdb.Server(COUCH_HOST) 
couch.resource.credentials = (COUCH_USER, COUCH_PASS) 

db = couch['raw_entries'] 

for feed in map(Feed._make, csv.reader(open("feeds.csv", "rb"))): 
    d = feedparser.parse(feed.url) 
    for item in d.entries: 
     j = json.dumps(item, default=to_json) 
     db.save(json.loads(j)) 
1

也許有Python中的CouchDB的錯誤。你可以說它接受的內容不夠開放。

但是,基本上,CouchDB存儲JSON。您應該使用您的語言中的任何「JSON」。很顯然,用Python代表dict對象。

在調用CouchDB之前,您可能會弄清楚如何將所有類型轉換爲純Python Python字典。也許這不是最「正確」的解決方案,但我懷疑它是最快的。

我的Python很生鏽。 dict(foo)可能會返回非字典嗎?也許FeedParserDict的子類dict然後使用元編程返回自己當dict()被調用?你能確認type(dict(item))絕對是一個普通的Python字典嗎?

JavaScript土地的一個常見伎倆是通過JSON等序列化程序進行往返。像pickle.loads(pickle.dumps(item))。這幾乎可以確保您擁有核心數據的普通副本。

+0

讓我知道'type(dict(item))'結果。如果我的假設是錯誤的,也許別的東西就會響起。順便問一下很好的問題! – JasonSmith 2011-04-01 04:52:53

+0

'type(dict(item))'''當然是返回'dict' :) – ashgromnies 2011-04-05 14:47:49

4

回覆郵件列表,但基本上這是因爲feedbparser條目包含無法無損序列化爲JSON的數據,例如, time.struct_time實例。不幸的是,couchdb-python繼續假設它是一個文件,掩蓋了實際的錯誤。