Проблема не в codecs.open
- это в передаче .write
байтовой строке, которая (учитывая код \xd0
в ней) четко кодируется в некотором ISO-8859-*
или связанном кодеке.
urllib2.urlopen возвращает объект ответа, который, помимо файлового поведения, в качестве дополнительного метода:
info()
- вернуть метаинформацию
страницы, такие как заголовки, в
форма httplib.HTTPMessage
экземпляр (см. Краткое руководство по HTTP
Заголовки )
В частности, заголовок Content-Type
для текстоподобного содержимого должен иметь параметр charset
, определяющий используемую им кодировку, например, Content-Type: text/html; charset=ISO-8859-4
. Вам нужно проанализировать и изолировать charset
и использовать его для декодирования содержимого в Unicode (поэтому ваш codecs.open
ed файловый объект всегда получает аргументы Unicode в write
и правильно записывает их в utf-8
).
Если charset
отсутствует, или использование его для декодирования текста приводит к ошибкам (предполагая, что charset
неверно), в качестве последней надежды на спасение вы можете попробовать Universal Encoding Detector , который использует эвристика для этой цели (в конце концов, многие страницы в сети содержат ужасные ошибки метаданных, а также неработающий HTML и т. д.)