Проблема кодирования синтаксического анализатора в Python3 html и lxml - PullRequest
0 голосов
/ 01 сентября 2018

При анализе некоторого HTML с использованием BeautifulSoup или PyQuery они будут использовать синтаксический анализатор, такой как lxml или html5lib. Допустим, у меня есть файл, содержащий следующее

<span>  é    and    ’  </span>

В моей среде они кажутся неправильно закодированными, используя PyQuery:

>>> doc = pq(filename=PATH, parser="xml")
>>> doc.text()
'é and â\u20ac\u2122'
>>> doc = pq(filename=PATH, parser="html")
>>> doc.text()
'Ã\x83© and ââ\x82¬â\x84¢'
>>> doc = pq(filename=PATH, parser="soup")
>>> doc.text()
'é and â\u20ac\u2122'
>>> doc = pq(filename=PATH, parser="html5")
>>> doc.text()
'é and â\u20ac\u2122'

Помимо того факта, что кодировка кажется неправильной, одна из основных проблем заключается в том, что doc.text() возвращает экземпляр str вместо bytes, что не является нормой в соответствии с этим вопросом Я спросил вчера.

Кроме того, передача аргумента encoding='utf-8' в PyQuery кажется бесполезной, я пытался 'latin1' ничего не изменить. Я также попытался добавить некоторые метаданные, потому что я прочитал, что lxml прочитал их, чтобы выяснить, какую кодировку использовать, но это ничего не меняет:

<!DOCTYPE html>
<html lang="fr" dir="ltr">
<head>
<meta http-equiv="content-type" content="text/html;charset=latin1"/>
<span>  é    and    ’  </span>
</head>
</html>  

Если я использую lxml напрямую, это кажется немного другим

>>> from lxml import etree
>>> tree = etree.parse(PATH)
>>> tree.docinfo.encoding
'UTF-8'

>>> result = etree.tostring(tree.getroot(), pretty_print=False)
>>> result
b'<span>  &#233;    and    &#8217;  </span>'

>>> import html
>>> html.unescape(result.decode('utf-8'))
'<span>  é    and    \u2019  </span>\n'

Erf, это меня немного сводит с ума, ваша помощь будет оценена

1 Ответ

0 голосов
/ 01 сентября 2018

Думаю, я понял это. Похоже, что даже BeautifulSoup или PyQuery позволяют это делать, плохая идея открывать файл, содержащий некоторые специальные символы UTF-8. Особенно меня смутило то, что символ «’ »неправильно обрабатывается моим терминалом Windows. Итак, решение состоит в том, чтобы предварительно обработать файл перед его разбором:

def pre_process_html_content(html_content, encoding=None):
    """Pre process bytes coming from file or request."""
    if not isinstance(html_content, bytes):
        raise TypeError("html_content must a bytes not a " + str(type(html_content)))

    html_content = html_content.decode(encoding)


    # Handle weird symbols here
    html_content = html_content.replace('\u2019', "'")

    return html_content


def sanitize_html_file(path, encoding=None):
    with open(path, 'rb') as f:
        content = f.read()
    encoding = encoding or 'utf-8'

    return pre_process_html_content(content, encoding)


def open_pq(path, parser=None, encoding=None):
    """Macro for open HTML file with PyQuery."""
    content = sanitize_html_file(path, encoding)
    parser = parser or 'xml'

    return pq(content, parser=parser)


doc = open_pq(PATH)
...