Оновлення 2018 року:
Станом на лютий 2018 року використання таких компресій gzip
стало досить популярним (близько 73% всіх веб-сайтів використовують його, включаючи великі сайти, такі як Google, YouTube, Yahoo, Wikipedia, Reddit, Stack Overflow та Stack Exchange Network).
Якщо ви виконаєте просте декодування, як в оригінальній відповіді з gzipped відповіддю, ви отримаєте помилку, подібну до цього:
UnicodeDecodeError: 'utf8' кодек не може декодувати байт 0x8b в позиції 1: несподіваний байт коду
Для декодування відповіді gzpipped вам потрібно додати наступні модулі (в Python 3):
import gzip
import io
Примітка. У Python 2 ви використовуєте StringIO
замість цьогоio
Тоді ви можете розібрати вміст так:
response = urlopen("https://example.com/gzipped-ressource")
buffer = io.BytesIO(response.read()) # Use StringIO.StringIO(response.read()) in Python 2
gzipped_file = gzip.GzipFile(fileobj=buffer)
decoded = gzipped_file.read()
content = decoded.decode("utf-8") # Replace utf-8 with the source encoding of your requested resource
Цей код зчитує відповідь і розміщує байти в буфері. Потім gzip
модуль зчитує буфер за допомогоюGZipFile
функції. Після цього gzipped файл можна знов прочитати в байти і в кінці розшифрувати до нормально читаного тексту.
Оригінальний відповідь від 2010 року:
Чи можемо ми використати фактичне значення link
?
Крім того, ми зазвичай стикаємося з цією проблемою тут, коли ми намагаємося .encode()
вже закодований рядок байтів. Тому ви можете спробувати розшифрувати його спочатку як в
html = urllib.urlopen(link).read()
unicode_str = html.decode(<source encoding>)
encoded_str = unicode_str.encode("utf8")
Як приклад:
html = '\xa0'
encoded_str = html.encode("utf8")
Не вдається з
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128)
Поки:
html = '\xa0'
decoded_str = html.decode("windows-1252")
encoded_str = decoded_str.encode("utf8")
Успіх без помилок. Зауважте, що "windows-1252" - це те, що я використовував як приклад . Я отримав це від шардета, і він мав 0,5 впевненості, що це правильно! (ну, як задано рядком довжиною 1 символу, що ви очікуєте) Ви повинні змінити це на кодування рядка байтів, повернене з.urlopen().read()
того, що стосується вмісту, який ви отримали.
Ще одна проблема, яку я бачу там, полягає в тому, що .encode()
метод string повертає модифіковану рядок і не змінює джерело на місці. Так що марно мати, self.response.out.write(html)
оскільки html - це не закодований рядок з html.encode (якщо саме це ви спочатку прагнули).
Як запропонував Ігнасіо, перевірте вихідну веб-сторінку на предмет фактичного кодування повернутого рядка з read()
. Це або в одному з тегів Meta, або у заголовку ContentType у відповіді. Використовуйте це тоді як параметр для .decode()
.
Однак зауважте, що не слід вважати, що інші розробники несуть достатню відповідальність, щоб переконатися, що декларації заголовка та / або мета символів відповідають дійсному вмісту. (Що таке ПІТА, так, я маю знати, я був одним із таких раніше).