Python文字列のHTMLエンティティをデコードしますか?


266

Beautiful Soup 3でHTMLを解析していますが、Beautiful Soup 3が自動的にデコードしないHTMLエンティティが含まれています。

>>> 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()標準ライブラリから使用できます:

>>> 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;」のような文字をエスケープしないようです。グーグルアプリエンジンでは、Python2.6でローカルに動作します。少なくとも(&quot;のような)エンティティは依然としてデコードされます
gfxmonk

ドキュメントに記載されていないAPIを非推奨にするにはどうすればよいですか?回答を編集しました。
Markus Unterwaditzer 2015年

@MarkusUnterwaditzerドキュメント化されていないメソッドを非推奨にすることができる理由はありません。これは非推奨の警告をスローします-回答の編集を参照してください。
Mark Amery 2015年

unescapeメソッドだけでなく、HTMLParserモジュール全体がの代わりに廃止された方がより論理的に思えますhtml.parser
Tom Russell、

Python 2の注意点:特殊文字は、Latin-1(ISO-8859-1)エンコーディングの対応する文字に置き換えられます。たとえば、が必要になる場合がありh.unescape(s).encode("utf-8")ます。ドキュメント: "" "ここで提供される定義には、Latin-1文字セット(ISO-8859-1)の単純なテキスト置換を使用して処理できるXHTML 1.0で定義されたすべてのエンティティが含まれます" "
匿名の臆病者

65

Beautiful Soupはエンティティ変換を処理します。Beautiful Soup 3ではconvertEntitiesBeautifulSoupコンストラクターへの引数を指定する必要があります(アーカイブされたドキュメントの「エンティティ変換」セクションを参照してください)。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。私がドキュメントでこれをどのように逃したかはわかりません:情報に感謝します。彼が質問で指定した標準のlibを使用しているので(私には重要ではありません)、lucの回答を受け入れます。
jkp

5
BeautifulSoup4HTMLParser主に使用します。ソースを
scharfmn 2015

4
元の文字列の一部ではなかった無関係なHTMLをすべて使用せずに、Beautiful Soup 4で変換を取得するにはどうすればよいですか?(つまり、<html>および<body>)
Praxiteles 2017年

@Praxiteles:BeautifulSoup( '&pound; 682m'、 "html.parser")stackoverflow.com/a/14822344/4376342
Soitje

13

w3lib.htmlライブラリのreplace_entitiesを使用できます

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は出力時に文字列をまったく変更しません。これは最も速いオプションですが、次の例のように、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!>>は、エスケープされていない<および>であり、その周りのHTMLを壊すため、無効な部分です。私はこれが私からの遅い投稿であることを知っていますが、万が一誰かが偶然見ていて不思議に思っている場合のために...
GMasucci

0

同様のエンコードの問題がありました。normalize()メソッドを使用しました。データフレームを別のディレクトリの.htmlファイルにエクスポートすると、pandas .to_html()メソッドを使用してUnicodeエラーが発生しました。私はこれをやってしまい、うまくいきました...

    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()が文字列内のエンティティを見つけることができることをすでに明確に示しているのに、あなたとロブが独自のエンティティマッチングをロールするこれらの複雑すぎるソリューションを投稿した理由がわかりません。
Mark Amery、2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.