Dekodować encje HTML w ciągu Python?


266

Analizuję trochę HTML z Beautiful Soup 3, ale zawiera encje HTML, które Beautiful Soup 3 nie dekodują automatycznie dla mnie:

>>> from BeautifulSoup import BeautifulSoup

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

>>> print text
&pound;682m

Jak mogę dekodować encje HTML, textaby uzyskać "£682m"zamiast "&pound;682m".


Odpowiedzi:


521

Python 3.4+

Użyj html.unescape():

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

FYI html.parser.HTMLParser.unescapejest przestarzałe i miało zostać usunięte w 3.5 , chociaż zostało pozostawione przez pomyłkę. Wkrótce zostanie usunięty z języka.


Python 2.6-3.3

Możesz użyć HTMLParser.unescape()ze standardowej biblioteki:

>>> 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

Możesz także użyć sixbiblioteki kompatybilności, aby uprościć import:

>>> from six.moves.html_parser import HTMLParser
>>> h = HTMLParser()
>>> print(h.unescape('&pound;682m'))
£682m

9
ta metoda nie wydaje się unikać znaków takich jak „& # 8217;” w silniku aplikacji Google, chociaż działa lokalnie na python2.6. Nadal dekoduje byty (jak ") przynajmniej
gfxmonk

Jak można wycofać nieudokumentowane API? Edytowałem odpowiedź.
Markus Unterwaditzer

@MarkusUnterwaditzer nie ma powodu, dla którego nieudokumentowana metoda nie może być przestarzała. Ten rzuca ostrzeżenia o wycofaniu - zobacz moją edycję odpowiedzi.
Mark Amery

Wydaje się bardziej logiczne, że zamiast samej unescapemetody cały HTMLParsermoduł był przestarzały na korzyść html.parser.
Tom Russell

Warto zwrócić uwagę na Python 2: Znaki specjalne są zamieniane na ich odpowiedniki Latin-1 (ISO-8859-1). Np. Może być konieczne h.unescape(s).encode("utf-8"). Dokumenty: „” „Podana tutaj definicja zawiera wszystkie byty zdefiniowane przez XHTML 1.0, które można obsługiwać za pomocą prostego zastępowania tekstu w zestawie znaków Latin-1 (ISO-8859-1)„ ””
anonimowy tchórz

65

Piękna Zupa obsługuje konwersję bytu. W Beautiful Soup 3 musisz podać convertEntitiesargument BeautifulSoupkonstruktora (zobacz sekcję „Konwersja encji” zarchiwizowanych dokumentów). W Beautiful Soup 4 jednostki są dekodowane automatycznie.

Piękna zupa 3

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

Piękna zupa 4

>>> from bs4 import BeautifulSoup
>>> BeautifulSoup("<p>&pound;682m</p>")
<html><body><p682m</p></body></html>

+1. Nie mam pojęcia, jak tęskniłem za tym w dokumentacji: dzięki za informację. Przyjmuję odpowiedź Luca, ponieważ używa on standardowej biblioteki lib, którą określiłem w pytaniu (nie jest to dla mnie ważne) i prawdopodobnie ma ona bardziej ogólne zastosowanie dla innych ludzi.
jkp

5
BeautifulSoup4używa HTMLParsergłównie. Zobacz źródło
scharfmn

4
Jak uzyskać konwersję w Beautiful Soup 4 bez całego obcego kodu HTML, który nie był częścią oryginalnego ciągu? (tj. <html> i <body>)
Praxiteles

@Praxiteles: BeautifulSoup („& pound; 682m”, „html.parser”) stackoverflow.com/a/14822344/4376342
Soitje 20.04.18

13

Możesz użyć replace_entities z biblioteki 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 pozwala ustawić formatyzator na wyjściu

Jeśli przejdziesz formatter=None, Piękna Zupa w ogóle nie zmodyfikuje napisów na wyjściu. Jest to najszybsza opcja, ale może prowadzić do generowania nieprawidłowej HTML / XML przez Beautiful Soup, jak w poniższych przykładach:

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>

To nie odpowiada na pytanie. (Poza tym nie mam pojęcia, co mówią doktryny, że tutaj jest ostatni fragment HTML).
Mark Amery

<< Sacré bleu! >> jest niepoprawną częścią, ponieważ odskoczyła <i> i złamie otaczający ją HTML. Wiem, że to ode mnie późny post, ale na wypadek, gdyby ktoś się rozglądał i zastanawiał ...
GMasucci,

0

Miałem podobny problem z kodowaniem. Użyłem metody normalize (). Podczas eksportowania ramki danych do pliku .html w innym katalogu otrzymywałem błąd Unicode przy użyciu metody pandas .to_html (). Skończyło się na tym i to zadziałało ...

    import unicodedata 

Obiektem ramki danych może być dowolny obiekt, nazwijmy go tabelą ...

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

koduj dane tabeli, abyśmy mogli je wyeksportować do pliku .html w folderze szablonów (może to być dowolna lokalizacja :))

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

eksport znormalizowanego ciągu do pliku HTML

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

    file.write(html_data) 

    file.close() 

Odniesienie: dokumentacja Unicodedata


-4

Prawdopodobnie nie ma to tutaj znaczenia. Ale aby wyeliminować te wpisy HTML z całego dokumentu, możesz zrobić coś takiego: (Załóżmy, że dokument = strona i proszę wybaczyć niechlujny kod, ale jeśli masz pomysły, jak to poprawić, jestem cały uszu - jestem nowy w to).

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
Nie! Nie musisz samodzielnie dopasowywać jednostek HTML i zapętlać je; .unescape()robi to dla ciebie . Nie rozumiem, dlaczego ty i Rob opublikowaliście te skomplikowane rozwiązania, które rzucają własnymi dopasowaniami do encji, gdy zaakceptowana odpowiedź już jasno pokazuje, że .unescape()można znaleźć encje w ciągu.
Mark Amery
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.