Кодирование в python с помощью lxml - комплексное решение - PullRequest
10 голосов
/ 22 апреля 2010

Мне нужно загрузить и проанализировать веб-страницу с помощью lxml и создать вывод в формате UTF-8 xml. Я думаю, что схема в псевдокоде является более наглядной:

from lxml import etree

webfile = urllib2.urlopen(url)
root = etree.parse(webfile.read(), parser=etree.HTMLParser(recover=True))

txt = my_process_text(etree.tostring(root.xpath('/html/body'), encoding=utf8))


output = etree.Element("out")
output.text = txt

outputfile.write(etree.tostring(output, encoding=utf8))

Таким образом, веб-файл может быть в любой кодировке (lxml должен обрабатывать это). Выходной файл должен быть в utf-8. Я не уверен, где использовать кодирование / кодирование. Эта схема в порядке? (Я не могу найти хороший учебник по lxml и кодированию, но я могу найти много проблем с этим ...) Мне нужно надежное решение.

Edit:

Так что для отправки utf-8 в lxml я использую

        converted = UnicodeDammit(webfile, isHTML=True)
        if not converted.unicode:
            print "ERR. UnicodeDammit failed to detect encoding, tried [%s]", \
                ', '.join(converted.triedEncodings)
            continue
        webfile = converted.unicode.encode('utf-8')

Ответы [ 2 ]

18 голосов
/ 22 апреля 2010

lxml может быть немного странным в отношении кодировок ввода. Лучше всего отправить UTF8 и получить UTF8.

Возможно, вы захотите использовать модуль chardet или UnicodeDammit для декодирования фактических данных.

Вы бы хотели сделать что-то вроде:

import chardet
from lxml import html
content = urllib2.urlopen(url).read()
encoding = chardet.detect(content)['encoding']
if encoding != 'utf-8':
    content = content.decode(encoding, 'replace').encode('utf-8')
doc = html.fromstring(content, base_url=url)

Я не уверен, почему вы переходите между lxml и etree, если вы не взаимодействуете с другой библиотекой, которая уже использует etree?

2 голосов
/ 06 июля 2012

lxml обнаружение кодировки слабое .

Однако учтите, что наиболее распространенной проблемой веб-страниц является отсутствие из (или наличие неправильных) объявлений кодирования. это поэтому часто достаточно использовать только обнаружение кодирования BeautifulSoup, называемый UnicodeDammit, а остальное оставить для lxml собственный HTML-парсер, который работает в несколько раз быстрее.

Я рекомендую обнаруживать кодировку, используя UnicodeDammit , и анализировать, используя lxml . Кроме того, вы можете использовать заголовок http Content-Type (вам нужно извлечь charset = ENCODING_NAME ) для более точного определения кодировки.

Для этого примера я использую BeautifulSoup4 (также вам нужно установить chardet для лучшего автоопределения, потому что UnicodeDammit использует chardet внутри ):

from bs4 import UnicodeDammit

if http_charset == "":
    ud = UnicodeDammit(content, is_html=True)
else:
    ud = UnicodeDammit(content, override_encodings=[http_charset], is_html=True)
root = lxml.html.fromstring(ud.unicode_markup)

ИЛИ, чтобы сделать предыдущий ответ более полным, вы можете изменить его на:

if ud.original_encoding != 'utf-8':
    content = content.decode(ud.original_encoding, 'replace').encode('utf-8')

Почему это лучше, чем просто использовать chardet?

  1. Вы не игнорируете Content-Type HTTP header

    Content-Type: Текст / html; кодировка = UTF-8

  2. Вы не игнорируете метатег http-эквивалент . Пример:

    ... http-equ = "Content-Type" content = "text / html; charset = UTF-8" ...

  3. Кроме того, вы используете мощность chardet , cjkcodecs и iconvcodec кодеков и и многих других .

...