ТипError: write() аргумент 1 должен быть unicode, а не str

Я пытаюсь импортировать текстовый файл и сохранить его на рабочем столе, но текст находится в "utf-8" (эта информация есть в книге), поэтому при сохранении без кодирования текст содержит много странных символов, но когда Я пытаюсь сохранить с явным кодированием появляется эта ошибка:

Traceback (most recent call last):

File "C:/Users/Unidas/Semestre/ABC/8.1.py", line 14, in n_palabras

libro.write(archivo.read())

TypeError: write() argument 1 must be unicode, not str

Код:

def n_palabras(x):
    import urllib2
    import io
    import string

    archivo = urllib2.urlopen(x)
    libro = io.open("alice.txt", "w", encoding="utf8")
    libro.write(archivo.read())
    libro.close()

Как я могу сохранить этот файл с кодировкой UTF-8? Я использую Pycharm с Python 2.7

+5
источник поделиться
1 ответ

Ваша проблема в том, что urlopen возвращает объект, urlopen на байты, в то время как io.open ожидает истинные текстовые входы (где "текст" означает " unicode на Python 2, str на Python 3").

Единственное, что вам нужно изменить - это decode результат вызова read; по умолчанию это байты, и вам нужен истинный текст. Вам нужно выяснить правильную кодировку (либо жестко кодировать, либо явно проверять заголовки, чтобы понять ее), чтобы правильно ее декодировать (вероятно, это UTF-8 или, что менее вероятно, cp1252, но это может быть что-то странное).

В любом случае, зная, что единственное изменение, которое вам нужно будет сделать, это изменить:

libro.write(archivo.read())

чтобы:

libro.write(archivo.read().decode(knownencoding))

Если вы уверены, что сервер всегда предоставляет выход UTF-8, то:

libro.write(archivo.read().decode('utf-8'))

достаточно. Да, это мягко расточительно (вы декодируете его только для того, чтобы записать его в поток, который сразу же перекодирует его), но, что немаловажно, это дает вам гарантию того, что полученные вами байты будут интерпретироваться как допустимый UTF-8, который сбрасывает необработанные байты на диск не гарантирует.

Более сложное решение проверяет заголовки:

import urllib2
import io
import string

def n_palabras(x):
    archivo = urllib2.urlopen(x)

    # Find charset in headers, if it exists    
    for p in archivo.headers.plist:
        key, sep, value = p.partition('=')
        if sep and key.strip().lower() == 'charset':
           encoding = value.strip()
           break
    else:
        encoding = 'utf-8'

    data = archivo.read()

    try:
        # Try to use parsed charset
        data = data.decode(encoding)
    except UnicodeDecodeError:
        # If that fails, try UTF-8 as fallback; let exception bubble
        # if this fails too
        data = data.decode('utf-8')

    with io.open("alice.txt", "w", encoding="utf-8") as libro:
        libro.write(data)
+5
источник

Посмотрите другие вопросы по меткам или Задайте вопрос