JSON 객체가 바이트를 받도록 허용하거나 urlopen 출력 문자열을 허용


177

Python 3에서는 URL에서 json 문서를 요청하고 있습니다.

response = urllib.request.urlopen(request)

response객체와 파일 - 류의 객체입니다 readreadline방법. 일반적으로 텍스트 모드에서 열린 파일로 JSON 객체를 만들 수 있습니다.

obj = json.load(fp)

내가하고 싶은 것은 :

obj = json.load(response)

그러나 urlopen은 파일 객체를 이진 모드로 반환하므로 작동하지 않습니다.

해결 방법은 물론 :

str_response = response.read().decode('utf-8')
obj = json.loads(str_response)

그러나 이것은 기분이 좋지 않습니다 ...

바이트 파일 객체를 문자열 파일 객체로 변환하는 더 좋은 방법이 있습니까? 또는 인코딩 urlopen또는 매개 변수가 누락 json.load되었습니까?


2
나는 당신이 거기에 오타가 있다고 생각합니다.
Bob Yoplait

@BobYoplait 동의합니다.
CaptainNemo

답변:


79

HTTP는 바이트를 보냅니다. 해당 리소스가 텍스트 인 경우 일반적으로 Content-Type HTTP 헤더 또는 다른 메커니즘 (RFC, HTML meta http-equiv, ...) 으로 문자 인코딩이 지정됩니다 .

urllib 해야 문자열로 바이트를 인코딩하는 방법을 알고,하지만 너무 순진 - 그건 무섭게 파워 부족 및 취소 파이썬 라이브러리입니다.

Python 3으로 다이빙 은 상황에 대한 개요를 제공합니다.

"해결 방법"은 문제가 없지만 올바른 방법입니다.


6
이것은 "올바른"방법 일 수 있지만 파이썬 3에 대해 취소 할 수있는 것이 있다면이 바이트 / 문자열 쓰레기 일 것입니다. 내장 라이브러리 함수는 다른 내장 라이브러리 함수를 처리하는 방법을 적어도 알고있을 것이라고 생각할 것입니다. 우리가 파이썬을 사용하는 이유 중 하나는 간단한 직관적 구문입니다. 이 변화는 그 모든 곳을 망가 뜨립니다.
ThatAintWorking

4
"요청"라이브러리를 확인하십시오 . 자동으로 이러한 종류의 작업을 처리합니다.
offby1

2
내장 함수 라이브러리 함수가 다른 함수를 처리하는 방법을 "알아야"하는 경우는 아닙니다. JSON은 객체의 UTF-8 표현으로 정의되므로 인코딩을 모르는 바이트를 마술로 디코딩 할 수 없습니다. urlopen인코딩을 알고 있기 때문에 바이트 자체를 디코딩 할 수 있어야 한다는 데 동의합니다 . 어쨌든, 파이썬 표준 라이브러리 솔루션을 답으로 게시했습니다 codecs. 모듈을 사용하여 바이트의 스트리밍 디코딩을 수행 할 수 있습니다 .
jbg

1
@ThatAintWorking : 동의하지 않습니다. 바이트와 ​​문자열의 차이를 명시 적으로 관리해야하는 것은 목에 통증이 있지만 언어가 암시 적으로 변환하도록하는 것은 훨씬 더 큰 고통입니다. 암시 적 바이트 <-> 문자열 변환은 많은 버그의 원천이며 Python3은 함정을 지적하는 데 매우 유용합니다. 그러나 도서관이이 분야에서 개선의 여지가 있다는 데 동의합니다.
EvertW

@EvertW 실패, 내 의견으로는, 문자열을 처음에는 유니 코드로 만들어야합니다.
ThatAintWorking

99

구조에 대한 파이썬의 훌륭한 표준 라이브러리…

import codecs

reader = codecs.getreader("utf-8")
obj = json.load(reader(response))

py2 및 py3과 함께 작동합니다.

문서 : Python 2 , Python3


11
python 3.4.3왜이 대답을 시도 할 때이 오류가 발생 했는지 확실하지 않습니까? 오류는TypeError: the JSON object must be str, not 'StreamReader'
Aaron Lelevier

9
@AronYsidoro json.loads()대신 사용하셨습니까 json.load()?
sleepycal

6
보너스 포인트의 경우 utf-8 :을 가정하는 대신 응답에 지정된 인코딩을 사용하십시오 response.headers.get_content_charset(). None인코딩이없고 python2에없는 경우 반환 합니다.
Phil Frost

5
@PhilFrost 매끈하다. 실제로는주의해서 지불해야합니다. JSON은 정의에 따라 항상 UTF-8, UTF-16 또는 UTF-32이며 UTF-8이 될 가능성이 매우 높습니다. 따라서 웹 서버에서 다른 인코딩을 반환하면 웹 서버 소프트웨어가 잘못 구성되어있을 수 있습니다. 진정한 비표준 JSON.
jbg

6
파이썬 3.5에서 사용할 때 오류는 "AttributeError : 'bytes'객체에 'read'속성이 없습니다"
Harper Koo

66

나는 그 질문이 가장 좋은 답이라고 생각했다. :)

import json
from urllib.request import urlopen

response = urlopen("site.com/api/foo/bar").read().decode('utf8')
obj = json.loads(response)

18

requests라이브러리를 사용 하여이 문제를 해결하려는 다른 사람은 다음을 수행하십시오 .

import json
import requests

r = requests.get('http://localhost/index.json')
r.raise_for_status()
# works for Python2 and Python3
json.loads(r.content.decode('utf-8'))

12
이 기능은 다음에 내장되어 requests있습니다. 간단하게 할 수 있습니다r.json()
jbg

1
@jbg의 방법을 사용하면 명확히 할 필요가 없습니다 json.loads. 당신이해야 할 일은 r.json()이미 JSON 객체를 dict에로드 한 것입니다.
Blairg23

*** UnicodeEncodeError: 'ascii' codec can't encode characters in position 264-265: ordinal not in range(128)
andilabs

13

이것은 나를 위해 작동합니다. 나는 '요청'라이브러리를 사용 하여 인간 요청json() 의 문서 를 확인했습니다.

import requests

url = 'here goes your url'

obj = requests.get(url).json() 

이것이 가장 좋은 방법입니다. 실제로 읽을 수 있으며 이와 같은 작업을 수행하는 사람은 요청해야합니다.
Baldrickk

6

Python 3.4.3 & 3.5.2와 Django 1.11.3을 사용하여 비슷한 문제가 발생했습니다. 그러나 Python 3.6.1로 업그레이드하면 문제가 해결되었습니다.

https://docs.python.org/3/whatsnew/3.6.html#json 에서 자세한 내용을 확인할 수 있습니다.

특정 버전의 Python에 묶이지 않으면 3.6 이상으로 업그레이드하십시오.


3

플라스크 마이크로 프레임 워크를 사용하는 동안이 문제가 발생하면 다음을 수행하면됩니다.

data = json.loads(response.get_data(as_text=True))

문서에서 : "as_text가 True로 설정된 경우 반환 값은 디코딩 된 유니 코드 문자열입니다."


Flask 단위 테스트에 문제가있어서이 페이지에 왔습니다. 단일 회선 호출을 게시 해 주셔서 감사합니다.
sfblackl

1

당신의 해결 방법은 실제로 저를 구했습니다. Falcon 프레임 워크를 사용하여 요청을 처리하는 데 많은 문제가있었습니다. 이것은 나를 위해 일했습니다. 요청 양식 curl pr httpie 인 req

json.loads(req.stream.read().decode('utf-8'))

1

바이트 데이터를 json으로 스트리밍합니다.

import io

obj = json.load(io.TextIOWrapper(response))

io.TextIOWrapper는 코덱의 모듈 리더보다 선호됩니다. https://www.python.org/dev/peps/pep-0400/


`*** AttributeError : 'Response'객체에 'readable'속성이 없습니다. '
andilabs

*** AttributeError : 'bytes'객체에 'readable'속성이 없습니다.
andilabs

urllib 또는 요청을 사용하고 있습니까? urllib 용입니다. bytes 객체가 있으면을 사용하십시오 json.loads(bytes_obj.decode()).
Collin Anderson

0

HttpResponse 컨텐츠를 JSON으로 만드는 간단한 방법을 찾았습니다.

import json

request = RequestFactory() # ignore this, this just like your request object

response = MyView.as_view()(request) # got response as HttpResponse object

response.render() # call this so we could call response.content after

json_response = json.loads(response.content.decode('utf-8'))

print(json_response) # {"your_json_key": "your json value"}

당신을 도울 희망


0

Python 3.6 json.loads()부터는 bytes객체 를 직렬화 해제하는 데 사용할 수 있습니다 (인코딩은 UTF-8, UTF-16 또는 UTF-32 여야 함). 따라서 표준 라이브러리의 모듈 만 사용하여 다음을 수행 할 수 있습니다.

import json
from urllib import request

response = request.urlopen(url).read()
data = json.loads(response)

-2

나는 아래 프로그램을 사용했다. json.loads()

import urllib.request
import json
endpoint = 'https://maps.googleapis.com/maps/api/directions/json?'
api_key = 'AIzaSyABbKiwfzv9vLBR_kCuhO7w13Kseu68lr0'
origin = input('where are you ?').replace(' ','+')
destination = input('where do u want to go').replace(' ','+')
nav_request = 'origin={}&destination={}&key={}'.format(origin,destination,api_key)
request = endpoint + nav_request
response = urllib.request.urlopen(request).read().decode('utf-8')
directions = json.loads(response)
print(directions)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.