Декодировать сущности HTML в строку Python?

266

Я разбираю немного HTML с Beautiful Soup 3, но он содержит HTML-сущности, которые Beautiful Soup 3 автоматически не декодирует для меня:

>>> from BeautifulSoup import BeautifulSoup

>>> soup = BeautifulSoup("<p>&pound;682m</p>")
>>> text = soup.find("p").string

>>> print text
&pound;682m

Как я могу декодировать HTML-сущности, textчтобы получить "£682m"вместо "&pound;682m".

JKP
источник

Ответы:

521

Python 3.4+

Используйте html.unescape():

import html
print(html.unescape('&pound;682m'))

К вашему сведению html.parser.HTMLParser.unescapeустарела, и должна была быть удалена в 3.5 , хотя она была оставлена ​​по ошибке. Это будет удалено из языка в ближайшее время.


Python 2.6-3.3

Вы можете использовать HTMLParser.unescape()из стандартной библиотеки:

>>> try:
...     # Python 2.6-2.7 
...     from HTMLParser import HTMLParser
... except ImportError:
...     # Python 3
...     from html.parser import HTMLParser
... 
>>> h = HTMLParser()
>>> print(h.unescape('&pound;682m'))
£682m

Вы также можете использовать sixбиблиотеку совместимости, чтобы упростить импорт:

>>> from six.moves.html_parser import HTMLParser
>>> h = HTMLParser()
>>> print(h.unescape('&pound;682m'))
£682m
Luc
источник
9
похоже, этот метод не экранирует символы типа "& # 8217;" на Google App Engine, хотя он работает локально на Python2.6. Он по-прежнему декодирует сущности (как & quot;), по крайней мере
gfxmonk
Как недокументированный API не рекомендуется использовать? Отредактировал ответ.
Маркус Унтервадитцер
@MarkusUnterwaditzer нет причины, по которой недокументированный метод не может быть признан устаревшим. Этот бросает предупреждения об устаревании - см. Мое изменение к ответу.
Марк Амери
Казалось бы более логичным, что вместо только unescapeметода весь HTMLParserмодуль устарел в пользу html.parser.
Том Рассел
Стоит отметить, что для Python 2: специальные символы заменены их аналогами кодировки Latin-1 (ISO-8859-1). Например, это может быть необходимо h.unescape(s).encode("utf-8"). Документы: "" "Представленное здесь определение содержит все объекты, определенные в XHTML 1.0, которые могут быть обработаны с помощью простой текстовой подстановки в наборе символов Latin-1 (ISO-8859-1)" ""
анонимный трус
65

Красивый Суп обрабатывает преобразование сущности. В Beautiful Soup 3 вам необходимо указать convertEntitiesаргумент для BeautifulSoupконструктора (см. Раздел « Преобразование сущностей» заархивированных документов). В Beautiful Soup 4 сущности декодируются автоматически.

Красивый суп 3

>>> from BeautifulSoup import BeautifulSoup
>>> BeautifulSoup("<p>&pound;682m</p>", 
...               convertEntities=BeautifulSoup.HTML_ENTITIES)
<p682m</p>

Красивый суп 4

>>> from bs4 import BeautifulSoup
>>> BeautifulSoup("<p>&pound;682m</p>")
<html><body><p682m</p></body></html>
Бен Джеймс
источник
+1. Понятия не имею, как я пропустил это в документах: спасибо за информацию. Я собираюсь принять ответ Люка, потому что он использует стандартную библиотеку, которую я указал в вопросе (не важно для меня), и, вероятно, более общего использования для других людей.
JKP
5
BeautifulSoup4использует HTMLParser, в основном. Смотрите источник
scharfmn
4
Как получить преобразование в Beautiful Soup 4 без всего лишнего HTML, который не был частью исходной строки? (т.е. <HTML> и <тело>)
Пракситель
@Praxiteles: BeautifulSoup ('& pound; 682m', "html.parser") stackoverflow.com/a/14822344/4376342
Soitje
13

Вы можете использовать replace_entities из библиотеки w3lib.html

In [202]: from w3lib.html import replace_entities

In [203]: replace_entities("&pound;682m")
Out[203]: u'\xa3682m'

In [204]: print replace_entities("&pound;682m")
£682m
Corvax
источник
2

Beautiful Soup 4 позволяет вам установить форматер для вывода

Если вы укажете formatter=None, Beautiful Soup не будет изменять строки на выходе. Это самый быстрый вариант, но он может привести к созданию Beautiful Soup неверного HTML / XML, как в следующих примерах:

print(soup.prettify(formatter=None))
# <html>
#  <body>
#   <p>
#    Il a dit <<Sacré bleu!>>
#   </p>
#  </body>
# </html>

link_soup = BeautifulSoup('<a href="http://example.com/?foo=val1&bar=val2">A link</a>')
print(link_soup.a.encode(formatter=None))
# <a href="http://example.com/?foo=val1&bar=val2">A link</a>
LoicUV
источник
Это не отвечает на вопрос. (Кроме того, я понятия не имею, что здесь говорят о недействительности документации о последнем фрагменте HTML здесь.)
Марк Эмери
<< Sacré bleu! >> является недопустимой частью, так как она выходит за пределы <и> и нарушает HTML-код вокруг нее. Я знаю, что это поздний пост от меня, но на случай, если кто-то посмотрит и
удивится
0

У меня была похожая проблема с кодировкой. Я использовал метод normalize (). Я получал ошибку Unicode, используя метод pandas .to_html () при экспорте моего фрейма данных в файл .html в другом каталоге. Я закончил тем, что делал это, и это работало ...

    import unicodedata 

Объект dataframe может быть любым, назовем его таблицей ...

    table = pd.DataFrame(data,columns=['Name','Team','OVR / POT'])
    table.index+= 1

закодируйте данные таблицы, чтобы мы могли экспортировать их в файл .html в папке шаблонов (это может быть любое место, которое вы пожелаете :))

     #this is where the magic happens
     html_data=unicodedata.normalize('NFKD',table.to_html()).encode('ascii','ignore')

экспортировать нормализованную строку в HTML-файл

    file = open("templates/home.html","w") 

    file.write(html_data) 

    file.close() 

Ссылка: документация unicodedata

Alex
источник
-4

Это, вероятно, здесь не актуально. Но чтобы исключить эти HTML-элементы из всего документа, вы можете сделать что-то вроде этого: (Допустим, document = page и, пожалуйста, простите неаккуратный код, но если у вас есть идеи, как сделать его лучше, я все слышу - я новичок в этот).

import re
import HTMLParser

regexp = "&.+?;" 
list_of_html = re.findall(regexp, page) #finds all html entites in page
for e in list_of_html:
    h = HTMLParser.HTMLParser()
    unescaped = h.unescape(e) #finds the unescaped value of the html entity
    page = page.replace(e, unescaped) #replaces html entity with unescaped value
Нил Аггарвал
источник
7
Нет! Вам не нужно сопоставлять сущности HTML самостоятельно и перебирать их; .unescape()делает это для вас . Я не понимаю, почему вы и Роб опубликовали эти слишком сложные решения, которые проверяют соответствие своих сущностей, когда принятый ответ уже ясно показывает, что .unescape()можно найти сущности в строке.
Марк Амери