Ошибка Unicode при выводе вывода python script в файл

Это код:

print '"' + title.decode('utf-8', errors='ignore') + '",' \
      ' "' + title.decode('utf-8', errors='ignore') + '", ' \
      '"' + desc.decode('utf-8', errors='ignore') + '")'

title и desc возвращаются Beautiful Soup 3 (p [0].text и p [0].prettify), и, насколько я могу понять из документации BeautifulSoup3, кодируется UTF-8.

Если я запустил

python.exe script.py > out.txt

Я получаю следующую ошибку:

Traceback (most recent call last):
  File "script.py", line 70, in <module>
    '"' + desc.decode('utf-8', errors='ignore') + '")'
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf8' in position 264
: ordinal not in range(128)

Однако, если я запустил

python.exe script.py

Я не ошибаюсь. Это происходит только в том случае, если указан выходной файл.

Как получить хорошие данные UTF-8 в выходном файле?

Ответы

Ответ 1

Вы можете использовать модуль кодеков для записи данных в формате Unicode в файл

import codecs
file = codecs.open("out.txt", "w", "utf-8")
file.write(something)

'print' выводится на стандартный вывод, и если ваша консоль не поддерживает utf-8, это может вызвать такую ​​ошибку, даже если вы передаете stdout в файл.

Ответ 2

Поведение Windows в этом случае немного сложнее. Вы должны слушать другие советы и внутренне использовать unicode для строк и декодировать во время ввода.

На ваш вопрос вам нужно напечатать закодированные строки (только вы знаете, какая кодировка!) в случае перенаправления stdout, но вы должны печатать строки unicode в случае простого вывода на экран (а python или windows обрабатывает конверсию в правильное кодирование).

Я рекомендую структурировать ваш script следующим образом:

# -*- coding: utf-8 -*- 
import sys, codecs
# set up output encoding
if not sys.stdout.isatty():
    # here you can set encoding for your 'out.txt' file
    sys.stdout = codecs.getwriter('utf8')(sys.stdout)

# next, you will print all strings in unicode
print u"Unicode string ěščřžý"

Обновление: см. также другой аналогичный вопрос: Установка правильной кодировки при отправке stdout трубопровода в Python

Ответ 3

Нет смысла конвертировать текст в Юникод, чтобы распечатать его. Работайте со своими данными в юникоде, преобразуйте его в некоторую кодировку для вывода.

Вместо этого ваш код: вы находитесь на python 2, поэтому ваш тип строки по умолчанию (str) является байтовым. В вашем заявлении вы начинаете с некоторых строк байтов, закодированных в utf, конвертируете их в Юникод, окружаете их кавычками (регулярные str, которые принуждаются к юникоду для объединения в одну строку). Затем вы передаете эту строку юникода в print, которая подталкивает ее к sys.stdout. Для этого необходимо превратить его в байты. Если вы пишете на консоль Windows, он может каким-то образом договориться, но если вы перенаправляетесь на обычный немой файл, он возвращается на ascii и жалуется, потому что нет никакого способа сделать это без потерь.

Решение. Не указывайте print строку юникода. "закодируйте" его сами по своему выбору:

print "Latin-1:", "unicode über alles!".decode('utf-8').encode('latin-1')
print "Utf-8:", "unicode über alles!".decode('utf-8').encode('utf-8')
print "Windows:", "unicode über alles!".decode('utf-8').encode('cp1252')

Все это должно работать без жалобы при перенаправлении. Вероятно, он не будет выглядеть правильно на вашем экране, но откройте выходной файл с помощью Notepad или что-то еще и посмотрите, установлен ли ваш редактор для просмотра формата. (Utf-8 является единственным, у которого есть надежда на обнаружение. Cp1252 - вероятный Windows по умолчанию).

Как только вы получите это, очистите свой код и не используйте print для вывода файла. Используйте модуль codecs и открывайте файлы с codecs.open, а не открытыми.

PS. Если вы декодируете строку utf-8, преобразование в unicode должно быть без потерь: вам не нужен флаг errors=ignore. Это подходит, если вы конвертируете в ascii или Latin-2 или что-то еще, и хотите просто отбросить символы, которые не существуют в целевой кодовой странице.

Ответ 4

Проблема: если вы работаете в Windows:

python.exe script.py

Будет действовать следующее:

sys.stdout.encoding: utf-8
sys.stdout.isatty(): True

Но если вы запустите:

python.exe script.py > out.txt

у вас действительно будет это:

sys.stdout.encoding: cp1252
sys.stdout.isatty(): False

Итак, возможное решение (В ПИТОНЕ> 3.7):

import sys
if not sys.stdout.isatty():
    sys.stdout.reconfigure(encoding='utf-8')

print '"' + title.decode('utf-8', errors='ignore') + '",' \
      ' "' + title.decode('utf-8', errors='ignore') + '", ' \
      '"' + desc.decode('utf-8', errors='ignore') + '")'

Смотрите также: Как установить кодировку sys.stdout в Python 3?