3

RSSフィードのエントリを読み取り、個々のエントリをJSON形式でCouchDBデータベースに保存するスクリプトがあります。

私のコードの興味深い部分は次のようになります。

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'>--ahhなので、feedparserは独自のdictタイプを使用しています...まあ、明示的にキャストしようとするとどうなり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-何?以下は問題なく機能し、タイプはまだであるため、これは意味がありませんdict

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

ここで何が欠けていますか?

4

3 に答える 3

4

構造をJSONにシリアル化してから、CouchDBに渡すPython dictに戻す方法を見つけました。これにより、JSONに再シリアル化して保存します(ええ、奇妙で好ましくありませんが、機能しますか?)

reprのはtime_structできないので、ダンプに対してカスタムシリアライザーメソッドを実行する必要がありましたeval

ソース: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))
于 2011-03-31T21:18:38.237 に答える
4

メーリングリストで回答しましたが、基本的にこれは、feedbparserエントリにJSONにロスレスでシリアル化できないデータ(time.struct_timeインスタンスなど)が含まれているために発生します。残念ながら、couchdb-pythonはそれがファイルであると想定し続け、実際のエラーをマスクします。

于 2011-04-01T09:11:41.393 に答える
1

たぶん、PythonCouchDBにバグがあります。あなたはそれが受け入れるものにおいて十分にリベラルではないと言うことができます。

ただし、基本的に、CouchDBはJSONを格納します。あなたの言語の「JSON」は何でも使用する必要があります。明らかに、Pythonではdictオブジェクトを意味します。

CouchDBを呼び出す前に、すべての型を単純なPythondictに変換する方法を理解するのに最適な方法が得られるかもしれません。おそらくそれは最も「正しい」解決策ではありませんが、私はそれが最も速いと思います。

私のPythonはさびています。dict(foo)非dictを返す可能性はありますか?たぶん、FeedParserDictサブクラス化dictしてから、メタプログラミングを使用して、dict()が呼び出されたときに自分自身を返しますか?type(dict(item))それが間違いなく単純なPythonの口述であることを確認できますか?

Javascriptランドでの一般的なトリックは、JSONなどのシリアライザーをラウンドトリップすることです。のようなものpickle.loads(pickle.dumps(item))。これにより、コアデータのプレーンコピーが確実に得られます。

于 2011-04-01T04:51:49.357 に答える