Giải mã các thực thể HTML trong chuỗi Python?


266

Tôi đang phân tích một số HTML bằng Beautiful Soup 3, nhưng nó chứa các thực thể HTML mà Beautiful Soup 3 không tự động giải mã cho tôi:

>>> from BeautifulSoup import BeautifulSoup

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

>>> print text
&pound;682m

Làm cách nào tôi có thể giải mã các thực thể HTML textđể nhận "£682m"thay thế "&pound;682m".


Câu trả lời:


521

Python 3,4+

Sử dụng html.unescape():

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

FYI html.parser.HTMLParser.unescapekhông được chấp nhận và được cho là sẽ bị xóa trong 3.5 , mặc dù nó bị bỏ lại do nhầm lẫn. Nó sẽ bị xóa khỏi ngôn ngữ sớm.


Python 2.6-3.3

Bạn có thể sử dụng HTMLParser.unescape()từ thư viện tiêu chuẩn:

  • Đối với Python 2.6-2.7, nó nằm trong HTMLParser
  • Đối với Python 3, nó nằm trong 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

Bạn cũng có thể sử dụng sixthư viện tương thích để đơn giản hóa việc nhập:

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

9
phương pháp này dường như không thoát khỏi các ký tự như "& # 8217;" trên công cụ ứng dụng google, mặc dù nó hoạt động cục bộ trên python2.6. Nó vẫn giải mã các thực thể (như & quot;) ít nhất
gfxmonk

Làm thế nào một API không có giấy tờ có thể bị phản đối? Chỉnh sửa câu trả lời.
Markus Unterwaditzer

@MarkusUnterwaditzer không có lý do gì mà một phương pháp không có giấy tờ không thể bị phản đối. Điều này ném cảnh báo phản đối - xem chỉnh sửa của tôi để trả lời.
Đánh dấu Amery

Có vẻ hợp lý hơn, thay vì chỉ là unescapephương thức, toàn bộ HTMLParsermô-đun đã không được ủng hộ html.parser.
Tom Russell

Đáng chú ý cho Python 2: Các ký tự đặc biệt được thay thế bằng các bản sao mã hóa Latin-1 (ISO-8859-1) của chúng. Ví dụ, nó có thể là cần thiết để h.unescape(s).encode("utf-8"). Các tài liệu: "" "Định nghĩa được cung cấp ở đây chứa tất cả các thực thể được xác định bởi XHTML 1.0 có thể được xử lý bằng cách sử dụng thay thế văn bản đơn giản trong bộ ký tự Latin-1 (ISO-8859-1)" ""
kẻ hèn nhát ẩn danh

65

Soup đẹp xử lý chuyển đổi thực thể. Trong Beautiful Soup 3, bạn sẽ cần chỉ định convertEntitiesđối số cho hàm BeautifulSouptạo (xem phần 'Chuyển đổi thực thể' trong các tài liệu được lưu trữ). Trong Beautiful Soup 4, các thực thể được giải mã tự động.

Súp đẹp 3

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

Súp đẹp 4

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

+1. Không biết làm thế nào tôi bỏ lỡ điều này trong các tài liệu: cảm ơn về thông tin. Tôi sẽ chấp nhận câu trả lời của luc vì anh ấy sử dụng lib tiêu chuẩn mà tôi đã chỉ định trong câu hỏi (không quan trọng đối với tôi) và có lẽ nó được sử dụng chung hơn cho người khác.
jkp

5
BeautifulSoup4sử dụng HTMLParser, chủ yếu. Xem nguồn
scharfmn 3/03/2015

4
Làm cách nào để chúng tôi có được chuyển đổi trong Beautiful Soup 4 mà không cần tất cả các HTML bên ngoài không phải là một phần của chuỗi gốc? (tức là <html> và <body>)
Praxiteles

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

13

Bạn có thể sử dụng thay thế từ thư viện 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 cho phép bạn đặt một bộ định dạng cho đầu ra của bạn

Nếu bạn chuyển vào formatter=None, Beautiful Soup sẽ không sửa đổi chuỗi nào ở đầu ra. Đây là tùy chọn nhanh nhất, nhưng nó có thể dẫn đến Beautiful Soup tạo HTML / XML không hợp lệ, như trong các ví dụ sau:

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>

Điều này không trả lời câu hỏi. (Ngoài ra, tôi không biết các tài liệu đang nói gì không hợp lệ về bit cuối cùng của HTML ở đây.)
Mark Amery

<< Sacré bleu! >> là phần không hợp lệ, vì nó không được giải phóng <và> và sẽ phá vỡ html xung quanh nó. Tôi biết đây là một bài viết muộn của tôi, nhưng trong trường hợp bất cứ ai tình
cờ

0

Tôi đã có một vấn đề mã hóa tương tự. Tôi đã sử dụng phương thức normalize (). Tôi đã gặp lỗi Unicode khi sử dụng phương thức pandas .to_html () khi xuất khung dữ liệu của mình sang tệp .html trong thư mục khác. Tôi đã kết thúc việc này và nó đã làm việc ...

    import unicodedata 

Đối tượng dataframe có thể là bất cứ thứ gì bạn thích, hãy gọi nó là bảng ...

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

mã hóa dữ liệu bảng để chúng ta có thể xuất nó ra tệp .html trong thư mục mẫu (đây có thể là bất kỳ vị trí nào bạn muốn :))

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

xuất chuỗi chuẩn hóa sang tệp html

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

    file.write(html_data) 

    file.close() 

Tham khảo: tài liệu unicodingata


-4

Điều này có lẽ không liên quan ở đây. Nhưng để loại bỏ các lệnh html này khỏi toàn bộ tài liệu, bạn có thể làm một cái gì đó như thế này: (Giả sử tài liệu = trang và xin vui lòng tha thứ cho mã cẩu thả, nhưng nếu bạn có ý tưởng làm thế nào để làm cho nó tốt hơn, tôi mới biết điều này).

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
Không! Bạn không cần phải tự khớp các thực thể HTML và lặp lại chúng; .unescape()nào đó cho bạn . Tôi không hiểu lý do tại sao bạn và Rob đã đăng các giải pháp quá phức tạp này để khớp với thực thể của chính họ khi câu trả lời được chấp nhận cho thấy rõ ràng .unescape()có thể tìm thấy các thực thể trong chuỗi.
Đánh dấu Amery
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.