Search on blog:

Python: Dlaczego `requests` niepoprawnie dekoduje tekst zamiast użyć UTF-8

Czasami requests niepoprawnie dekoduje tekst w response.text - używa ISO-8859-1 (Latin-1) zamiast UTF-8 nawet jeśli w HTML jest <meta charset="uft-8"> lub <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">.

Można to zobaczyć w response.headers['content-type'] oraz response.encoding

Problem jest ponieważ on nie używa <meta> ale nagłówka Content-Type, który zwykle ma wartość text/html; charset=UTF-8 (HTML5) ale czasami jakiś server wysyła tylko text/html a domyślne kodowanie dla takiej wartości jest ISO-8859-1 (HTML4)

Na szczęście on także używa chardet aby rozpoznać kodowanie w tekście i zapisuje to w response.apparent_encoding więc można zrobić:

print(response.content.decode(response.apparent_encoding))

lub

response.encoding = response.apparent_encoding

print(response.text)

Przykładowy kod

import requests
import lxml.html
import chardet

r = requests.get('https://travel.rakuten.co.jp/')

print('content-type:', r.headers['content-type'])
print('encoding:', r.encoding)
print('apparent:', r.apparent_encoding)
print('chardet :', chardet.detect(r.content) )

# wrong result
html = r.text
tree = lxml.html.fromstring(html)
result = tree.xpath('//*[@id="rt-nav-box"]/li[1]/a')[0]
print('1:', result.text)

# correct result
detected_encoding = chardet.detect(r.content)['encoding']
html = r.content.decode(detected_encoding)
tree = lxml.html.fromstring(html)
result = tree.xpath('//*[@id="rt-nav-box"]/li[1]/a')[0]
print('2:', result.text)

# correct result
html = r.content.decode(r.apparent_encoding)
tree = lxml.html.fromstring(html)
result = tree.xpath('//*[@id="rt-nav-box"]/li[1]/a')[0]
print('3:', result.text)

# correct result
r.encoding = r.apparent_encoding
html = r.text
tree = lxml.html.fromstring(html)
result = tree.xpath('//*[@id="rt-nav-box"]/li[1]/a')[0]
print('4:', result.text)

Result:

encoding: ISO-8859-1
apparent: utf-8
chardet : {'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}
1: 国内旅行
2: 国内旅行
3: 国内旅行
4: 国内旅行
If you like it
Buy a Coffee