-
[PlayData - Day 14] 웹 API[플레이데이터] 2023. 1. 12. 11:13
1. K-Digital Training 과정
- 빅데이터 기반 지능형SW 및 MLOps 개발자 양성과정 19기 (2023/01/09 - Day 14)
2. 목차
- 웹 API의 이해
- 정부의 공공 데이터 가져오기
3. 수업 내용
1. 웹 API의 이해
API (Application Programming Interface)
응용 프로그램에서 사용할 수 있도록 기능을 제어할 수 있게 만든 인터페이스웹 API
웹 어플리케이션 개발에서 다른 서비스에 요청을 보내 응답을 받기 위해 정의된 명세
어떤 웹사이트에서 어떤 API를 제공하는지를 정리한 사이트 (www.programmableweb.com/category/all/apis)웹 API의 데이터 획득 과정
정보를 요청하면 원하는 데이터를 전송한다.
REST(Representational State Transfer) API = 요청하면 응답 후 연결을 끊음
Streaming API = 강제로 연결을 끊기 전까지 연결을 유지함웹 API의 인증 방식
- 인증이 필요할 경우 여러가지 방법으로 인증을 요구하는 경우가 있음
- 최근에는 대부분이 Open Authorization 방식을 사용함 (API 키, 접속토큰)을 이용해 권한을 부여함
- 다른 사람에게 공개해서는 안되며, 공개할 경우 재신청을 해야함
응답 데이터의 형식 및 처리
JSON, XML = 웹 서버에서 클라이언트로 데이터를 전달하기 위해 만든 구조화된 텍스트 형식
JSON 형식의 데이터 처리
JSON (Javascript Object Notation)
데이터 하나의 집합을 객체(Object)라고 하며 '이름(name): 값(Value)'으로 구분import json python_dict = { '이름':'홍길동', '나이':25, '거주지':'서울', '신체정보':{ '키':175.4, '몸무게':71.2 }, '취미':[ '등산', '자전거타기', '독서' ] } type(python_dict) >>> dict
참고) JSON 뷰어 (http://jsonviewer.stack.hu/)
파이썬을 JSON 형태로 변환하기
json_data = json.dumps(python_dict) print(type(json_data)) print(json_data) # 이걸로 출력된 데이터를 복사해서 JSON 뷰어에 입력해도 똑같이 보여준다. >>> <class 'str'> {"\uc774\ub984": "\ud64d\uae38\ub3d9", "\ub098\uc774": 25, "\uac70\uc8fc\uc9c0": "\uc11c\uc6b8", "\uc2e0\uccb4\uc815\ubcf4": {"\ud0a4": 175.4, "\ubab8\ubb34\uac8c": 71.2}, "\ucde8\ubbf8": ["\ub4f1\uc0b0", "\uc790\uc804\uac70\ud0c0\uae30", "\ub3c5\uc11c"]}
옵션을 추가해서 출력 (들여쓰기, 딕셔너리일 경우 Key를 기준으로 정렬, 아스키코드로 구성된 문자열을 설정(한글 = False)
json_data = json.dumps(python_dict, indent=3, sort_keys=True, ensure_ascii=False) print(json_data) >>> { "거주지": "서울", "나이": 25, "신체정보": { "몸무게": 71.2, "키": 175.4 }, "이름": "홍길동", "취미": [ "등산", "자전거타기", "독서" ] }
JSON 형식의 데이터를 파이썬의 딕셔너리 데이터로 변환하고
이 딕셔너리에서 정보를 추출json_dict = json.loads(json_data) print(type(json_dict)) print(json_dict['신체정보']['몸무게']) print(json_dict['취미']) print(json_dict['취미'][0]) >>> <class 'dict'> 71.2 ['등산', '자전거타기', '독서'] 등산
XML 형식의 데이터 처리
XML (eXtensible Markup Language) 다목적 마크업 언어로 태그(Tag)를 사용!pip install xmltodict
xml_data = """<?xml version="1.0" encoding="UTF-8" ?> <사용자정보> <이름>홍길동</이름> <나이>25</나이> <거주지>서울</거주지> <신체정보> <키 unit="cm">175.4</키> <몸무게 unit="kg">71.2</몸무게> </신체정보> <취미>등산</취미> <취미>자전거타기</취미> <취미>독서</취미> </사용자정보> """ print(xml_data) >>> <?xml version="1.0" encoding="UTF-8" ?> <사용자정보> <이름>홍길동</이름> <나이>25</나이> <거주지>서울</거주지> <신체정보> <키 unit="cm">175.4</키> <몸무게 unit="kg">71.2</몸무게> </신체정보> <취미>등산</취미> <취미>자전거타기</취미> <취미>독서</취미> </사용자정보>
파이썬의 딕셔너리 타입의 데이터 (속성 '@속성이름', 태그의 문자열'#text')로 출력
import xmltodict dict_data = xmltodict.parse(xml_data, xml_attribs=True) dict_data >>> {'사용자정보': {'이름': '홍길동', '나이': '25', '거주지': '서울', '신체정보': {'키': {'@unit': 'cm', '#text': '175.4'}, '몸무게': {'@unit': 'kg', '#text': '71.2'}}, '취미': ['등산', '자전거타기', '독서']}}
dict_data = xmltodict.parse(xml_data, xml_attribs=False) dict_data >>> #True와 False의 차이 {'사용자정보': {'이름': '홍길동', '나이': '25', '거주지': '서울', '신체정보': {'키': '175.4', '몸무게': '71.2'}, '취미': ['등산', '자전거타기', '독서']}}
사용자 정보 중 이름 혹은 신체정보를 알고 싶을 때
dict_data['사용자정보']['이름'] >>> '홍길동 dict_data['사용자정보']['신체정보'] >>> {'키': {'@unit': 'cm', '#text': '175.4'}, '몸무게': {'@unit': 'kg', '#text': '71.2'}} dict_data['사용자정보']['신체정보']['키']['@unit'] >>> 'cm' dict_data['사용자정보']['신체정보']['키']['#text'] >>> '175.4'
XML 데이터에서 원하는 데이터 추출
dict_data = xmltodict.parse(xml_data) user_name = dict_data['사용자정보']['이름'] body_data = dict_data['사용자정보']['신체정보'] height = body_data['키']['#text'] height_unit = body_data['키']['@unit'] weight = body_data['몸무게']['#text'] weight_unit = body_data['몸무게']['@unit'] print("[사용자 {0}의 신체정보]".format(user_name)) print("*키: {0}{1}".format(height, height_unit)) print("*몸무게: {0}{1}".format(weight, weight_unit)) >>> [사용자 홍길동의 신체정보] *키: 175.4cm *몸무게: 71.2kg
xml_attribs = False 선택시, unit값이 사라지고 dictionary 형태로 변환된다.
JSON 형식과 유사dict_data2 = xmltodict.parse(xml_data, xml_attribs=False) dict_data2 >>> {'사용자정보': {'이름': '홍길동', '나이': '25', '거주지': '서울', '신체정보': {'키': '175.4', '몸무게': '71.2'}, '취미': ['등산', '자전거타기', '독서']}}
# 2, 3번은 pass
4. 정부의 공공 데이터 가져오기
회원 가입 및 서비스 신청
주소 및 우편번호 가져오기
공공 데이터 포털(www.data.go.kr/ )에서 인증키 받기
- 접속 후 회원가입
- 회원가입 후 로그인
- 데이터 찾기에서 '도로명주소조회' 검색
- 활용신청(심의 승인의 경우 오랜 시간이 걸릴 수 있으므로 주의)
- 마이페이지에서 인증키 확인 및 참고문서 다운로드
import requests API_KEY = 'KEY' # 자신의 인증키를 복사해서 입력합니다. API_KEY_decode = requests.utils.unquote(API_KEY) API_KEY_decode
req_url = "http://openapi.epost.go.kr/postal/retrieveNewAdressAreaCdService/retrieveNewAdressAreaCdService/getNewAddressListAreaCd" search_Se = "road" srch_wrd = "세종로17" req_parameter = {"ServiceKey":API_KEY_decode, "searchSe":search_Se, "srchwrd":srch_wrd} r = requests.get(req_url, params = req_parameter) xml_data = r.text print(xml_data)
dict_data = xmltodict.parse(xml_data) dict_data
adress_list = dict_data['NewAddressListResponse']['newAddressListAreaCd'] print("[입력한 도로명 주소]", srch_wrd) print("[응답 데이터에서 추출한 결과]") print("- 우편번호:", adress_list[0]['zipNo']) # 여러 개의 검색결과가 나온 경우, 리스트의 위치값[0]을 지정해줘야한다. print("- 도로명 주소:", adress_list[0]['lnmAdres']) print("- 지번 주소:", adress_list[0]['rnAdres'])
# 여러개의 검색 결과가 있을 경우 전부 프린트하기 위한 코드 (직접 수정) adress_list = dict_data['NewAddressListResponse']['newAddressListAreaCd'] print("[입력한 도로명 주소]", srch_wrd) print("[응답 데이터에서 추출한 결과]") for adres in adress_list: print("- 우편번호:", adres['zipNo']) print("- 도로명 주소:", adres['lnmAdres']) print("- 지번 주소:", adres['rnAdres']) print("-----------------------------------------------------------------")
'[플레이데이터]' 카테고리의 다른 글
[PlayData - Day 26] MySQL - DBMS 개요와 MySQL 설치 (0) 2023.01.30 [PlayData - Day 16] JAVA 시작하기, 변수와 타입 (0) 2023.01.13 [PlayData - Day 13] BeautifulSoup - 웹 스크레이핑(Web Scraping) (0) 2023.01.09 [PlayData - Day 12] 파이썬으로 엑셀 파일 다루기 (0) 2023.01.06 [PlayData - Day 11] Matplotlib - 데이터 시각화 (1) 2023.01.06