Requests: Response.textκ°€ λΆ€μ μ ˆν•˜κ²Œ λ””μ½”λ”©λœ ν…μŠ€νŠΈλ₯Ό λ°˜ν™˜ν•¨(μš”μ²­ 1.2.3, python 2.7)

에 λ§Œλ“  2013λ…„ 09μ›” 15일  Β·  24μ½”λ©˜νŠΈ  Β·  좜처: psf/requests

http μ„œλ²„κ°€ 인코딩 없이 Content-type: text/*λ₯Ό λ°˜ν™˜ν•˜λ©΄ Response.textλŠ” 항상 'ISO-8859-1' ν…μŠ€νŠΈλ‘œ λ””μ½”λ”©ν•©λ‹ˆλ‹€.

RFC2616/3.7.1μ—μ„œλŠ” μœ νš¨ν•  수 μžˆμ§€λ§Œ 2013λ…„μ—λŠ” μ‹€μƒν™œμ—μ„œ 잘λͺ»λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

쀑ꡭ어 ν…μŠ€νŠΈλ‘œ 예제 νŽ˜μ΄μ§€λ₯Ό λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.
http://lavr.github.io/python-emails/tests/requests/some-utf8-text.html
λͺ¨λ“  λΈŒλΌμš°μ €λŠ” 이 νŽ˜μ΄μ§€λ₯Ό μ˜¬λ°”λ₯΄κ²Œ λ Œλ”λ§ν•©λ‹ˆλ‹€.
κ·ΈλŸ¬λ‚˜ reguests.get은 잘λͺ»λœ ν…μŠ€νŠΈλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

λ‹€μŒμ€ ν•΄λ‹Ή URL을 μ‚¬μš©ν•œ κ°„λ‹¨ν•œ ν…ŒμŠ€νŠΈμž…λ‹ˆλ‹€.
https://gist.github.com/lavr/6572927

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

@lavr (/cc @sigmavirus24), 그보닀 훨씬 더 μ‰½κ²Œ 인코딩을 직접 μ œκ³΅ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

>>> r = requests.get('http://irresponsible-server/')
>>> r.encoding = 'utf-8'

그런 λ‹€μŒ μ •μƒμ μœΌλ‘œ μ§„ν–‰ν•˜μ‹­μ‹œμ˜€.

λͺ¨λ“  24 λŒ“κΈ€

@lavrλ‹˜ κ°μ‚¬ν•©λ‹ˆλ‹€!

이것은 μš”μ²­μ— λŒ€ν•œ μ˜λ„μ μΈ λ””μžμΈ κ²°μ •μž…λ‹ˆλ‹€. 사양이 μ‹€μ œ λ™μž‘κ³Ό λ„ˆλ¬΄ 많이 달라 λ¬Έμ œκ°€ λ˜λŠ” μœ„μΉ˜μ— μžˆμ§€ μ•ŠλŠ” ν•œ 사양을 λ”°λ₯΄κ³  μžˆμŠ΅λ‹ˆλ‹€(예: POST에 λŒ€ν•œ 302 응닡 ν›„ GET).

μ—…μŠ€νŠΈλ¦Ό μ„œλ²„κ°€ μ˜¬λ°”λ₯Έ 인코딩이 무엇인지 μ•Œκ³  있으면 μ‹ ν˜Έλ₯Ό 보내야 ν•©λ‹ˆλ‹€. 그렇지 μ•ŠμœΌλ©΄ 사양이 λ§ν•˜λŠ” 것을 λ”°λ₯Ό κ²ƒμž…λ‹ˆλ‹€. =)

사양 기본값이 잘λͺ»λœ 것이라고 μƒκ°ν•œλ‹€λ©΄ 이 기본값을 λ³€κ²½ν•˜κΈ° μœ„ν•΄ HTTP/2.0용 RFC ν”„λ‘œμ„ΈμŠ€μ— μ°Έμ—¬ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€. =)

@LukasaλŠ” + ν—€λ”μ—μ„œ 검색 인코딩이 μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” 경우 μš°λ¦¬κ°€μ— μ˜μ‘΄ν•œλ‹€λŠ” 사싀 λ§ν–ˆλ‹€ 무엇 ν—ˆκ΅¬ 인코딩 μΆ”μΈ‘ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 문자 μˆ˜κ°€ λ„ˆλ¬΄ 적기 λ•Œλ¬Έμ— charadeλŠ” 톡계 데이터λ₯Ό μ‚¬μš©ν•˜μ—¬ μ˜¬λ°”λ₯Έ 인코딩이 무엇인지 μΆ”μΈ‘ ν•˜κΈ° λ•Œλ¬Έμ— ν™•μ‹€ν•œ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ†”μ§νžˆ μ—°λ„λŠ” 차이가 μ—†μœΌλ©° 사양도 λ³€κ²½λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ–΄λ–€ 인코딩을 μ˜ˆμƒν•˜λŠ”μ§€ μ•Œκ³  μžˆλ‹€λ©΄ λ‹€μŒκ³Ό 같이 직접 λ””μ½”λ”©ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

text = str(r.content, '<ENCODING>', errors='replace')

λ‚΄κ°€ μ—Όλ €ν•˜λŠ” ν•œ μš”μ²­μ—λŠ” μ•„λ¬΄λŸ° λ¬Έμ œκ°€ μ—†μœΌλ©° 이것은 μ‚¬κΈ°μ˜ 버그도 μ•„λ‹™λ‹ˆλ‹€. @Lukasa κ°€ μ €μ—κ²Œ λ™μ˜ν•˜λŠ” 것 κ°™μ•„μ„œ 이 글을 λ‹«μŠ΅λ‹ˆλ‹€.

@lavr (/cc @sigmavirus24), 그보닀 훨씬 더 μ‰½κ²Œ 인코딩을 직접 μ œκ³΅ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

>>> r = requests.get('http://irresponsible-server/')
>>> r.encoding = 'utf-8'

그런 λ‹€μŒ μ •μƒμ μœΌλ‘œ μ§„ν–‰ν•˜μ‹­μ‹œμ˜€.

@kennethreitz μ‹€λ§μŠ€λŸ½μŠ΅λ‹ˆλ‹€. μ™œ μš°λ¦¬λŠ” μ‚¬λžŒλ“€μ„ μœ„ν•΄ 그것을 μ‰½κ²Œ λ§Œλ“€κ³  μžˆμŠ΅λ‹ˆκΉŒ? =ν”Ό

μ „μ μœΌλ‘œ :)

주둜 일본 μ›Ήμ‚¬μ΄νŠΈμš©μž…λ‹ˆλ‹€. 그듀은 λͺ¨λ‘ μžμ‹ μ˜ 인코딩에 λŒ€ν•΄ 거짓말을 ν•©λ‹ˆλ‹€.

@sigmavirus24
utils.get_encoding_from_headersλŠ” 항상 'ISO-8859-1'을 λ°˜ν™˜ν•˜κ³  charadeλŠ” 호좜될 κΈ°νšŒκ°€ μ—†λ‹€λŠ” 점에 μœ μ˜ν•˜μ‹­μ‹œμ˜€.
κ·Έλž˜μ„œ λ²„κ·ΈλŠ”: μš°λ¦¬λŠ” charadeκ°€ 인코딩을 μΆ”μΈ‘ν•˜λŠ” 데 μ‚¬μš©λœλ‹€κ³  μ˜ˆμƒν•˜μ§€λ§Œ 그렇지 μ•ŠμŠ΅λ‹ˆλ‹€.

μœ„μ˜ νŒ¨μΉ˜λŠ” 버그λ₯Ό μˆ˜μ •ν•˜μ§€λ§Œ μ—¬μ „νžˆ RFCλ₯Ό λ”°λ¦…λ‹ˆλ‹€.
κ²€ν† ν•΄ λ³΄μ‹œκΈ° λ°”λžλ‹ˆλ‹€.

@lavr μ£„μ†‘ν•©λ‹ˆλ‹€. 이 점을 λͺ…ν™•νžˆ ν•˜μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” 이 κ²½μš°μ— charadeκ°€ 호좜되기λ₯Ό κΈ°λŒ€ν•˜μ§€ _μ•ŠμŠ΅λ‹ˆλ‹€_. RFCλŠ” 맀우 λͺ…ν™•ν•©λ‹ˆλ‹€. 문자 집합을 μ§€μ •ν•˜μ§€ μ•Šκ³  MIME μœ ν˜•μ΄ text/* 인 경우 인코딩은 ISO-8859-1둜 κ°€μ •ν•΄μ•Ό ν•©λ‹ˆλ‹€. 그것은 "μΆ”μΈ‘ν•˜μ§€ λ§ˆμ‹­μ‹œμ˜€"λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€. =)

@lavr : r.encoding λ₯Ό None 둜 μ„€μ •ν•˜λ©΄ μ˜ˆμƒλŒ€λ‘œ μž‘λ™ν•©λ‹ˆλ‹€.

λ˜λŠ” r.encoding = r.apparent_encoding .

더 μ’‹μŠ΅λ‹ˆλ‹€.

r.encoding = None 및 r.encoding = r.apparent_encoding μ„œλ²„ 문자 집합 정보가 μ†μ‹€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
μ„œλ²„ 헀더λ₯Ό μ™„μ „νžˆ λ¬΄μ‹œν•˜λŠ” 것은 쒋은 해결책이 μ•„λ‹ˆλΌκ³  μƒκ°ν•©λ‹ˆλ‹€.

μ˜¬λ°”λ₯Έ μ†”λ£¨μ…˜μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

r = requests.get(...)
params = cgi.parse_header(r.headers.get('content-type'))[0]
server_encoding = ('charset' in params) and params['charset'].strip("'\"") or None
r.encoding = server_encoding or r.apparent_encoding
text = r.text

이상해 λ³΄μ—¬μš” :(

λ˜λŠ” λ‹€μŒμ„ μˆ˜ν–‰ν•˜μ‹­μ‹œμ˜€.

r = requests.get(...)

if r.encoding is None or r.encoding == 'ISO-8859-1':
    r.encoding = r.apparent_encoding

λ‚˜λŠ” κ·Έλ ‡κ²Œ μƒκ°ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€ :)

r.encoding is None 은 μ˜λ―Έκ°€ μ—†μŠ΅λ‹ˆλ‹€. r.encoding은 content-type=text/*에 λŒ€ν•΄ None이 될 수 μ—†κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

r.encoding == 'ISO-8859-1' ...은(λŠ”) 무슨 λœ»μΈκ°€μš”? μ„œλ²„μ—μ„œ charset='ISO-8859-1'을 λ³΄λƒˆκ±°λ‚˜ μ„œλ²„μ—μ„œ charset을 보내지 μ•Šμ•˜μŠ΅λ‹ˆκΉŒ? λ¨Όμ € charset을 μΆ”μΈ‘ν•΄μ„œλŠ” μ•ˆλ©λ‹ˆλ‹€.

@lavr λΉ„ν…μŠ€νŠΈ κΈ°λ°˜μ„ 닀루고 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. λŒ€μ‹  λ‹€μŒ 쑰건을 μ‚¬μš©ν•˜μ—¬ charset κ°€λŠ₯성을 λ°°μ œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

r.encoding == 'ISO-8859-1' and not 'ISO-8859-1' in r.headers.get('Content-Type', '')

@루카사
κΈ€μŽ„, λ‚˜λŠ”μ΄ 해킹을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
그리고 λ™μœ λŸ½κ³Ό μ•„μ‹œμ•„μ˜ λͺ¨λ“  μ‚¬λžŒλ“€μ΄ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ μš”μ²­μ—μ„œ μˆ˜μ •ν•˜λ©΄ μ–΄λ–»κ²Œ λ κΉŒμš”? ;)
μš”μ²­μ΄ charset 없이 응닡에 λŒ€ν•΄ μ •μ§ν•˜κ²Œ enconding=None λ₯Ό μ„€μ •ν•  수 μžˆλ‹€λ©΄ μ–΄λ–»κ²Œ λ κΉŒμš”?

μ—¬λŸ¬ 번 λ…Όμ˜ν•œ κ²ƒμ²˜λŸΌ RequestsλŠ” HTTP 사양을 λ”°λ₯΄κ³  μžˆμŠ΅λ‹ˆλ‹€. ν˜„μž¬μ˜ 행동은 잘λͺ»λœ 것이 μ•„λ‹™λ‹ˆλ‹€. =)

μ‚¬μš© 사둀에 도움이 λ˜μ§€ μ•ŠλŠ”λ‹€λŠ” 사싀은 μ™„μ „νžˆ λ‹€λ₯Έ μ΄μ•ΌκΈ°μž…λ‹ˆλ‹€. =)

μ’‹μ•„μš”, μ΄κ²ƒμœΌλ‘œ μΆ©λΆ„ν•œ λ…Όμ˜κ°€ μžˆμŠ΅λ‹ˆλ‹€. ν”Όλ“œλ°±μ„ μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€.

μ—…λ°μ΄νŠΈλœ HTTP 1.1은 ISO-8859-1 κΈ°λ³Έ 문자 집합을 μ‚¬μš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. http://tools.ietf.org/html/rfc7231#appendix -B

μš°λ¦¬λŠ” 이미 #2086μ—μ„œ 이것을 μΆ”μ ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. =)

κ±±μ •ν•  수 μžˆλŠ” μ‚¬λžŒ, 여기에 ν˜Έν™˜μ„± νŒ¨μΉ˜κ°€ μžˆμŠ΅λ‹ˆλ‹€.

λ‹€μŒ μ½”λ“œλ‘œ requests_patch.py νŒŒμΌμ„ μƒμ„±ν•˜κ³  κ°€μ Έμ˜€λ©΄ λ¬Έμ œκ°€ ν•΄κ²°λ©λ‹ˆλ‹€.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests
import chardet

def monkey_patch():
    prop = requests.models.Response.content
    def content(self):
        _content = prop.fget(self)
        if self.encoding == 'ISO-8859-1':
            encodings = requests.utils.get_encodings_from_content(_content)
            if encodings:
                self.encoding = encodings[0]
            else:
                self.encoding = chardet.detect(_content)['encoding']

            if self.encoding:
                _content = _content.decode(self.encoding, 'replace').encode('utf8', 'replace')
                self._content = _content
                self.encoding = 'utf8'

        return _content
    requests.models.Response.content = property(content)

monkey_patch()


@lavr (/cc @sigmavirus24), 그보닀 훨씬 더 μ‰½κ²Œ 인코딩을 직접 μ œκ³΅ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

>>> r = requests.get('http://irresponsible-server/')
>>> r.encoding = 'utf-8'

그런 λ‹€μŒ μ •μƒμ μœΌλ‘œ μ§„ν–‰ν•˜μ‹­μ‹œμ˜€.

κ°μ‚¬ν•©λ‹ˆλ‹€! ν•œ μ€„λ‘œ μˆ˜ν–‰ν•˜λŠ” 방법에 λŒ€ν•œ 아이디어가 μžˆμŠ΅λ‹ˆκΉŒ?

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰