2015-11-04 14 views
7

Tôi đang sử dụng scrapy để xóa các blog và sau đó lưu trữ dữ liệu trong mongodb. Lúc đầu, tôi nhận được ngoại lệ InvalidDocument. Rõ ràng với tôi là dữ liệu không phải là mã hóa đúng. Vì vậy, trước khi kiên trì đối tượng, trong MongoPipeline của tôi, tôi kiểm tra xem tài liệu có nằm trong 'utf-8 strict' hay không, và chỉ sau đó tôi cố gắng tiếp tục tồn tại đối tượng đến mongodb. NHƯNG Tuy nhiên tôi nhận được ngoại lệ InvalidDocument, bây giờ đó là gây phiền nhiễu.MongoDB InvalidDocument: Không thể mã hóa đối tượng

Đây là mã của tôi Object MongoPipeline tôi rằng vẫn còn đối tượng để 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 

Và vẫn còn tôi nhận được ngoại lệ sau đây:

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

Một điều buồn cười từ những nhận xét của @eLRuLL i đã làm như sau:

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

Sau đó, câu hỏi của tôi là. Nếu văn bản này không thể được mã hóa. Vậy tại sao, MongoPipeline của tôi thử bắt không bắt được ngoại lệ này? Vì chỉ có các đối tượng không tăng bất kỳ ngoại lệ nào nên được thêm vào mục ['comments']?

+0

trước tiên bạn đã thử chuyển đổi mục thành dict rồi cập nhật mọi trường? – eLRuLL

+0

@eLRuLL Như bạn đã đề xuất tôi đã thử chuyển đổi mục thành dict, sau đó cập nhật tất cả các trường bằng cách mã hóa giá trị nghiêm ngặt utf8, Nhưng điều đó cũng làm tăng cùng một InvalidDocumentException –

Trả lời

2

Cuối cùng tôi đã tìm ra. Vấn đề không phải với mã hóa. Đó là với cấu trúc của các tài liệu.

Bởi vì tôi đã đi ra trên ví dụ MongoPipeline tiêu chuẩn mà không đối phó với các mặt hàng được xếp kề lồng nhau.

gì tôi đang làm là: BlogItem: "url" ... comments = [CommentItem]

Vì vậy BlogItem tôi có một danh sách các CommentItems. Bây giờ vấn đề đã xuất hiện ở đây, vì kiên trì đối tượng trong cơ sở dữ liệu tôi làm:

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

Vì vậy, ở đây tôi đang phân tích BlogItem thành một bài viết. Nhưng tôi không phân tích cú pháp danh sách CommentItems. Và bởi vì traceback hiển thị loại CommentItem giống như một dict, Nó đã không xảy ra với tôi rằng đối tượng có vấn đề không phải là một dict!

Vì vậy, cuối cùng là cách để khắc phục vấn đề này là có sự thay đổi khi phụ thêm nhận xét vào danh sách bình luận như vậy:

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

Bây giờ MongoDB coi nó như là một tài liệu hợp lệ.

Cuối cùng, đối với phần cuối cùng mà tôi hỏi lý do tại sao tôi nhận được ngoại lệ trên bàn điều khiển python chứ không phải trong tập lệnh.

Lý do là vì tôi đang làm việc trên bảng điều khiển python, chỉ hỗ trợ ascii. Và do đó, lỗi.

1

Thứ nhất, khi bạn làm "somestring".encode(...), không phải là thay đổi "somestring", nhưng nó sẽ trả về một chuỗi được mã hóa mới, vì vậy bạn nên sử dụng một cái gì đó như:

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

và tương tự cho các lĩnh vực khác.

+0

Mục đích là để xác minh xem mã hóa có khả thi hay không. Nếu các biến có thể được mã hóa thành utf8. Và nếu nó ném một ngoại lệ, thì tôi không bao gồm đối tượng này. Plus như mongodb theo mặc định mã hóa các đối tượng của nó trước khi sự bền bỉ, tôi nghĩ rằng nó sẽ là vô ích để lưu trữ các đối tượng được mã hóa. Không bao giờ ít hơn tôi đã làm như bạn đề nghị. Nhưng vẫn gặp lỗi tương tự. Tôi đang cập nhật câu hỏi. –

+0

btw, khi tôi thử: 's = 'Tellement vrai \ xe2 \ x80 \ xa6 Il ...'; s2 = s.encode ('utf-8', 'strict') 'Tôi nhận được' UnicodeDecodeError' – eLRuLL

+0

Vì vậy, điều đó có nghĩa là, chú thích ['content'] không được mã hóa. Hoặc lỗi mã hóa rõ ràng cần được nêu ra, không được nâng lên. –

Các vấn đề liên quan