python и scrapy проблема с кодировкой

#python #unicode #encoding #utf-8 #scrapy

#python #unicode #кодирование #utf-8 #scrapy

Вопрос:

Я просто не могу понять! : (Я удаляю данные с сайта в кодировке utf-8, ну, по крайней мере, так там написано:

 Content-Type: text/html;charset=utf-8
  

Я получаю список обычных строк Unicode с помощью вызова XPath selector extract ():

 item['city']= element.select('//div[@id="bubble_2"]/div/text()').extract()
  

Это список:

 [u'Westbahnhofstr.xa010', u'72070xa0Txfcbingen']
  

Теперь я объединяю список в одну строку Unicode:

 item['city']= "".join(element.select('//div[@id="bubble_2"]/div/text()').extract())
  

Пока все хорошо:

 u'Beim Nonnenhausxa0672070xa0Txfcbingen'
  

Проблема возникает, когда я пытаюсь вывести эту строку Unicode либо на экран (печать), либо в файл (запись). что бы я ни пробовал, это возвращает ошибку (http://pastebin.com/51DkX2R2 ):

 exceptions.UnicodeEncodeError: 'ascii' codec can't encode character u'xa0' in   position 11: ordinal not in range(128)
  

Я, конечно, закодировал Unicode в байтовую строку перед выводом:

 item['city'].encode('utf-8')
  

Это мой конвейер.что и как я использую для открытия и записи в свои резюме:

 import csv
import items
import urlparse
import codecs

class DepostPipeline(object):
    def __init__(self):
        self.modelsCsv = csv.writer(codecs.open('Dees.csv', mode='w',encoding='utf-8'))
        self.modelsCsv.writerow(['city'])

def process_item(self, item, spider):
    if isinstance(item, items.DetailsItem): 
        item['city'] = item['city'].encode('utf-8')

        self.modelsCsv.writerow([item['city']]) 
        return item
  

Самое странное, что моя система (python в Windows) отлично обрабатывает строки unicode:

 C:Console2>python
Python 2.7.6 (default, Nov 10 2013, 19:24:18) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> s=u'Beim Nonnenhausxa0672070xa0Txfcbingen'
>>> print s
Beim Nonnenhaus 672070 Tübingen
  

Я много читал о utf-8, unicode, кодировании и декодировании за последние 10 дней, но, похоже, я все еще что-то здесь упускаю?!
Я ценю любую помощь или совет.

Ответ №1:

Вы игнорируете результат .encode() вызова:

 item['city'].encode('utf-8')
  

Строки неизменяемы и не кодируются на месте. Еще лучше, что тип возвращаемого объекта отличается. Вам нужно будет присвоить возвращаемое значение обратно:

 item['city'] = item['city'].encode('utf-8')
  

Однако вы не должны использовать codecs.open() для файла CSV. csv Модуль всегда будет записывать байтовые строки, а не Юникод.

При использовании codecs.open() файлового объекта выполняется неявное декодирование для возврата к Unicode, и именно это у вас не получается; именно поэтому вы получаете UnicodeDecodeError исключение, а не ошибку кодирования:

   File "C:Python27libcodecs.py", line 351, in write
    data, consumed = self.encode(object, self.errors)
exceptions.UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 11: ordinal not in range(128)
  

Вместо этого используйте обычный open() вызов:

 self.modelsCsv = csv.writer(open('Dees.csv', mode='wb'))
  

Обратите внимание на 'wb' ; csv модуль сам обрабатывает окончания строк.

Комментарии:

1. Извините, каким-то образом я пропустил это в своем коде, это уже было на месте… Я редактирую свой пост. Спасибо за ответ.

2. @mrki: верно, это потому, что вы используете codecs.open() ; Я пропустил это. В следующий раз было бы очень полезно включить обратную трассировку в ваш вопрос ! 🙂

3. Я действительно не понял этого из отслеживания ошибки: (сейчас вы спасаете мне жизнь 🙂 Я использовал вызов open () во всех моих предыдущих сканерах. На этот раз я действительно подумал, что мне нужен файл utf-8 для хранения сведений в виде байтовых строк, а не строк unicode. Но зачем мне это нужно сейчас, если я просто могу выбрать кодировку, если мне нужно открыть свой файл для ручного редактирования. Что за беспорядок! Хотя для меня это очень хороший опыт! Спасибо Martijn!

Ответ №2:

Вы можете использовать параметр «игнорировать»:

 item['city'].encode('utf-8', 'ignore')
  

https://docs.python.org/2/howto/unicode.html#the-unicode-type

Комментарии:

1. UTF-8 может обрабатывать все кодовые точки Unicode; здесь нечего игнорировать .