18

Próbuję odszyfrować wpisy HTML stąd NYTimes.com i nie mogę określić, co robię źle.Dekodowanie encji HTML za pomocą Pythona

Weźmy na przykład:

"U.S. Adviser’s Blunt Memo on Iraq: Time ‘to Go Home’" 

Próbowałem BeautifulSoup, dekodowania ('iso-8859-1'), a smart_str django.utils.encoding bez jakiegokolwiek sukcesu.

+0

To pytanie wydaje się być bardzo popularne bez dobrego rozwiązania. Sprawia, że ​​chcę napisać coś własnego ... – Triptych

+0

Ha Myślę, że to najlepsze rozwiązanie, jakie do tej pory znalazłem. Właściwie mógłbym spróbować to zrobić sam. Jeśli to zrobię, opublikuję moje rozwiązanie. – KeyboardInterrupt

+0

@ Triptych: istnieje ['unescape()'] (http://stackoverflow.com/a/20715131/4279). – jfs

Odpowiedz

6

Spróbuj tego:

import re 

def _callback(matches): 
    id = matches.group(1) 
    try: 
     return unichr(int(id)) 
    except: 
     return id 

def decode_unicode_references(data): 
    return re.sub("&#(\d+)(;|(?=\s))", _callback, data) 

data = "U.S. Adviser’s Blunt Memo on Iraq: Time ‘to Go Home’" 
print decode_unicode_references(data) 
+0

UnicodeEncodeError: Kodek 'charmap' nie może kodować znaków u '\ u2019' na pozycji 12: mapy znaków do To wydaje się być błąd, który otrzymuję niezależnie od tego, co próbuję. – KeyboardInterrupt

+0

Czy możesz podać więcej kodu? Po prostu wypróbowałem to z funkcją, którą napisałem, a postać 2019 działa dobrze. Pojawia się jako: ߣ –

+0

Kilka pytań na temat regexp: (1) Czy nie powinno to być \ d zamiast \ w? Wyrażenie regularne będzie pasować do ' ' i ' ', ale następnie ulegnie awarii w int() (2) Umożliwienie odwołanie się do znaku (to NIE byt) do zakończenia w odstępach zamiast ";" wydaje się bardzo tolerancyjny - czy nie możesz o tym wspomnieć? (3) Czy ostatnia część nie byłaby lepiej napisana jako [; \ s]? –

18

to działa:

from BeautifulSoup import BeautifulStoneSoup 
s = "U.S. Adviser’s Blunt Memo on Iraq: Time ‘to Go Home’" 
decoded = BeautifulStoneSoup(s, convertEntities=BeautifulStoneSoup.HTML_ENTITIES) 

Jeśli chcesz ciąg zamiast obiektu Unicode, trzeba rozszyfrować go do kodowania, który obsługuje używane postacie; ISO-8859-1 nie:

result = decoded.encode("UTF-8") 

To niefortunne, że potrzebujesz modułu zewnętrznego do czegoś takiego; proste dekodowanie obiektu HTML/XML powinno znajdować się w standardowej bibliotece i nie wymagać od mnie korzystania z biblioteki o pozbawionych znaczenia nazwach takich jak "BeautifulStoneSoup". (Nazwy klas i funkcji nie powinny być "kreatywne", powinny być znaczące.)

+2

lxml, niestety również nie w standardowej bibliotece, udostępnia także parser Beautiful Soup (i wiele więcej) z nieco mniej "kreatywnymi" nazwami. –

+1

Obsługa dekodowania encji znajduje się w standardowej bibliotece (module htmlentitydefs). To, co OP ma (dziesiętne), to numeryczne odniesienia do znaków, a nie encje. –

+0

Działa również z BeautifulSoup zamiast BeautifulStoneSoup - o krok mniej "kreatywny" :) –

20

W rzeczywistości to, co masz, nie jest elementami HTML. Istnieją TRZY odmiany tych & .....; rzeczy - na przykład       wszystkie średnie U + 00A0 NO-BREAK SPACE.

  (Twój typ) to "numeryczne odwołanie do znaku" (dziesiętnie).
  to "numeryczne odniesienie znaków" (szesnastkowo).
  to obiekt.

Dalsze czytanie: http://htmlhelp.com/reference/html40/entities/

Tutaj znajdziesz kod Python2.x że nie wszystkie trzy w jednym skanie przez wejście: http://effbot.org/zone/re-sub.htm#unescape-html

+0

+1 za link do effbot.org, bardzo cenne! –

16
>>> from HTMLParser import HTMLParser 
>>> print HTMLParser().unescape('U.S. Adviser’s Blunt Memo on Iraq: ' 
...        'Time ‘to Go Home’') 
U.S. Adviser’s Blunt Memo on Iraq: Time ‘to Go Home’ 

Funkcja jest nieudokumentowane w Pythonie 2. It is fixed in Python 3.4+: jest wyeksponowany jako html.unescape() there.

+4

Dla przyszłych użytkowników, ta odpowiedź wydaje się mieć tak mało awansów tylko dlatego, że przyszła 4 lata później niż istniejące odpowiedzi. Wydaje się, że jest to równie dobra odpowiedź. Ta odpowiedź ma tę zaletę, że jest prosta (w przeciwieństwie do pisania własnej funkcji interpretowania standardów HTML za pomocą wyrażeń regularnych) i używa standardowej biblioteki (w przeciwieństwie do BeautifulSoup). Wadą jest wykorzystanie nieudokumentowanej funkcji. –

+0

Uproś te osoby! – Private