ถอดรหัสเอนทิตี 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 app แม้ว่ามันจะทำงานได้ในเครื่องบน python2.6 มันยังคงถอดรหัสเอนทิตี (เช่น & quot;) อย่างน้อย
gfxmonk

API ที่ไม่มีเอกสารสามารถเลิกใช้อย่างไร แก้ไขคำตอบ
Markus Unterwaditzer

@MarkusUnterwaditzer ไม่มีเหตุผลว่าวิธีการที่ไม่มีเอกสารไม่สามารถคัดค้านได้ อันนี้โยนคำเตือนการคัดค้าน - ดูการแก้ไขคำตอบของฉัน
Mark Amery

มันจะดูเหมือนตรรกะมากขึ้นนั้นมากกว่าแค่unescapeวิธีการทั้งโมดูลเลิกในความโปรดปรานของHTMLParser html.parser
Tom Russell

น่าสังเกตสำหรับ Python 2: อักขระพิเศษจะถูกแทนที่ด้วย Latin-1 (ISO-8859-1) ของพวกเขาเข้ารหัสคู่ h.unescape(s).encode("utf-8")เช่นมันอาจจะเป็นสิ่งที่จำเป็นเพื่อ เอกสาร: "" "คำจำกัดความที่ให้ไว้ที่นี่มีเอนทิตีทั้งหมดที่กำหนดโดย XHTML 1.0 ที่สามารถจัดการได้โดยใช้การแทนที่ข้อความแบบง่ายในชุดอักขระละติน -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 ไม่ทราบว่าฉันพลาดสิ่งนี้ในเอกสารได้อย่างไร: ขอบคุณสำหรับข้อมูล ฉันจะยอมรับคำตอบของ luc เพราะเขาใช้ lib มาตรฐานที่ฉันระบุไว้ในคำถาม
jkp

5
BeautifulSoup4ใช้HTMLParserส่วนใหญ่ ดูแหล่งที่มา
scharfmn

4
เราจะได้รับการแปลงใน Beautiful Soup 4 โดยไม่ใช้ HTML ที่ไม่เกี่ยวข้องทั้งหมดที่ไม่ได้เป็นส่วนหนึ่งของสตริงต้นฉบับได้อย่างไร (เช่น <html> และ <body>)
Praxiteles

@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

2

Beautiful Soup 4 ให้คุณตั้งค่าฟอร์แมตเตอร์เป็นเอาต์พุตของคุณ

หากคุณส่งผ่านformatter=NoneBeautiful 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>

สิ่งนี้ไม่ตอบคำถาม (นอกจากนี้ฉันไม่ทราบว่าเอกสารที่พูดนั้นไม่ถูกต้องเกี่ยวกับบิตสุดท้ายของ HTML ที่นี่)
Mark Amery

<< Sacré Bleu! >> เป็นส่วนที่ไม่ถูกต้องเนื่องจากมันไม่ได้ใช้ Escape <และ> และจะทำลาย HTML รอบ ๆ มัน ฉันรู้ว่านี่เป็นโพสต์ที่ล่าช้าจากฉัน แต่ในกรณีที่มีใครบางคนกำลังมองหาและสงสัย ...
GMasucci

0

ฉันมีปัญหาการเข้ารหัสคล้ายกัน ฉันใช้วิธี normalize () ฉันได้รับข้อผิดพลาด Unicode โดยใช้วิธีการ pandas .to_html () เมื่อส่งออก data frame ไปยังไฟล์. 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() 

การอ้างอิง: เอกสารที่ไม่มีการเข้ารหัส


-4

นี่อาจจะไม่เกี่ยวข้องที่นี่ แต่หากต้องการกำจัด html เหล่านี้จากเอกสารทั้งหมดคุณสามารถทำสิ่งนี้: (สมมติว่า document = หน้าและโปรดยกโทษให้รหัสเลอะเทอะ แต่ถ้าคุณมีความคิดเกี่ยวกับวิธีที่จะทำให้ดีขึ้น Im all ears - Im new 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
No! คุณไม่จำเป็นต้องจับคู่เอนทิตี HTML ด้วยตนเองและวนซ้ำไปมา .unescape()ไม่ว่าสำหรับคุณ ฉันไม่เข้าใจว่าทำไมคุณและ Rob จึงได้โพสต์โซลูชั่นที่ซับซ้อนเหล่านี้ซึ่งจะจับคู่เอนทิตีของตัวเองเมื่อคำตอบที่ยอมรับแล้วแสดงให้เห็นชัดเจนว่า.unescape()สามารถค้นหาเอนทิตีในสตริงได้
Mark Amery
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.