2015-11-04 6 views
7

nicht verschlüsseln Ich benutze Scrapy, um Blogs zu verschrotten und dann die Daten in mongodb zu speichern. Zuerst bekam ich die InvalidDocument Exception. So offensichtlich für mich ist, dass die Daten nicht in der richtigen Codierung sind. Bevor ich also das Objekt persistiere, überprüfe ich in meiner MongoPipeline, ob das Dokument in 'utf-8 strict' ist, und nur dann versuche ich, das Objekt an mongodb festzuhalten. ABER noch bekomme ich InvalidDocument Exceptions, jetzt ist das nervig.MongoDB InvalidDocument: Kann Objekt

Dies ist mein Code mein MongoPipeline Objekt, das Objekte i

# -*- 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 

Und noch erhalten die folgende Ausnahme für MongoDB weiterhin besteht:

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)} 

Eine andere lustige Sache aus dem Kommentar von @eLRuLL i tat folgendes:

>>> 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) 

Dann ist meine Frage. Wenn dieser Text nicht codiert werden kann. Dann, warum, ist mein MongoPipeline Versuch, gefangen zu fangen dieser AUSNAHME? Weil nur Objekte, die keine Ausnahme auslösen, an Element ['Kommentare'] angehängt werden sollen?

+0

Haben Sie zuerst versucht, das Element in dict umzuwandeln und dann jedes Feld zu aktualisieren? – eLRuLL

+0

@eLRuLL Wie Sie vorgeschlagen, habe ich versucht, das Element in dict zu konvertieren, dann alle Felder durch utf8 strikte Werte zu aktualisieren, aber das löst auch die gleiche InvalidDocumentException –

Antwort

2

Endlich habe ich es herausgefunden. Das Problem war nicht mit der Codierung. Es war mit der Struktur der Dokumente.

Weil ich auf das Standard-MongoPipeline-Beispiel gegangen bin, das sich nicht mit verschachtelten Scrapy-Elementen beschäftigt.

Was ich tue, ist: BlogItem: "url" ... Kommentare = [CommentItem]

Also meine BlogItem hat eine Liste von CommentItems. Nun kam das Problem hier, für persistierende das Objekt in der Datenbank i tun:

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

Also hier ich die BlogItem zu einem dict bin Parsen. Aber ich analysiere nicht die Liste von CommentItems. Und weil das Traceback die Art CommentItem wie ein Diktat anzeigt, fiel mir nicht auf, dass das problematische Objekt kein Diktat ist!

So endlich die die Art und Weise, dieses Problem zu beheben, ist die Linie zu ändern, wenn Sie den Kommentar zu der Kommentarliste als solche anhängt:

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

Jetzt MongoDB als gültiges Dokument hält.

Zuletzt für den letzten Teil, wo ich frage, warum ich eine Ausnahme auf der Python-Konsole und nicht im Skript bekomme.

Der Grund ist, weil ich an der Python-Konsole arbeitete, die nur ASCII unterstützt. Und damit der Fehler.

1

Erstens, wenn Sie "somestring".encode(...) tun, ist nicht "somestring" zu ändern, aber es gibt einen neuen codierten String, so dass Sie so etwas wie verwenden sollen:

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

und das gleiche für die anderen Felder.

+0

Das Ziel war es, zu überprüfen, ob Codierung möglich ist. Wenn die Variablen in utf8 codiert werden könnten. Und wenn es eine Ausnahme auslöst, dann schließe ich dieses Objekt nicht ein. Plus wie mongodb standardmäßig seine Objekte vor der Persistenz codiert, dachte ich, es wäre nutzlos, diese codierten Objekte zu speichern. Trotzdem habe ich getan, wie Sie vorgeschlagen haben. Aber immer noch den gleichen Fehler. Ich aktualisiere die Frage. –

+0

BTW, wenn ich versuche: 's = 'Tellement vrai \ xe2 \ x80 \ xa6 Il ...'; s2 = s.encode ('utf-8', 'strict') 'Ich bekomme' UnicodeDecodeError' – eLRuLL

+0

Das würde also bedeuten, dass der Kommentar ['content'] nicht codiert wurde. Oder der offensichtliche Kodierungsfehler, der hätte erhoben werden sollen, wird nicht erhoben. –