2015-11-04 15 views
7

Sto utilizzando i blog di scrapy su scrap e quindi memorizzo i dati in mongodb. All'inizio ho ricevuto l'eccezione InvalidDocument. Quindi, per me è ovvio che i dati non sono nella giusta codifica. Quindi, prima di persistere nell'oggetto, nella mia MongoPipeline controllerò se il documento è in 'utf-8 strict', e solo allora provo a mantenere l'oggetto su mongodb. MA Ancora ottengo eccezioni InvalidDocument, ora è fastidioso.MongoDB InvalidDocument: Impossibile codificare l'oggetto

Questo è il mio codice mio oggetto MongoPipeline che persiste oggetti da MongoDB

# -*- coding: utf-8 -*- 

# Define your item pipelines here 
# 

import pymongo 
import sys, traceback 
from scrapy.exceptions import DropItem 
from crawler.items import BlogItem, CommentItem 


class MongoPipeline(object): 
    collection_name = 'master' 

    def __init__(self, mongo_uri, mongo_db): 
     self.mongo_uri = mongo_uri 
     self.mongo_db = mongo_db 

    @classmethod 
    def from_crawler(cls, crawler): 
     return cls(
      mongo_uri=crawler.settings.get('MONGO_URI'), 
      mongo_db=crawler.settings.get('MONGO_DATABASE', 'posts') 
     ) 

    def open_spider(self, spider): 
     self.client = pymongo.MongoClient(self.mongo_uri) 
     self.db = self.client[self.mongo_db] 

    def close_spider(self, spider): 
     self.client.close() 

    def process_item(self, item, spider): 

     if type(item) is BlogItem: 
      try: 
       if 'url' in item: 
        item['url'] = item['url'].encode('utf-8', 'strict') 
       if 'domain' in item: 
        item['domain'] = item['domain'].encode('utf-8', 'strict') 
       if 'title' in item: 
        item['title'] = item['title'].encode('utf-8', 'strict') 
       if 'date' in item: 
        item['date'] = item['date'].encode('utf-8', 'strict') 
       if 'content' in item: 
        item['content'] = item['content'].encode('utf-8', 'strict') 
       if 'author' in item: 
        item['author'] = item['author'].encode('utf-8', 'strict') 

      except: # catch *all* exceptions 
       e = sys.exc_info()[0] 
       spider.logger.critical("ERROR ENCODING %s", e) 
       traceback.print_exc(file=sys.stdout) 
       raise DropItem("Error encoding BLOG %s" % item['url']) 

      if 'comments' in item: 
       comments = item['comments'] 
       item['comments'] = [] 

       try: 
        for comment in comments: 
         if 'date' in comment: 
          comment['date'] = comment['date'].encode('utf-8', 'strict') 
         if 'author' in comment: 
          comment['author'] = comment['author'].encode('utf-8', 'strict') 
         if 'content' in comment: 
          comment['content'] = comment['content'].encode('utf-8', 'strict') 

         item['comments'].append(comment) 

       except: # catch *all* exceptions 
        e = sys.exc_info()[0] 
        spider.logger.critical("ERROR ENCODING COMMENT %s", e) 
        traceback.print_exc(file=sys.stdout) 

     self.db[self.collection_name].insert(dict(item)) 

     return item 

E ancora ottengo la seguente eccezione:

au coeur de l\u2019explosion de la bulle Internet n\u2019est probablement pas \xe9tranger au succ\xe8s qui a suivi. Mais franchement, c\u2019est un peu court comme argument !Ce que je sais dire, compte tenu de ce qui pr\xe9c\xe8de, c\u2019est quelles sont les conditions pour r\xe9ussir si l\u2019on est vraiment contraint de rester en France. Ce sont des sujets que je d\xe9velopperai dans un autre article.', 
    'date': u'2012-06-27T23:21:25+00:00', 
    'domain': 'reussir-sa-boite.fr', 
    'title': u'Peut-on encore entreprendre en France ?\t\t\t ', 
    'url': 'http://www.reussir-sa-boite.fr/peut-on-encore-entreprendre-en-france/'} 
    Traceback (most recent call last): 
     File "h:\program files\anaconda\lib\site-packages\twisted\internet\defer.py", line 588, in _runCallbacks 
     current.result = callback(current.result, *args, **kw) 
     File "H:\PDS\BNP\crawler\crawler\pipelines.py", line 76, in process_item 
     self.db[self.collection_name].insert(dict(item)) 
     File "h:\program files\anaconda\lib\site-packages\pymongo\collection.py", line 409, in insert 
     gen(), check_keys, self.uuid_subtype, client) 
    InvalidDocument: Cannot encode object: {'author': 'Arnaud Lemasson', 
    'content': 'Tellement vrai\xe2\x80\xa6 Il faut vraiment \xc3\xaatre motiv\xc3\xa9 aujourd\xe2\x80\x99hui pour monter sa bo\xc3\xaete. On est pr\xc3\xa9lev\xc3\xa9 de partout, je ne pense m\xc3\xaame pas \xc3\xa0 embaucher, cela me co\xc3\xbbterait bien trop cher. Bref, 100% d\xe2\x80\x99accord avec vous. Le probl\xc3\xa8me, je ne vois pas comment cela pourrait changer avec le gouvernement actuel\xe2\x80\xa6 A moins que si, j\xe2\x80\x99ai pu lire il me semble qu\xe2\x80\x99ils avaient en t\xc3\xaate de r\xc3\xa9duire l\xe2\x80\x99IS pour les petites entreprises et de l\xe2\x80\x99augmenter pour les grandes\xe2\x80\xa6 A voir', 
    'date': '2012-06-27T23:21:25+00:00'} 
    2015-11-04 15:29:15 [scrapy] INFO: Closing spider (finished) 
    2015-11-04 15:29:15 [scrapy] INFO: Dumping Scrapy stats: 
    {'downloader/request_bytes': 259, 
    'downloader/request_count': 1, 
    'downloader/request_method_count/GET': 1, 
    'downloader/response_bytes': 252396, 
    'downloader/response_count': 1, 
    'downloader/response_status_count/200': 1, 
    'finish_reason': 'finished', 
    'finish_time': datetime.datetime(2015, 11, 4, 14, 29, 15, 701000), 
    'log_count/DEBUG': 2, 
    'log_count/ERROR': 1, 
    'log_count/INFO': 7, 
    'response_received_count': 1, 
    'scheduler/dequeued': 1, 
    'scheduler/dequeued/memory': 1, 
    'scheduler/enqueued': 1, 
    'scheduler/enqueued/memory': 1, 
    'start) 
    time': datetime.datetime(2015, 11, 4, 14, 29, 13, 191000)} 

Un'altra cosa divertente dal commento di @eLRuLL i ha fatto quanto segue:

>>> s = "Tellement vrai\xe2\x80\xa6 Il faut vraiment \xc3\xaatre motiv\xc3\xa9 aujourd\xe2\x80\x99hui pour monter sa bo\xc3\xaete. On est pr\xc3\xa9lev\xc3\xa9 de partout, je ne pense m\xc3\xaame pas \xc3\xa0 embaucher, cela me" 
>>> s 
'Tellement vrai\xe2\x80\xa6 Il faut vraiment \xc3\xaatre motiv\xc3\xa9 aujourd\xe2\x80\x99hui pour monter sa bo\xc3\xaete. On est pr\xc3\xa9lev\xc3\xa9 de partout, je ne pense m\xc3\xaame pas \xc3\xa0 embaucher, cela me' 
>>> se = s.encode("utf8", "strict") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 14: ordinal not in range(128) 
>>> se = s.encode("utf-8", "strict") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 14: ordinal not in range(128) 
>>> s.decode() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 14: ordinal not in range(128) 

Quindi la mia domanda è. Se questo testo non può essere codificato. Allora perché, la mia MongoPipeline tenta di catturare lo che non cattura questa ECCEZIONE? Perché solo gli oggetti che non generano alcuna eccezione dovrebbero essere aggiunti all'elemento ['commenti']?

+0

hai provato prima a convertire l'elemento in dettatura e quindi ad aggiornare ogni campo? – eLRuLL

+0

@eLRuLL Come hai suggerito, ho provato a convertire l'elemento in dettato, aggiornando quindi tutti i campi mediante valori rigorosi di utf8 codificati, ma anche questo solleva lo stesso InvalidDocumentException –

risposta

2

Finalmente l'ho capito. Il problema non era con la codifica. Era con la struttura dei documenti.

Perché sono andato sull'esempio di MongoPipeline standard che non si occupa di elementi rugginosi annidati.

quello che sto facendo è: BlogItem: "URL" ... commenti = [CommentItem]

Quindi il mio BlogItem ha una lista di CommentItems. Ora il problema è venuto qui, per la persistenza l'oggetto nel database faccio:

self.db[self.collection_name].insert(dict(item)) 

Così eccomi qui l'analisi del BlogItem ad un dict. Ma non sto analizzando la lista di CommentItems. E poiché il traceback mostra il tipo CommentItem come un dict, non mi è venuto in mente che l'oggetto problematico non è un dict!

Così alla fine il modo per risolvere questo problema è quello di cambiare la linea quando si aggiunge il commento alla lista commento in quanto tale:

item['comments'].append(dict(comment)) 

Ora MongoDB considera come un documento valido.

Infine, per l'ultima parte in cui chiedo perché sto ricevendo un'eccezione sulla console python e non nello script.

Il motivo è perché stavo lavorando sulla console python, che supporta solo ASCII. E quindi l'errore.

1

In primo luogo, quando si esegue "somestring".encode(...), è non cambiare "somestring", ma restituisce una nuova stringa codificata, così si dovrebbe usare qualcosa di simile:

item['author'] = item['author'].encode('utf-8', 'strict') 

e lo stesso per gli altri campi.

+0

L'obiettivo era verificare se la codifica è possibile. Se le variabili potrebbero essere codificate in utf8. E se lancia un'eccezione, allora non includo questo oggetto. Inoltre, come mongodb di default codifica i suoi oggetti prima di persistere, ho pensato che sarebbe inutile memorizzare questi oggetti codificati. Mai meno ho fatto come suggerivi tu. Ma ottengono ancora lo stesso errore. Sto aggiornando la domanda. –

+0

btw, quando provo: 's = 'Tellement vrai \ xe2 \ x80 \ xa6 Il ...'; s2 = s.encode ('utf-8', 'strict') 'Sto ricevendo' UnicodeDecodeError' – eLRuLL

+0

Quindi questo significherebbe che il commento ['content'] non è stato codificato. O l'ovvio errore di codifica che avrebbe dovuto essere sollevato, non viene sollevato. –

Problemi correlati