Andrbez
@Andrbez
Procrastination

Как распаковать zip-архив с русскими именами файлов в Python?

Задача: скачать прайс-лист поставщика в архиве, распаковать и передать данные парсеру. Отлично работал до тех пор, пока в архиве не стали использоваться русские имена файлов.

import requests
from io import BytesIO
from zipfile import ZipFile

# Создаем сессию
s = requests.Session()

# Авторизуемся и получаем ссылку на zip-архив
# ...

# Скачиваем zip-архив
request = s.get(self.url_price, cookies=cookies)

# Извлекаем данные
zip_data = ZipFile(BytesIO(request.content))
xls_data = zip_data.open(zip_data.namelist()[0])


Выдает ошибку BadZipFile:
File name in directory 'Åαá⌐ß½¿ßΓ_æá¼áαá.xml' and header b'\xcf\xf0\xe0\xe9\xf1\xeb\xe8\xf1\xf2_\xd1\xe0\xec\xe0\xf0\xe0.xml' differ.

Предполагаю, что проблему можно обойти, указав кодировку, или обратившись к файлу не по имени, а по индексу, но в описании zipfile не нашел ничего подобного.

Уточнение: используется Python 3.4.

UPD: приведение имени к читабельному виду смог сделать так:
name = zip_data.namelist()[0]
name = bytes(name, 'CP437').decode('CP866')


При попытке открыть файл с этим именем:
xls_data = zip_data.open(name)

Система сообщает, что не может найти файл в архиве с ошибкой:
KeyError
"There is no item named 'Прайслист_Самара.xml' in the archive"
  • Вопрос задан
  • 5599 просмотров
Решения вопроса 1
@Andy_U
Перепишите файл zipfile.py из библиотеки питона к себе, и исправьте строки decode('cp437') и decode("cp437") на decode('cp866'). По-крайней мере, имена файлов внутри архивов станут правильными. Ну и еще надо иметь ввиду, что метод read() выдает байты, а не строки.

Кстати, если всегда

bytes.decode('cp437').encode('cp437') == bytes

то можно обойтись и без патча zipfile.py:

f = ZipFile('z.zip', 'r')

for name in f.namelist():
    unicode_name = name.encode('cp437').decode('cp866')
    print(unicode_name)


P.S. Почему имена файлов хранятся внутри архива в OEM кодировке, я не понимаю. Что Windows так делает, что 7-zip.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@aon24
akarin забыл указать, что ссылка демонстрирует решение для Python 2.7
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы