Piękna zupa - kodowanie

Wszystkie dokumenty HTML lub XML są zapisywane w określonym kodowaniu, takim jak ASCII lub UTF-8. Jednak po załadowaniu tego dokumentu HTML / XML do BeautifulSoup został on przekonwertowany na Unicode.

>>> markup = "<p>I will display £</p>"
>>> Bsoup = BeautifulSoup(markup)
>>> Bsoup.p
<p>I will display £</p>
>>> Bsoup.p.string
'I will display £'

Powyższe zachowanie wynika z tego, że BeautifulSoup wewnętrznie używa podbiblioteki o nazwie Unicode, Dammit do wykrywania kodowania dokumentu, a następnie konwertuje go na Unicode.

Jednak nie zawsze, Unicode, Dammit odgaduje poprawnie. Ponieważ dokument jest przeszukiwany bajt po bajcie, aby odgadnąć kodowanie, zajmuje to dużo czasu. Możesz zaoszczędzić trochę czasu i uniknąć błędów, jeśli znasz już kodowanie, przekazując je do konstruktora BeautifulSoup jako from_encoding.

Poniżej znajduje się przykład, w którym BeautifulSoup błędnie identyfikuje dokument ISO-8859-8 jako ISO-8859-7 -

>>> markup = b"<h1>\xed\xe5\xec\xf9</h1>"
>>> soup = BeautifulSoup(markup)
>>> soup.h1
<h1>νεμω</h1>
>>> soup.original_encoding
'ISO-8859-7'
>>>

Aby rozwiązać powyższy problem, przekaż go do BeautifulSoup za pomocą from_encoding -

>>> soup = BeautifulSoup(markup, from_encoding="iso-8859-8")
>>> soup.h1
<h1>ולש </h1>
>>> soup.original_encoding
'iso-8859-8'
>>>

Kolejną nową funkcją dodaną z BeautifulSoup 4.4.0 jest exclude_encoding. Można go użyć, gdy nie znasz prawidłowego kodowania, ale jesteś pewien, że Unicode, Cholera pokazuje zły wynik.

>>> soup = BeautifulSoup(markup, exclude_encodings=["ISO-8859-7"])

Kodowanie wyjściowe

Dane wyjściowe z BeautifulSoup to dokument UTF-8, niezależnie od dokumentu wprowadzonego do BeautifulSoup. Poniżej dokument, w którym znajdują się polskie znaki w formacie ISO-8859-2.

html_markup = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-2">
</HEAD>
<BODY>
ą ć ę ł ń ó ś ź ż Ą Ć Ę Ł Ń Ó Ś Ź Ż
</BODY>
</HTML>
"""


>>> soup = BeautifulSoup(html_markup)
>>> print(soup.prettify())
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
   <head>
      <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
   </head>
   <body>
      ą ć ę ł ń ó ś ź ż Ą Ć Ę Ł Ń Ó Ś Ź Ż
   </body>
</html>

W powyższym przykładzie, jeśli zauważysz, tag <meta> został przepisany, aby odzwierciedlić wygenerowany dokument z BeautifulSoup jest teraz w formacie UTF-8.

Jeśli nie chcesz generować danych wyjściowych w UTF-8, możesz przypisać żądane kodowanie w prettify ().

>>> print(soup.prettify("latin-1"))
b'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n<html>\n <head>\n <meta content="text/html; charset=latin-1" http-equiv="content-type"/>\n </head>\n <body>\n ą ć ę ł ń \xf3 ś ź ż Ą Ć Ę Ł Ń \xd3 Ś Ź Ż\n </body>\n</html>\n'

W powyższym przykładzie zakodowaliśmy cały dokument, jednak możesz zakodować dowolny element w zupie tak, jakby był ciągiem znaków Pythona -

>>> soup.p.encode("latin-1")
b'<p>0My first paragraph.</p>'
>>> soup.h1.encode("latin-1")
b'<h1>My First Heading</h1>'

Wszelkie znaki, których nie można przedstawić w wybranym kodowaniu, zostaną przekonwertowane na numeryczne odniesienia do encji XML. Poniżej znajduje się jeden taki przykład -

>>> markup = u"<b>\N{SNOWMAN}</b>"
>>> snowman_soup = BeautifulSoup(markup)
>>> tag = snowman_soup.b
>>> print(tag.encode("utf-8"))
b'<b>\xe2\x98\x83</b>'

Jeśli spróbujesz zakodować powyższe w „latin-1” lub „ascii”, wygeneruje „☃”, co oznacza, że ​​nie ma dla tego reprezentacji.

>>> print (tag.encode("latin-1"))
b'<b>☃</b>'
>>> print (tag.encode("ascii"))
b'<b>☃</b>'

Unicode, cholera

Unicode, Dammit jest używany głównie wtedy, gdy przychodzący dokument jest w nieznanym formacie (głównie w języku obcym) i chcemy zakodować w jakimś znanym formacie (Unicode), a także nie potrzebujemy do tego Beautifulsoup.