Python CouchDB не может сохранить dict, созданный из записи feedparser?(без атрибута «читать») - PullRequest
3 голосов
/ 01 апреля 2011

У меня есть скрипт, который я хочу читать записи в 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'

ОК, тогда я немного отладил ...

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 ... ну, что если я попытаюсь явно привести его к 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'

ч-что? Это не имеет смысла, потому что следующее работает просто отлично, а тип все еще dict:

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

Что мне здесь не хватает?

Ответы [ 3 ]

4 голосов
/ 01 апреля 2011

Отвечено в списке рассылки, но в основном это происходит потому, что запись feedbparser содержит данные, которые не могут быть сериализованы без потерь в JSON, например, экземпляры time.struct_time.К сожалению, couchdb-python продолжает предполагать, что это файл, скрывая фактическую ошибку.

4 голосов
/ 01 апреля 2011

Я нашел способ сериализации структуры в JSON, а затем обратно в Python, который я передаю CouchDB - который затем повторно сериализует его обратно в JSON для сохранения (да, странно и не выгодно, но это работает?)

Мне пришлось сделать собственный метод сериализатора для дампов, потому что repr для time_struct не может быть 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 голос
/ 01 апреля 2011

Возможно есть ошибка в Python CouchDB.Можно сказать, что он недостаточно либерален в том, что принимает.

Но, в основном, CouchDB хранит JSON.Вы должны работать с любым "JSON" на вашем языке.Очевидно, что с Python это означает dict объекты.

Вы можете получить лучший результат, чтобы выяснить, как преобразовать все ваши типы в простой Python-диктант перед вызовом в CouchDB.Возможно, это не самое «правильное» решение, но я подозреваю, что оно самое быстрое.

Мой Python ржавый.Возможно ли, что dict(foo) сможет когда-нибудь вернуть недикт?Может быть, FeedParserDict подклассы dict, а затем использует метапрограммирование для возврата при вызове dict()?Можете ли вы подтвердить, что type(dict(item)) определенно является простым языком Python?

Обычная хитрость в мире Javascript - это обход через сериализатор, такой как JSON.Что-то вроде pickle.loads(pickle.dumps(item)).Это в значительной степени гарантирует, что у вас есть простая копия основных данных.

...