Mendekode entitas HTML dalam string Python?

266

Saya mem-parsing beberapa HTML dengan Beautiful Soup 3, tetapi itu berisi entitas HTML yang Beautiful Soup 3 tidak dapat memecahkan kode untuk saya:

>>> from BeautifulSoup import BeautifulSoup

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

>>> print text
&pound;682m

Bagaimana saya bisa mendekode entitas HTML textuntuk mendapatkan "£682m"alih-alih "&pound;682m".

jkp
sumber

Jawaban:

521

Python 3.4+

Gunakan html.unescape():

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

FYI html.parser.HTMLParser.unescapesudah usang, dan seharusnya dihapus dalam 3,5 , meskipun itu ditinggalkan karena kesalahan. Itu akan segera dihapus dari bahasa.


Python 2.6-3.3

Anda dapat menggunakan HTMLParser.unescape()dari perpustakaan standar:

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

Anda juga dapat menggunakan sixperpustakaan kompatibilitas untuk menyederhanakan impor:

>>> from six.moves.html_parser import HTMLParser
>>> h = HTMLParser()
>>> print(h.unescape('&pound;682m'))
£682m
luc
sumber
9
metode ini sepertinya tidak lepas dari karakter seperti "& # 8217;" di mesin app google, meskipun bekerja secara lokal di python2.6. Itu masih memecahkan kode entitas (seperti & quot;) setidaknya
gfxmonk
Bagaimana API yang tidak terdokumentasi tidak digunakan lagi? Diedit jawabannya.
Markus Unterwaditzer
@MarkusUnterwaditzer tidak ada alasan bahwa metode tidak terdokumentasi tidak dapat dihentikan. Yang ini melempar peringatan penghentian - lihat edit saya untuk jawabannya.
Mark Amery
Akan tampak lebih logis bahwa, daripada hanya unescapemetode, seluruh HTMLParsermodul tidak digunakan lagi html.parser.
Tom Russell
Patut dicatat untuk Python 2: Karakter khusus diganti dengan rekan penyandian Latin-1 (ISO-8859-1) mereka. Misalnya, mungkin perlu h.unescape(s).encode("utf-8"). Dokumen: "" "Definisi yang diberikan di sini berisi semua entitas yang didefinisikan oleh XHTML 1.0 yang dapat ditangani menggunakan substitusi teks sederhana dalam set karakter Latin-1 (ISO-8859-1)" ""
pengecut anonim
65

Beautiful Soup menangani konversi entitas. Di Beautiful Soup 3, Anda harus menentukan convertEntitiesargumen untuk BeautifulSoupkonstruktor (lihat bagian 'Konversi Entitas' dari dokumen yang diarsipkan). Di Beautiful Soup 4, entitas diterjemahkan secara otomatis.

Sup Cantik 3

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

Sup Cantik 4

>>> from bs4 import BeautifulSoup
>>> BeautifulSoup("<p>&pound;682m</p>")
<html><body><p682m</p></body></html>
Ben James
sumber
+1. Tidak tahu bagaimana saya melewatkan ini di dokumen: terima kasih atas informasinya. Saya akan menerima jawaban luc tho karena dia menggunakan lib standar yang saya sebutkan dalam pertanyaan (tidak penting bagi saya) dan mungkin lebih umum digunakan untuk orang lain.
jkp
5
BeautifulSoup4menggunakan HTMLParser, sebagian besar. Lihat sumber
scharfmn
4
Bagaimana kita mendapatkan konversi dalam Beautiful Soup 4 tanpa semua HTML asing yang bukan bagian dari string asli? (yaitu <html> dan <body>)
Praxiteles
@Praxiteles: BeautifulSoup ('& pound; 682m', "html.parser") stackoverflow.com/a/14822344/4376342
Soitje
13

Anda dapat menggunakan replace_entities dari pustaka 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
sumber
2

Beautiful Soup 4 memungkinkan Anda untuk mengatur formatter ke output Anda

Jika Anda lewat formatter=None, Beautiful Soup tidak akan mengubah string sama sekali pada output. Ini adalah opsi tercepat, tetapi mungkin menyebabkan Beautiful Soup menghasilkan HTML / XML yang tidak valid, seperti dalam contoh berikut:

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
sumber
Ini tidak menjawab pertanyaan. (Juga, saya tidak tahu apa yang dikatakan dokumen tidak valid tentang bagian terakhir dari HTML di sini.)
Mark Amery
<< Sacré bleu! >> adalah bagian yang tidak valid, karena telah dihapus <dan> dan akan memecah html di sekitarnya. Saya tahu ini adalah posting terakhir dari saya, tetapi kalau-kalau ada yang kebetulan mencari dan bertanya-tanya ...
GMasucci
0

Saya memiliki masalah penyandian yang serupa. Saya menggunakan metode normalize (). Saya mendapatkan kesalahan Unicode menggunakan metode panda .to_html () saat mengekspor bingkai data saya ke file .html di direktori lain. Saya akhirnya melakukan ini dan berhasil ...

    import unicodedata 

Objek dataframe dapat berupa apa pun yang Anda suka, sebut saja tabel ...

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

menyandikan data tabel sehingga kami dapat mengekspornya ke file .html di folder templat (ini bisa berupa lokasi apa pun yang Anda inginkan :))

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

ekspor string yang dinormalisasi ke file html

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

    file.write(html_data) 

    file.close() 

Referensi: dokumentasi unicodedata

Alex
sumber
-4

Ini mungkin tidak relevan di sini. Tetapi untuk menghilangkan html ini dari seluruh dokumen, Anda dapat melakukan sesuatu seperti ini: (Asumsikan dokumen = halaman dan tolong maafkan kode yang ceroboh, tetapi jika Anda memiliki ide bagaimana membuatnya lebih baik, saya ingin tahu - saya baru saja ini).

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
Neil Aggarwal
sumber
7
Tidak! Anda tidak perlu mencocokkan entitas HTML sendiri dan memutarnya; .unescape()melakukan itu untukmu . Saya tidak mengerti mengapa Anda dan Rob memposting solusi rumit yang menggulung pencocokan entitas mereka sendiri ketika jawaban yang diterima sudah menunjukkan dengan jelas yang .unescape()dapat menemukan entitas dalam string.
Mark Amery