Розшифрувати сутність 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".


Відповіді:


521

Python 3.4+

Використання html.unescape():

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

FYI html.parser.HTMLParser.unescapeзастаріла, і її слід було видалити в 3,5 , хоча це було залишено помилково. Це буде видалено з мови незабаром.


Python 2.6-3.3

Ви можете використовувати HTMLParser.unescape()зі стандартної бібліотеки:

  • Для Python 2.6-2.7 він знаходиться в HTMLParser
  • Для Python 3 він є html.parser
>>> 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

9
цей метод, схоже, не уникає символів типу "& # 8217;" на двигуні додатка google, хоча він працює локально на python2.6. Він все ще розшифровує сутності (наприклад, & quot;) щонайменше
gfxmonk

Як можна заставити незадокументований API? Відредагував відповідь.
Маркус Унтервадітцер

@MarkusUnterwaditzer немає причин, що недокументований метод не може бути застарілим. Це накидає попередження про депресію - дивіться мою редакцію відповіді.
Марк Амері

Здавалося б, більш логічним є те, що, а не лише unescapeметод, весь HTMLParserмодуль був вичерпаний на користь html.parser.
Том Расселл

Варто зауважити для Python 2: Спеціальні символи замінюються на їх аналоги, що кодують латинську 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> і <body>)
Praxiteles

@Praxiteles: BeautifulSoup ( '& фунт; 682 млн', "html.parser") stackoverflow.com/a/14822344/4376342
Soitje

13

Ви можете використовувати заміна_файлів з бібліотеки 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

2

Beautiful Soup 4 дозволяє встановити формат для вашого виводу

Якщо ви переходите до програми formatter=None, 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>

Це не відповідає на запитання. (Крім того, я не маю уявлення про те, що документи говорять, що недійсні щодо останнього біта HTML тут.)
Марк Амерді

<< Sacré bleu! >> є недійсною частиною, оскільки вона не змінила розмір <і> і порушить html навколо неї. Я знаю, що це пізній пост від мене, але на випадок, коли хтось дивиться і цікавиться ...
GMasucci

0

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

    import unicodedata 

Об'єктом фрейму даних може бути все, що завгодно, назвемо його таблицею ...

    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


-4

Це, мабуть, тут не актуально. Але щоб усунути ці HTML-елементи з цілого документа, ви можете зробити щось на зразок цього: (Припустимо, що документ = сторінка і, будь ласка, пробачте неохайний код, але якщо у вас є ідеї, як зробити це краще, я всі вуха - я новачок у це).

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()можуть знаходити сутності в рядку.
Марк Амері
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.