Верстакфорум практиков
рекламаiprazon: приватные серверные адреса IPv4 и SOCKS5, безлимитный трафик, бесплатный тест до 2 часов
ФорумСбор данных

Кодировки: откуда берутся кракозябры в выгрузке

Борис Лапин
Борис Лапин
Знаток
сообщений 1960
с мар
8 октября, 11:57первое сообщение

Свожу каталог с трёх поставщиков в один CSV. У двоих названия читаются, у третьего в файле вот такое:

Ð¡Ð¾ÑƒÑ Ñ‡ÐµÑночный 250 г

В браузере страница открывается нормально, curl в терминал тоже выводит по-русски. Ломается где-то по дороге до файла.

Куда смотреть первым делом?

hexdump
hexdump
Знаток
сообщений 940
с июн
15 марта, 14:14#2

В байты и смотреть. Возьмите одно слово, гляньте дамп до записи и после.

Вот эта Ð с хвостом верный признак: текст в utf-8 прочитали как cp1251 и записали обратно в utf-8. Двойной проход.

Борис Лапин
Борис Лапин
Знаток
сообщений 1960
с мар
22 августа, 17:31#3
hexdump: прочитали как cp1251 и записали обратно в utf-8

Кто мог прочитать? Я кодировку нигде руками не задаю.

Юля Ким
Юля Ким
Знаток
сообщений 1240
с мая
1 января, 08:48#4

Вот отсюда и растёт. Раз кодировка не задана, её угадывают за вас, и каждая библиотека угадывает по-своему.

requests берёт charset из заголовка Content-Type. Заголовка нет, и для text/* ставится latin-1 по старому правилу. Дальше вы получаете строку с мусором ещё до разбора.

r = requests.get(url)
print(r.headers.get("content-type"))   # text/html, без charset
print(r.encoding)                      # ISO-8859-1
r.encoding = "utf-8"                   # ставим руками
tekst = r.text
Света Панина
Света Панина
Новичок
сообщений 160
с мар, второй сезон
8 июня, 11:05#5

а если в meta на странице написано windows-1251, а сервер отдаёт utf-8, кого слушать?

rawsocket
rawsocket
Ветеран
сообщений 2290
с фев
15 ноября, 14:22#6

Порядок такой, он же и порядок разбора в браузере.

Сначала заголовок ответа. Есть в Content-Type внятный charset, он и главный. Нет его, лезем в первые 1024 байта тела и ищем meta charset. Пусто и там, пробуем utf-8, при ошибке декодирования откатываемся на cp1251. Для русских сайтов эта пара покрывает почти всё.

Врут, кстати, обе стороны. Бывает заголовок с utf-8, а внутри cp1251, потому что шаблон правили одни люди, отдачу настраивали другие. Поэтому после декодирования полезно быстро глянуть на результат: считаете долю символов U+FFFD и одиночных вопросительных знаков, и если она выше пары процентов, кодировка выбрана мимо. Проверка занимает три строки и ловит ровно тот случай, когда формально всё сошлось.

И отдельно про запись. Файл открывайте с явной кодировкой, иначе Windows подставит свою системную и вы получите второй такой же проход уже на выходе. Excel по двойному щелчку читает CSV в системной кодировке, поэтому под него пишут utf-8 с меткой в начале файла.

with open("vygruzka.csv", "w", encoding="utf-8-sig", newline="") as f:
    ...
один и тот же слог до и после лишнего прохода
один и тот же слог до и после лишнего прохода
читаю байты, а потом уже документацию
Борис Лапин
Борис Лапин
Знаток
сообщений 1960
с мар
22 апреля, 17:39#7

Нашёл. У третьего поставщика заголовок пустой, requests ставил latin-1, а я потом записывал строку в utf-8. Ровно двойной проход, как вы и сказали.

Поставил кодировку руками, файл пишу с меткой в начале. Excel открывает без плясок, названия целые. Спасибо, тема закрыта.