이 튜토리얼에서는 다음을 살펴보게 됩니다:
- JSON이란 무엇이며 Python에서 처리하는 방법
- 파이썬의 json 모듈로 JSON 파싱하는 방법
- JSON 파싱에 json이 최선의 선택인지
파이썬에서의 JSON 소개
파이썬으로 JSON 파싱을 시작하기 전에, JSON이 무엇이며 파이썬에서 어떻게 사용하는지 이해해 봅시다.
JSON이란 무엇인가?
JSON(JavaScript Object Notation의 약자)은 경량 데이터 교환 형식입니다. 사람이 읽고 쓰기 쉽고, 기계가 파싱하고 생성하기 쉬운 특징을 지닙니다. 이로 인해 가장 널리 쓰이는 데이터 형식 중 하나가 되었습니다. 특히 JSON은 API를 통해 서버와 웹 애플리케이션 간 데이터 전송에 흔히 사용되기 때문에 “웹의 언어”로 자리매김했습니다.
다음은 JSON의 예시입니다:
{
"name": "Maria Smith",
"age": 32,
"isMarried": true,
"hobbies": ["reading", "jogging"],
"address": {
"street": "123 Main St",
"city": "San Francisco",
"state": "CA",
"zip": "12345"
},
"phoneNumbers": [
{
"type": "home",
"number": "555-555-1234"
},
{
"type": "work",
"number": "555-555-5678"
}
],
"notes": null
}
보시다시피 JSON은 키-값 쌍으로 구성됩니다. 각 키는 문자열이며, 각 값은 문자열, 숫자, 부울, null, 배열 또는 객체일 수 있습니다. 자바스크립트 객체와 유사하지만, JSON은 파이썬을 포함한 모든 프로그래밍 언어에서 사용할 수 있습니다.
파이썬에서 JSON 처리 방법
파이썬은 표준 라이브러리의 일부인 json 모듈을 통해 JSON을 기본적으로 지원합니다. 즉, 파이썬에서 JSON을 다루기 위해 추가 라이브러리를 설치할 필요가 없습니다. json은 다음과 같이 임포트할 수 있습니다:
import json
파이썬 내장 json 라이브러리는 JSON을 처리하기 위한 완전한 API를 제공합니다. 특히 두 가지 핵심 함 수인 loads와 load가 있습니다. loads 함수는 문자열로부터 JSON 데이터를 파싱할 수 있게 합니다. 이름이 복수형처럼 보이지만, 끝의 “s”는 “string”을 의미하므로 “load-s”로 읽어야 합니다. 반면 load 함수는 JSON 데이터를 바이트로 파싱하는 데 사용됩니다.
이 두 메서드를 통해 json은 JSON 데이터를 사전(dictionary) 이나 리스트(list) 같은 동등한 Python 객체로 변환하거나 그 반대로 변환할 수 있는 기능을 제공합니다. 또한 json 모듈은 특정 데이터 유형을 처리하기 위한 사용자 정의 인코더(encoder)와 디코더(decoder)를 생성할 수 있게 합니다.
계속해서 json 라이브러리를 사용하여 Python에서 JSON 데이터를 파싱하는 방법을 알아보세요!
파이썬으로 JSON 데이터 파싱하기
실제 사례를 살펴보고 다양한 소스의 JSON 데이터를 서로 다른 Python 데이터 구조로 파싱하는 방법을 배워봅시다.
JSON 문자열을 Python 사전으로 변환하기
문자열에 저장된 JSON 데이터를 Python 사전으로 변환해야 한다고 가정해 보겠습니다. JSON 데이터는 다음과 같습니다:
{
"name": "iPear 23",
"colors": ["black", "white", "red", "blue"],
"price": 999.99,
"inStock": true
}
그리고 이 데이터의 Python 문자열 표현은 다음과 같습니다:
smartphone_json = '{"name": "iPear 23", "colors": ["black", "white", "red", "blue"], "price": 999.99, "inStock": true}'
긴 다중 행 JSON 문자열을 저장할 때는 Python의 삼중 따옴표(“`) 사용 규칙을 고려하세요.
아래 코드로 smartphone이 유효한 Python 문자열인지 확인할 수 있습니다:
print(type(smartphone))
다음과 같이 출력됩니다:
<class 'str'>
str은 “문자열(string)”을 의미하며, smartphone 변수가 텍스트 시퀀스 유형임을 나타냅니다.
json.loads() 메서드를 사용하여 smartphone에 포함된 JSON 문자열을 Python 사전으로 파싱합니다:
import json
# JSON 문자열
smartphone_json = '{"name": "iPear 23", "colors": ["black", "white", "red", "blue"], "price": 999.99, "inStock": true}'
# JSON 문자열을 Python 딕셔너리로 변환
smartphone_dict = json.loads(smartphone_json)
# 결과 변수의 타입 확인
print(type(smartphone_dict)) # dict
이 코드 조각을 실행하면 다음과 같은 결과가 출력됩니다:
{"name": "John", "surname": "Williams", "age": 48, "city": "New York"}
훌륭합니다! smartphone_dict는 이제 유효한 Python 사전(dict)을 포함합니다!
따라서 JSON 문자열을 Python 사전으로 변환하려면 유효한 JSON 문자열을 json.loads()에 전달하기만 하면 됩니다.
이제 결과 사전의 필드에 평소처럼 접근할 수 있습니다:
product = smartphone_dict['name'] # smartphone
priced = smartphone['price'] # 999.99
colors = smartphone['colors'] # ['black', 'white', 'red', 'blue']
json.loads() 함수가 항상 사전(dictionary)을 반환하는 것은 아니라는 점을 명심하세요. 구체적으로, 반환되는 데이터 유형은 입력 문자열에 따라 달라집니다. 예를 들어, JSON 문자열이 평면 값(flat value)을 포함하는 경우, 해당 값은 대응하는 Python 기본형(primitive) 값으로 변환됩니다:
import json
json_string = '15.5'
float_var = json.loads(json_string)
print(type(float_var)) # <class 'float'>
마찬가지로, 배열 리스트를 포함하는 JSON 문자열은 Python 리스트가 됩니다:
import json
json_string = '[1, 2, 3]'
list_var = json.loads(json_string)
print(list_var) # <class 'list'>
아래 변환 테이블을 통해 json이 JSON 값을 Python 데이터로 변환하는 방식을 확인하세요:
| JSON 값 | Python 데이터 |
문자열 |
문자열 |
number (integer) |
정수 |
숫자 (실수) |
float |
참 |
참 |
false |
False |
null |
없음 |
배열 |
목록 |
객체 |
사전 |
JSON API 응답을 Python 사전으로 변환하기
API를 만들고 그 JSON 응답을 Python 사전으로 변환해야 한다고 가정해 보겠습니다. 아래 예시에서는 {JSON} Placeholder 프로젝트의 다음 API 엔드포인트를 호출하여 가짜 JSON 데이터를 가져옵니다:
https://jsonplaceholder.typicode.com/todos/1
해당 RESTful API는 아래 JSON 응답을 반환합니다:
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
표준 라이브러리의 urllib 모듈을 사용하여 해당 API를 호출하고 결과 JSON을 다음과 같이 Python 사전으로 변환할 수 있습니다:
import urllib.request
import json
url = "https://jsonplaceholder.typicode.com/todos/1"
with urllib.request.urlopen(url) as response:
body_json = response.read()
body_dict = json.loads(body_json)
user_id = body_dict['userId'] # 1
urllib.request.urlopen() 은 API 호출을 수행하고 HTTPResponse 객체를 반환합니다. 그 다음 read() 메서드를 사용하여 응답 본문 body_json을 가져옵니다. 이 본문은 API 응답을 JSON 문자열로 포함하고 있습니다. 마지막으로, 앞서 설명한 대로 json.loads() 를 통해 해당 문자열을 파이썬 사전으로 파싱할 수 있습니다.
비슷하게 requests를 사용해도 동일한 결과를 얻을 수 있습니다 :
import requests
import json
url = "https://jsonplaceholder.typicode.com/todos/1"
response = requests.get(url)
body_dict = response.json()
user_id = body_dict['userId'] # 1
.json() 메서드는 JSON 데이터를 포함하는 응답 객체를 해당 파이썬 데이터 구조로 자동 변환한다는 점에 유의하세요.
좋습니다! 이제 urllib과 requests를 모두 사용하여 Python에서 JSON API 응답을 파싱하는 방법을 알게 되었습니다.
JSON 파일을 Python 사전으로 로드하기
스마트폰에 저장된 smartphone.json 파일에 다음과 같은 JSON 데이터가 있다고 가정해 보겠습니다:
{
"name": "iPear 23",
"colors": ["black", "white", "red", "blue"],
"price": 999.99,
"inStock": true,
"dimensions": {
"width": 2.82,
"height": 5.78,
"depth": 0.30
},
"features": [
"5G",
"HD display",
"Dual camera"
]
}
목표는 JSON 파일을 읽고 Python 사전(dict)에 로드하는 것입니다. 아래 코드 조각으로 이를 달성하세요:
import json
with open('smartphone.json') as file:
smartphone_dict = json.load(file)
print(type(smartphone_dict)) # <class 'dict'>
features = smartphone_dict['features'] # ['5G', 'HD display', 'Dual camera']
내장된 open() 라이브러리를 사용하면 파일을 로드하고 해당 파일 객체를 얻을 수 있습니다. 그런 다음 json.read() 메서드는 JSON 문서를 포함하는 텍스트 파일 또는 바이너리 파일을 동등한 Python 객체로 역직렬화합니다. 이 경우 smartphone.json은 Python 사전이 됩니다.
완벽합니다! Python에서 JSON 파일을 파싱하는 데는 단 몇 줄의 코드만 필요합니다!
JSON 데이터에서 사용자 정의 Python 객체로
이제 JSON 데이터를 사용자 정의 Python 클래스로 파싱하고 싶을 것입니다. 사용자 정의 Smartphone Python 클래스는 다음과 같습니다:
class Smartphone:
def __init__(self, name, colors, price, in_stock):
self.name = name
self.colors = colors
self.price = price
self.in_stock = in_stock
여기서 목표는 다음 JSON 문자열을 Smartphone 인스턴스로 변환하는 것입니다:
{
"name": "iPear 23 Plus",
"colors": ["black", "white", "gold"],
"price": 1299.99,
"inStock": false
}
이 작업을 수행하려면 사용자 정의 디코더를 생성해야 합니다. 구체적으로 JSONDecoder 클래스를 확장하고 __init__ 메서드에서 object_hook 매개변수를 설정해야 합니다. 사용자 정의 파싱 로직이 포함된 클래스 메서드의 이름을 할당하세요. 해당 파싱 메서드에서는 json.read() 가 반환하는 표준 사전의 값을 사용하여 Smartphone 객체를 생성할 수 있습니다.
아래와 같이 사용자 정의 SmartphoneDecoder 를 정의하세요:
import json
class SmartphoneDecoder(json.JSONDecoder):
def __init__(self, object_hook=None, *args, **kwargs):
# 커스텀 object_hook 메서드 설정
super().__init__(object_hook=self.object_hook, *args, **kwargs)
# 커스텀 파싱 로직을 포함하는 클래스 메서드
#
def object_hook(self, json_dict):
new_smartphone = Smartphone(
json_dict.get('name'),
json_dict.get('colors'),
json_dict.get('price'),
json_dict.get('inStock'),
)
return new_smartphone
참고: 사용자 정의 object_hook() 메서드 내에서 사전 값을 읽을 때는 get() 메서드를 사용해야 합니다. 이렇게 하면 사전에서 키가 누락된 경우에도 KeyError가발생하지 않고 대신 None 값이 반환됩니다.
이제 SmartphoneDecoder 클래스를 json.loads() 의 cls 매개변수에 전달하여 JSON 문자열을 Smartphone 객체로 변환할 수 있습니다:
import json
# class Smartphone:
# ...
# class SmartphoneDecoder(json.JSONDecoder):
# ...
smartphone_json = '{"name": "iPear 23 Plus", "colors": ["black", "white", "gold"], "price": 1299.99, "inStock": false}'
smartphone = json.loads(smartphone_json, cls=SmartphoneDecoder)
print(type(smartphone)) # <class '__main__.Smartphone'>
name = smartphone.name # iPear 23 Plus
마찬가지로 json.load()와 함께 SmartphoneDecoder를 사용할 수 있습니다:
smartphone = json.load(smartphone_json_file, cls=SmartphoneDecoder)
자, 이제 JSON 데이터를 사용자 정의 Python 객체로 파싱하는 방법을 알게 되었습니다!
Python 데이터 → JSON
반대로 Python 데이터 구조와 기본형을 JSON으로 변환하는 것도 가능합니다. 이는 json.dump() 및 json.dumps() 함수를 통해 가능하며, 아래 변환 테이블을 따릅니다:
| 파이썬 데이터 | JSON 값 |
str |
문자열 |
정수 |
숫자 (정수) |
float |
숫자 (실수) |
참 |
참 |
False |
false |
없음 |
null |
목록 |
배열 |
사전 |
객체 |
Null |
None |
json.dump() 는 JSON 문자열을 파일에 기록할 수 있게해줍니다 . 다음 예시와 같습니다:
import json
user_dict = {
"name": "John",
"surname": "Williams",
"age": 48,
"city": "New York"
}
# 샘플 딕셔너리를 JSON 파일로 직렬화
with open("user.json", "w") as json_file:
json.dump(user_dict, json_file)
이 코드 조각은 Python 사용자 변수 user_dict 를 user.json 파일로 직렬화합니다.
마찬가지로, json.dumps() 는 Python 변수를 동등한 JSON 문자열로 변환합니다 :
import json
user_dict = {
"name": "John",
"surname": "Williams",
"age": 48,
"city": "New York"
}
user_json_string = json.dumps(user_dict)
print(user_json_string)
이 코드 조각을 실행하면 다음과 같은 결과가 출력됩니다:
{"name": "John", "surname": "Williams", "age": 48, "city": "New York"}
이것은 Python 딕셔너리의 JSON 표현과 정확히 일치합니다.
사용자 정의 인코더를 지정할 수도 있지만, 그 방법은 본 문서의 목적이 아닙니다. 자세한 내용은 공식 문서를 참고하세요.
파이썬에서 JSON 파싱을 위한 최적의 도구는 json 표준 모듈인가?
일반적인 데이터 파싱과 마찬가지로 JSON 파싱에도 간과할 수 없는 어려움이 따릅니다. 예를 들어, 유효하지 않거나 손상되었거나 비표준 JSON의 경우 Python json 모듈로는 처리하기 어렵습니다.
또한 신뢰할 수 없는 출처의 JSON 데이터를 파싱할 때는 주의가 필요합니다. 악의적인 JSON 문자열이 파서를 중단시키거나 대량의 리소스를 소모할 수 있기 때문입니다. 이는 Python JSON 파서가 고려해야 할 여러 과제 중 하나에 불과합니다.
이러한 특수한 경우를 처리하기 위해 사용자 정의 로직을 도입할 수 있습니다. 하지만 이는 시간이 너무 오래 걸리고 복잡하며 신뢰할 수 없는 코드로 이어질 수 있습니다. 따라서 Web Scraper API와 같이 JSON 파싱을 더 쉽게 만들어주는 상용 도구를 고려해야 합니다.
웹 스크래핑 API는 개발자를 위해 특별히 설계되었으며, JSON 콘텐츠 및 기타 데이터를 파싱하는 다양한 기능을 제공합니다. 이 도구는 시간을 크게 절약하고 JSON 파싱 프로세스의 보안을 강화하는 데 도움이 됩니다. 또한 Bright Data의 차단 방지 프록시 기능을 통해 익명으로 JSON API를 호출할 수 있습니다.
급한 경우, 당사의 ‘서비스로서의 데이터(Data as a Service)’ 제안에도 관심을 가져보시기 바랍니다. 이 서비스를 통해 Bright Data에 특정 요구사항에 맞는 맞춤형 데이터셋 제공을 요청할 수 있습니다. Bright Data가 성능부터 데이터 품질까지 모든 것을 책임집니다.
JSON 데이터 파싱이 이토록 쉬웠던 적이 없습니다!
결론
Python은 json 표준 모듈을 통해 JSON 데이터를 네이티브로 파싱할 수 있게 합니다. 이 모듈은 JSON 콘텐츠를 직렬화 및 역직렬화하는 강력한 API를 제공합니다. 특히 JSON 파일과 JSON 문자열을 각각 처리하기 위한 json.read() 및 json.reads() 메서드를 제공합니다. 여기서는 여러 실제 사례를 통해 Python에서 JSON 데이터를 파싱하는 방법을 살펴보았습니다. 동시에 이 접근 방식의 한계점도 이해하셨을 것입니다. 따라서 데이터 파싱을 위한 최첨단, 완전한 기능을 갖춘 상용 솔루션, 예를 들어 Bright Data의 데이터 및 프록시 제품을 시도해 보시길 권합니다.