학습 목표
- 웹 서비스 API에서 데이터를 가져오는 방법을 배웁니다.
- 웹 페이지를 웹 스크래핑하여 데이터를 가져오는 방법을 배웁니다.
웹 페이지를 전송하기 위한 통신 규약: HTTP
- 웹 사이트는 웹 페이지를 서비스하기 위해 웹 서버 소프트웨어를 사용
- 웹 서버 소프트웨어: 엔진엑스, 아파치
- 웹 서버는 웹 브라우저와 통신할 때 HTTP 프로토콜을 사용
- HTTP(Hyper Text Transfer Protocol): 인터넷에서 웹 페이지를 전송하는 기본 통신 방법
- HTTP 프로토콜을 사용해 API를 만드는 것이 웹 기반 API
웹 서버 -> 웹 데이터 요청(HTTP) -> 웹 브라우저
웹 서버 <- 웹 데이터 전송(HTML) <- 웹 브라우저
웹 페이지 문서: HTML
- HTML(Hypertext Markup Language)
- 웹 브라우저가 화면에 표시할 수 있는 문서의 한 종류
- 웹 페이지를 위한 표준 언어
- 마크업 언어로 태그(tag ex. < div >)를 이용해 표현
웹 기반 API
프로그램 A -> 데이터 요청(HTTP) -> 프로그램 B
프로그램 A <- 데이터 전송(CSV, JSON, XML) <- 프로그램 B
코드
{“키”: “값”}
d = {"name": "혼자 공부하는 데이터 분석"}
print(d['name'])
파이썬 객체를 JSON 문자열로 변환하기: json.dumps() 함수
- json.dumps()
- 파이썬 객체를 JSON 형식에 맞는 문자열로 바꿀 때 사용
- 아스키 문자 외의 다른 문자를 16진수로 출력
- 딕셔너리 d에 한글이 포함되어 있으므로 매개변수 ensure_ascii를 False로 지정하여 원래 저장된 문자 그대로 출력
- type()
- d_str 문자열이 객체인지 확인
code
import json d_str = json.dumps(d, ensure_ascii=False) print(d_str) print(type(d_str))
JSON 문자열을 파이썬 객체로 변환하기: json.loads() 함수
왜 파이썬 객체를 문자열로 바꾸어 전송하는가?
- 웹 기반 API가 사용하는 HTTP 프로토콜이 텍스트 기반이기 때문
- 직렬화(serialization): 프로그램 상의 객체를 저장하거나 읽을 수 있는 형태로 변환하는 것
- 역직렬화(deserialization): 직렬화된 정보를 다시 프로그램에서 실행 가능한 객체로 변환하는 것
code
d2 = json.loads(d_str) print(d2) print(d2['name']) print(type(d2))
딕셔너리
여러 항목을 가진 딕셔너리
code
d3 = json.loads('{"name": "혼자 공부하는 데이터 분석", "author": "박해선", \ "year": 2022}') print(d3) print(d3['name']) print(d3['author']) print(d3['year'])
한 키에 여러 항목이 들어간 딕셔너리
code
d3 = json.loads('{"name": "혼자 공부하는 데이터 분석", "author": ["박해선", "홍길동"], \ "year": 2022}') print(d3) print(d3['name']) print(d3['author']) print(d3['author'][1])
JSON 객체 여러 개를 가진 JSON 배열
- 세겹따옴표(""")를 사용하여 여러 줄에 걸친 문자열 만들기
code
d4_str = """ [ {"name": "혼자 공부하는 데이터 분석", "author": "박해선", "year": 2022}, {"name": "혼자 공부하는 머신러닝+딥러닝", "author": "박해선", "year": 2020} ] """ d4 = json.loads(d4_str) print(d4[0]['name'])
JSON 문자열을 데이터프레임으로 변환하기: read_json(), DataFrame() 함수
- read_json(): JSON 문자열을 읽어서 데이터프레임으로 변환
code
import pandas as pd pd.read_json(d4_str)
- DataFrame(): JSON 문자열을 파이썬 객체로 만든 다음 Data Frame 클래스 사용
code
pd.DataFrame(d4)
XML
- XML(eXtensible Markup Language)
- 엘리먼트(element)가 계층 구조를 이루면서 정보 표현
- 엘리먼트는 시작 태그와 종료 태그 사이에 위치
- 루트, 부모, 자식 엘리먼트가 존재
- 태그
- < 기호로 시작해서 > 기호로 끝남.
- 태그 이름은 영문자와 숫자를 이용
- 시작 태그와 종료 태그 이름이 같아야 함.
XML 문자열을 파이썬 객체로 변환하기: fromstring() 함수
code
x_str = """ <book> <name>혼자 공부하는 데이터 분석</name> <author>박해선</author> <year>2022</year> </book> """
- json 패키지는 JSON 문자열을 파이썬 객체로 변환하지만, fromstring() 함수가 반환하는 객체는 ElementTree 모듈 아래에 정의된 Element 클래스의 객체
import xml.etree.ElementTree as et book = et.fromstring(x_str) print(type(book))
- book 객체는 부모 엘리먼트 < book >에 해당
- book 객체의 tag 속성 출력
code
print(book.tag)
자식 엘리먼트 확인하기: findtext() 메서드
- XML 문서에서 추출하고 싶은 것을 결정
- 부모 엘리먼트의 자식 엘리먼트를 구한 다음, 각각의 자식 엘리먼트에 담긴 텍스트를 읽어보자.
- 부모 객체를 리스트로 변환하여 자식 엘리먼트를 구해본다.
code
book_childs = list(book) print(book_childs)
결과
[<Element 'name' at 0x798d42317380>, <Element 'author' at 0x798d42317290>, <Element 'year' at 0x798d423172e0>]
- 자식 엘리먼트를 각 변수에 할당하고 text 속성으로 엘리먼트에 있는 텍스트를 출력해본다.
- 단, XML은 자식 엘리먼트 순서를 보장하지 않는다는 점을 주의한다.
code
name, author, year = book_childs print(name.text) print(author.text) print(year.text)
- book 객체의 findtext() 메서드를 사용하여 자식 엘리먼트를 탐색하여 특정 변수에 특정 자식 엘리먼트를 지정하고, 해당 자식 엘리먼트의 텍스트를 반환할 수 있다.
code
name = book.findtext('name') author = book.findtext('author') year = book.findtext('year') print(name) print(author) print(year)
두개의 엘리멘트가 있는 XML 문서
code
x2_str = """ <books> <book> <name>혼자 공부하는 데이터 분석</name> <author>박해선</author> <year>2022</year> </book> <book> <name>혼자 공부하는 머신러닝+딥러닝</name> <author>박해선</author> <year>2020</year> </book> </books> """
- fromstring() 함수를 이용하여 부모 엘리먼트를 확인한다.
code
books = et.fromstring(x2_str) print(books.tag)
여러 개의 자식 엘리먼트 확인하기: findall() 메서드와 for 문
- 특히, 동일한 이름을 가진 여러 개의 자식 엘리먼트를 찾을 때 findall() 메서드와 for 문을 함께 사용하면 편리
code
for book in books.findall('book'): name = book.findtext('name') author = book.findtext('author') year = book.findtext('year') print(name) print(author) print(year) print()
read_json() 함수
- 판다스 read_json() 함수를 사용하면 JSON 문자열을 바로 판다스 데이터프레임으로 변환할 수 있음.
- read_xml() 함수를 사용하면 XML을 데이터프레임으로 변환할 수 있음.
- 판다스 1.3.0 버전부터 지원하는 기능
데이터 수집
- 도서관 정보나루 - 데이터 활용 - Open API 활용방법 - 이용절차
- 도서관 정보나루 - 데이터 활용 - Open API 활용방법 - API매뉴얼다운로드
- 매뉴얼 PDF 7쪽 - 3. 인기대출도서 조회
API를 호출하는 URL 작성하기
- 도서관 정보나루 공개 API를 사용하려면 호출 URL 필요
- 호출 URL과 파라미터
- 호출 URL: http://data4library.kr/api/loanItemSrch
- 파라미터
- format: 지정하지 않으면 XML 문서로 반환
- startDt: 검색시작일자
- endDt: 검색종료일자
- age: 연령대
- authKey: 인증키
- ATTP GET 방식
- 웹 브라우저가 웹 서버에 요청을 할 때 URL로 파라미터 값이나 데이터를 전달할 수 있음.
- 쿼리 스트링: ? 문자 뒤에 연결된 파라미터와 값으로 안전상 2,000자 이내 정도가 권장됨.
- 길이가 2,000자 이상인 경우 HTTP POST 방식이 권장됨.
- 조회할 값: 호출 URL?authKey=[발급받은키]&startDt=2022-01-01&endDt=2022-03-31&gender=1&age=20
API 인증키 발급하기
- 도서관 정보나루 사이트 로그인 - 마이페이지
- 인증키 정보 - 개인정보 수집 및 이용에 관한 안내 - 선택항목: 동의 / 사용목적: 기타 / 인증키 발급
- 인증키 복사 후 URL 마지막 authKey=이후에 붙여 넣어 호출 URL 완성
주소
http://www.data4library.kr/api/loanItemSrch?format=json&startDt=2021-04-01&endDt2021-04-30&age=20&authKey=인증키
파이썬으로 API 호출하기: requests 패키지
- requests 패키지: 파이썬에서 URL을 호출하여 데이터를 받을 수 있음.
- json() 메서드: 웹 서버로부터 받은 JSON 문자열을 파이썬 객체로 변환하여 반환
code
import requests url = "http://www.data4library.kr/api/loanItemSrch?format=json&startDt=2021-04-01&endDt2021-04-30&age=20&authKey=인증키" r = requests.get(url) data = r.json print(data)
+ JSON 말고 원본 데이터 받는 방법
- r.text(): 응답으로 받은 원본 텍스트를 담고 있음.
- r.content(): 응답으로 받은 데이터를 파이썬 바이트 객체로 제공
- r.status_code(): HTTP 상태 코드를 담고 있음.
ex. 404: 파일을 찾을 수 없음/ 200: 정상 응답
- colab 에서는 print 하지 않아도 JSON 출력을 들여쓰기해서 보여줌.
code
data
- data 딕셔너리 중 도서정보를 담고 있는 딕셔너리인 docs 딕셔너리를 확인
- data['response']['docs']에 매핑된 리스트를 순회하면서 doc 키에 매핑된 딕셔너리를 추출한 후 빈 리스트에 추가하기
code
books = [] for d in data['reponse']['docs']: books.append(d['doc']) books
- 혹은 리스트 내포 구문으로 books 만들기
code
books = [d['doc'] for in data['reponse']['docs']] books
- 판다스 DataFrame 클래스에 이 리스트를 넘김.
code
books_df = pd.DataFrame(books) books_df
- books_df의 내용을 JSON으로 변환하여 저장
code
books_df.to_json('20s_best_books/json')