Requests: 슀트리밍 gzip 응닡

에 λ§Œλ“  2014λ…„ 07μ›” 31일  Β·  10μ½”λ©˜νŠΈ  Β·  좜처: psf/requests

큰 XML 응닡을 슀트림으둜 μ²˜λ¦¬ν•΄μ•Ό ν•©λ‹ˆλ‹€. μ••μΆ•λ˜μ§€ μ•Šμ€ 응닡은 크기가 수백 λ©”κ°€λ°”μ΄νŠΈμΌ 수 μžˆμœΌλ―€λ‘œ XML νŒŒμ„œμ— μ „λ‹¬ν•˜κΈ° 전에 μ™„μ „νžˆ λ©”λͺ¨λ¦¬μ— λ‘œλ“œν•˜λŠ” 것은 μ˜΅μ…˜μ΄ μ•„λ‹™λ‹ˆλ‹€.

lxml을 μ‚¬μš©ν•˜μ—¬ ꡬ문 λΆ„μ„ν•˜κ³  μš”μ²­ λ¬Έμ„œμ˜ μ–΄λ”˜κ°€μ— μ„€λͺ…λœ λŒ€λ‘œ response.raw λ₯Ό iterparse() ν•¨μˆ˜μ— μ „λ‹¬ν•©λ‹ˆλ‹€. 이것은 μ••μΆ•λ˜μ§€ μ•Šμ€ 응닡에 λŒ€ν•΄ 잘 μž‘λ™ν•©λ‹ˆλ‹€.

λΆˆν–‰νžˆλ„, λ‚΄κ°€ ν˜ΈμΆœν•˜λŠ” APIλŠ” 특히 쒋지 μ•ŠμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ μ••μΆ•λ˜μ§€ μ•Šμ€ 데이터λ₯Ό λͺ…μ‹œμ μœΌλ‘œ μš”μ²­ν•˜λ”λΌλ„ Content-Encoding: gzip λ₯Ό λ°˜ν™˜ν•˜λŠ” κ²½μš°κ°€ μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ μ΄λŸ¬ν•œ κ·Ήλ„λ‘œ 반볡적이고 μž₯ν™©ν•œ XML 파일의 μ••μΆ•λ₯ μ€ 정말 μ’‹κΈ° λ•Œλ¬Έμ—(10x+) μ••μΆ•λœ 응닡을 μ‚¬μš©ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

μš”μ²­μœΌλ‘œ κ°€λŠ₯ν•œκ°€μš”? λ¬Έμ„œμ—μ„œ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€. urllib3에 λŒ€ν•΄ μžμ„Ένžˆ μ‘°μ‚¬ν•˜λ©΄ HTTPResponse.read() λ©”μ„œλ“œκ°€ decode_content λ§€κ°œλ³€μˆ˜λ₯Ό μ§€μ›ν•˜λŠ” κ²ƒμœΌλ‘œ λ³΄μž…λ‹ˆλ‹€. μ„€μ •λ˜μ§€ μ•Šμ€ 경우 urllib3은 μƒμ„±μžμ— μ„€μ •λœ κ²ƒμœΌλ‘œ λŒ€μ²΄λ©λ‹ˆλ‹€. μš”μ²­μ΄ requests.adapters.HTTPAdapter.send() 의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜λ©΄ decode_content λ₯Ό False 둜 λͺ…μ‹œμ μœΌλ‘œ μ„€μ •ν•©λ‹ˆλ‹€.

μš”μ²­μ΄ κ·Έλ ‡κ²Œ ν•˜λŠ” μ΄μœ κ°€ μžˆμŠ΅λ‹ˆκΉŒ?

μ΄μƒν•˜κ²Œλ„ iter_content() μ‹€μ œλ‘œ μ½λŠ” λ™μ•ˆ decode_content=True λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€. μ—¬κΈ° μ™œ? 그것은 λͺ¨λ‘ μ•½κ°„ μž„μ˜μ μœΌλ‘œ λ‚˜νƒ€λ‚©λ‹ˆλ‹€. μ—¬κΈ° μ €κΈ°μ„œ μ΄λ ‡κ²Œ ν•˜λŠ” 동기가 정말 이해가 λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
개인적으둜 lxml을 μœ„ν•œ 파일λ₯˜ 객체가 ν•„μš”ν•˜κΈ° λ•Œλ¬Έμ— λ¬Όλ‘  iter_content() λ₯Ό μ‹€μ œλ‘œ μ‚¬μš©ν•  μˆ˜λŠ” μ—†μŠ΅λ‹ˆλ‹€.

이전에 μš”μ²­κ³Ό lxml 사이에 μ—°κ²°ν•  수 μžˆλŠ” 자체 파일과 같은 개체λ₯Ό μž‘μ„±ν–ˆμ§€λ§Œ λ¬Όλ‘  버퍼링이 μ–΄λ ΅κ³  이전에 μž‘μ„±ν•œ 것보닀 더 λ˜‘λ˜‘ν•œ μ‚¬λžŒλ“€μ²˜λŸΌ λŠκ»΄μ§€λ―€λ‘œ 직접 둀링할 ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€. .

이것을 μ²˜λ¦¬ν•˜λŠ” 방법에 λŒ€ν•œ λ‹Ήμ‹ μ˜ 쑰언은 λ¬΄μ—‡μž…λ‹ˆκΉŒ? urllib3μ—μ„œ decode_content=True λ₯Ό κΈ°λ³Έκ°’μœΌλ‘œ μ„€μ •ν•˜λ„λ‘ μš”μ²­μ„ λ³€κ²½ν•΄μ•Ό ν•©λ‹ˆκΉŒ?

Contributor Friendly Documentation Planned

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

λ‚˜λŠ” 과거에 이것을 ν–ˆλ‹€

r = requests.get('url', stream=True)
r.raw.decode_content = True
...

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

μ•„λ‹ˆμš”, λ‹€μ–‘ν•œ 이유둜 기본적으둜 μ„€μ •ν•΄μ„œλŠ” μ•ˆ λ©λ‹ˆλ‹€. 당신이 ν•΄μ•Ό ν•  일은 functools.partial λ₯Ό μ‚¬μš©ν•˜μ—¬ μ‘λ‹΅μ—μ„œ read λ©”μ†Œλ“œλ₯Ό λ°”κΎΈλŠ” κ²ƒμž…λ‹ˆλ‹€.

response.raw.read = functools.partial(response.raw.read, decode_content=True)

그런 λ‹€μŒ response.raw λ₯Ό νŒŒμ„œμ— μ „λ‹¬ν•©λ‹ˆλ‹€.

@sigmavirus24 κ°μ‚¬ν•©λ‹ˆλ‹€. μœ„μ—μ„œ μ„€λͺ…ν•œ λ¬Έμ œμ— λŒ€ν•œ ν™•μ‹€ν•œ ν•΄κ²°μ±…μž…λ‹ˆλ‹€!

μš”μ²­ λ¬Έμ„œ(예: FAQ: http://docs.python-requests.org/en/latest/community/faq/#encoded -data)에 μΆ”κ°€ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.
ν˜„μž¬ "Requests automatically decompresses gzip-encoded response"λΌλŠ” λ¬Έκ΅¬λŠ” stream=True κ²½μš°μ— μ˜¬λ°”λ₯΄μ§€ μ•ŠμœΌλ©° λ†€λΌμ›€μœΌλ‘œ μ΄μ–΄μ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€.

λ‚΄ λ¬Έμ œμ— κ΄€ν•΄μ„œλŠ” urllib3 문제 μ—μ„œ μ½μ—ˆλ“―μ΄ gzip μ••μΆ• ν•΄μ œμ˜ urllib3 κ΅¬ν˜„μ—λŠ” λ‚΄ μ½”λ“œμ—μ„œ ν•΄κ²°ν•΄μ•Ό ν•˜λŠ” 자체 μž‘μ€ 단점이 μžˆμ§€λ§Œ 더 이상 μš”μ²­μ— λŒ€ν•œ λ¬Έμ œλŠ” μ•„λ‹™λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ 더 이상 μš”μ²­μ— λ¬Έμ œκ°€ λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

이것이 λ‹«νž 수 μžˆλ‹€κ³  λŠλΌμ‹­λ‹ˆκΉŒ?

@sigmavirus24 ν˜„μž¬ λ¬Έμ„œκ°€ μ˜¬λ°”λ₯΄μ§€

κ·ΈλŸ¬λ‚˜ 그것에 λ™μ˜ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ 예, λ‹«μœΌμ‹­μ‹œμ˜€!

λ¬Έμ„œκ°€ 더 λͺ…ν™•ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ‚˜μ—κ²Œ (그리고 이것은 μ „μ μœΌλ‘œ λ‚΄κ°€ 핡심 개발자이기 λ•Œλ¬Έμ—) 첫 번째 단락은 μ›μ‹œ 응닡을 μ ˆλŒ€ κ±΄λ“œλ¦¬μ§€ μ•Šμ„ μ‚¬μš©μžμ˜ 90%μ—κ²Œ λ§ν•˜λŠ” 반면, 두 번째 단락은 "ν•˜μ§€λ§Œ μ•‘μ„ΈμŠ€ν•΄μ•Ό ν•˜λŠ” 경우 μ›μ‹œ 데이터가 μžˆμŠ΅λ‹ˆλ‹€." λ‚΄κ°€ λ§ν–ˆλ“―μ΄, 그것은 λ‚˜μ—κ²Œ λΆ„λͺ…ν•˜μ§€λ§Œ 그것이 μ–΄λ–»κ²Œ 더 λͺ…ν™•ν•΄μ§ˆ 수 μžˆλŠ”μ§€ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€. 였늘 밀에 μž‘μ—…ν•˜κ² μŠ΅λ‹ˆλ‹€.

μ €μ—κ²ŒλŠ” "μ›μ‹œ 데이터"λ₯Ό "μ›μ‹œ νŽ˜μ΄λ‘œλ“œ", 즉 μ••μΆ• ν•΄μ œλœ 슀트림으둜 ν•΄μ„ν–ˆμ„ κ²ƒμž…λ‹ˆλ‹€. ν•„μš”ν•œ λΆ€λΆ„λ§Œ 읽으면 λ©λ‹ˆλ‹€. μ••μΆ• ν•΄μ œλœ blob인 .content 와 λŒ€μ‘°μ μœΌλ‘œ(νŽ˜μ΄λ‘œλ“œλ„ μžˆμ§€λ§Œ λ‹€λ₯Έ ν˜•μ‹μž„).

μ‹€μ œ μ••μΆ• ν•΄μ œλŠ” λ‚˜μ—κ²Œ HTTP 라이브러리의 κ΄€μ‹¬μ‚¬μ²˜λŸΌ λŠκ»΄μ§‘λ‹ˆλ‹€. μš”μ²­μ΄ 좔상화될 κ²ƒμœΌλ‘œ μ˜ˆμƒλ˜λŠ” HTTP κ΅¬ν˜„ μ„ΈλΆ€ μ •λ³΄μž…λ‹ˆλ‹€. μš”μ²­μ—μ„œ νŽ˜μ΄λ‘œλ“œλ₯Ό 슀트림으둜 읽든 미리 κ°€μ Έμ˜¨ 데이터 λ©μ–΄λ¦¬λ‘œ 읽든 차이가 μ—†μŠ΅λ‹ˆλ‹€. μ–΄λŠ μͺ½μ΄λ“  μš”μ²­μ€ κ΅¬ν˜„ μ„ΈλΆ€ 정보 'μ••μΆ•'을 μΆ”μƒν™”ν•©λ‹ˆλ‹€.

(이 가정은 decode_content λ₯Ό True 둜 κΈ°λ³Έ μ„€μ •ν•˜λΌλŠ” λ‚΄ μ›λž˜ μš”μ²­μ˜ 핡심이기도 ν–ˆμŠ΅λ‹ˆλ‹€. λ¬Όλ‘  이것이 λˆ„μΆœλœ 좔상화λ₯Ό λ³΄μ•˜μœΌλ―€λ‘œ 더 이상 μ œμ•ˆν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.)

ν•˜μ§€λ§Œ λ„€, μ‚¬μš©μžμ˜ 99%κ°€ 이 μ„ΈλΆ€ μ‚¬ν•­μ˜ 영ν–₯을 받지 μ•Šμ„ κ²ƒμ΄λΌλŠ” 데 μ ˆλŒ€μ μœΌλ‘œ λ™μ˜ν•©λ‹ˆλ‹€.

이 문제λ₯Ό λ‹«μœΌμ‹­μ‹œμ˜€.

κ·Έλž˜μ„œ 이것은 μ‹€μ œλ‘œ ν•œλ™μ•ˆ λ‚΄ 머리 μ†μ—μ„œ λ– λ“€μ©ν•˜κ²Œ λ§΄λŒμ•˜μ§€λ§Œ μ€‘μš”ν•œ API 변경이 될 것이기 λ•Œλ¬Έμ— 아직 μ œμ•ˆν•˜μ§€ μ•Šμ€ κ²ƒμœΌλ‘œ μ΄μ–΄μ§‘λ‹ˆλ‹€.

r.raw λŠ” λ¬Έμ„œν™”ν•˜μ§€ μ•Šμ€ 객체이고 urllib3 μ œκ³΅ν•œ 객체이기 λ•Œλ¬Έμ— μ‚¬λžŒλ“€μ—κ²Œ r.raw μ‚¬μš©ν•˜λ„λ‘ μ œμ•ˆν•œλ‹€λŠ” 사싀이 λ§ˆμŒμ— 듀지 μ•ŠμŠ΅λ‹ˆλ‹€. κ΅¬ν˜„ μ„ΈλΆ€ 사항). 이λ₯Ό 염두에 두고 urllib3 λ©”μ„œλ“œμ— ν”„λ‘μ‹œν•˜λŠ” Response κ°œμ²΄μ— λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•˜λŠ” 아이디어λ₯Ό 가지고 λ†€μ•˜μŠ΅λ‹ˆλ‹€( read λŠ” raw.read λ“±). 이것은 μ£Όμœ„μ— μš°λ¦¬μ—κ²Œ 좔가적인 μœ μ—°μ„±μ„ 제곡 urllib3 와 (μ‚¬μš©μžλ₯Ό λŒ€μ‹ ν•˜μ—¬) ν•Έλ“€μ˜ API λ³€κ²½ 우리λ₯Ό 수 urllib3 κ·Έλž˜μ„œ μ–΄λ–€μ΄μ—†λŠ”, μ—­μ‚¬μ μœΌλ‘œ 거의 λ¬Έμ œκ°€λ˜μ§€ μ•Šμ•˜μ–΄μš” ( κΈ΄κΈ‰).

κ·Έλ ‡κΈ΄ ν•˜μ§€λ§Œ λ‚΄ μƒκ°μ—λŠ” Response κ°œμ²΄μ— λŒ€ν•œ λ©”μ„œλ“œκ°€ 이미 μΆ©λΆ„ν•˜κ³  APIλ₯Ό λŠ˜λ¦¬λŠ” 것은 이상적이지 μ•ŠμŠ΅λ‹ˆλ‹€. 졜고의 APIλŠ” μ œκ±°ν•  것이 μ—†λŠ” APIμž…λ‹ˆλ‹€. κ·Έλž˜μ„œ λ‚˜λŠ” 이것에 λŒ€ν•΄ 계속 κ²½κ³„ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.


이 가정은 λ˜ν•œ κΈ°λ³Έ decode_contentλ₯Ό True둜 μ„€μ •ν•˜λΌλŠ” λ‚΄ μ›λž˜ μš”μ²­μ˜ ν•΅μ‹¬μ΄μ—ˆμŠ΅λ‹ˆλ‹€. λ¬Όλ‘  이것이 λˆ„μΆœλœ 좔상화λ₯Ό λ³΄μ•˜μœΌλ―€λ‘œ 더 이상 μ œμ•ˆν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

이것을 λ°œκ²¬ν•˜κ³  이것이 μ™œ 사싀인지 ν™•μ‹€ν•˜μ§€ μ•Šμ€ λ‹€λ₯Έ μ‚¬λžŒλ“€μ„ μœ„ν•΄ μ„€λͺ…ν•˜κ² μŠ΅λ‹ˆλ‹€.

응닡 길이λ₯Ό ν™•μΈν•˜κ±°λ‚˜ μ‘λ‹΅μœΌλ‘œ λ‹€λ₯Έ μ€‘μš”ν•œ μž‘μ—…μ„ μˆ˜ν–‰ν•˜κΈ° μœ„ν•΄ μžλ™ μ••μΆ• ν•΄μ œλ₯Ό λ„λŠ” μš”μ²­ μ‚¬μš©μžκ°€ μ—¬λŸ¬ λͺ… μžˆμŠ΅λ‹ˆλ‹€. μ „μžμ˜ μ†ŒλΉ„μž 쀑 ν•˜λ‚˜λŠ” OpenStackμž…λ‹ˆλ‹€. λ§Žμ€ OpenStack ν΄λΌμ΄μ–ΈνŠΈλŠ” ν΄λΌμ΄μ–ΈνŠΈλ‘œ μ „μ†‘λœ Content-Length 헀더와 μˆ˜μ‹ λœ 본문의 μ‹€μ œ 길이λ₯Ό κ²€μ¦ν•©λ‹ˆλ‹€. κ·Έλ“€μ—κ²Œ 감압 μ²˜λ¦¬λŠ” μœ νš¨ν•œ 응닡을 μˆ˜μ‹ ν•˜κ³  μ²˜λ¦¬ν•˜κ³  μžˆλŠ”μ§€ ν™•μΈν•˜κΈ° μœ„ν•œ κ³΅μ •ν•œ μ ˆμΆ©μ•ˆμž…λ‹ˆλ‹€.

또 λ‹€λ₯Έ μ†ŒλΉ„μžλŠ” Betamax(λ˜λŠ” μ‹€μ œλ‘œ Response 개체λ₯Ό (재)κ΅¬μ„±ν•˜λŠ” λͺ¨λ“  도ꡬ)μž…λ‹ˆλ‹€. μ™„μ „νžˆ μœ νš¨ν•œ 응닡을 λ§Œλ“œλŠ” 전체 ν”„λ‘œμ„ΈμŠ€λ₯Ό μ²˜λ¦¬ν•  λ•Œ μ½˜ν…μΈ κ°€ μ••μΆ•λœ ν˜•μ‹μ΄μ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

@Lukasa λ‚˜ λ‚΄κ°€ μ•Œμ§€ λͺ»ν•˜λŠ” λ‹€λ₯Έ μ‚¬λžŒλ“€λ„ 이 λ™μž‘μ— 크게 μ˜μ‘΄ν•œλ‹€κ³  ν™•μ‹ ν•©λ‹ˆλ‹€.

였늘 같은 문제λ₯Ό κ²ͺμ—ˆκ³  ν˜„μž¬λ‘œμ„œλŠ” 응닡을 μŠ€νŠΈλ¦¬λ°ν•  수 μžˆλŠ” λ‹€λ₯Έ 방법이 μ—†κΈ° λ•Œλ¬Έμ— 같은 가정을 ν•˜κ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

였히렀 μ‘λ‹΅μ—μ„œ μ—¬λŸ¬ μƒˆλ‘œμš΄ 방법보닀 μ™œ μ•ˆ ν•˜λ‚˜μ˜ μƒˆλ‘œμš΄ 속성 예λ₯Ό λ“€μ–΄ response.stream 에 ν”„λ‘μ‹œμ˜ 같은 μ—­ν•  μ—°μ£Ό 것이닀 .raw ? λ˜ν•œ stream=True μ„€μ •/λ§€κ°œλ³€μˆ˜λ₯Ό ν›Œλ₯­ν•˜κ²Œ λ―ΈλŸ¬λ§ν•˜κ³  ν˜„μž¬ .raw λ™μž‘μ΄ ν•„μš”ν•œ μ‚¬μš©μžμ—κ²Œ 영ν–₯을 주지 μ•ŠμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” 과거에 이것을 ν–ˆλ‹€

r = requests.get('url', stream=True)
r.raw.decode_content = True
...

@sigmavirus24에 μ˜ν•œ ν•΄κ²° 방법 은 잘λͺ»λœ μ˜€ν”„μ…‹μ„ λ°˜ν™˜ν•˜λŠ” tell λ©”μ„œλ“œμ˜ 의미 체계λ₯Ό 깨뜨 λ¦½λ‹ˆλ‹€.

tell() λ₯Ό μ‚¬μš©ν•˜μ—¬ 방금 읽은 λ°”μ΄νŠΈ 수λ₯Ό νŒŒμ•…ν•˜λŠ” Google Cloud Storage API에 재개 κ°€λŠ₯ν•œ μ—…λ‘œλ“œλ‘œ 응닡을 μŠ€νŠΈλ¦¬λ°ν•  λ•Œ 이 λ¬Έμ œκ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€( μ—¬κΈ° ).

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