[혼공학습단 11기] 혼자 공부하는 데이터 분석 with 파이썬 Ch 02

수빈·2024년 1월 14일
0

02-1 API 사용하기

API란

  • 데이터베이스 접근 권한에 문제가 있을 때 인증된 URL만 사용하여 데이터에 접근하는 방식.
  • API(Application Programming Interface)는 두 프로그램이 서로 대화하기 위한 방법을 정의한 것이다.
  • 예를 들어, 우리가 사용하는 윈도우 혹은 맥OS같은 운영체제는 문서 작성 프로그램이 디스크에 있는 파일을 읽고 쓸 수 있도록 API를 제공한다.
  • 기상청 제공 API를 사용하면 지역별 실시간 날씨 정보를 얻을 수 있다.

웹 페이지를 전송하기 위한 통신 규약 : HTTP

웹사이트는 웹 페이지 서비스를 위해 웹 서버 소프트웨어를 사용하는데, 이러한 웹 서버 프로그램은 웹 브라우저와 통신 시 HTTP란 프로토콜을 사용한다.

  • HTTP(Hyper Text Transfer Protocol)는 인터넷에서 웹 페이지를 전송하는 기본 통신 방법이다.
  • 웹 브라우저가 웹 서버에 웹 페이지를 HTTP 방식으로 요청하고, 웹 서버는 요청에 맞는 웹 페이지를 웹 브라우저에게 전송한다.
  • 웹 서버는 네이버 등의 웹사이트에서 운영하고, 웹 브라우저는 내 컴퓨터에 설치되어 있다.

웹 페이지 문서 : HTML

  • HTML(Hypertext Markup Language)은 웹 브라우저가 화면에 표시할 수 있는 문서의 한 종류이자, 웹 페이지를 위한 표준 언어이다.

CSV, JSON, XML

  • 웹 기반 API는 HTTP 프로토콜을 사용하지만 HTML을 주고받는 것이 아니라 일반적으로 CSV, JSON, XML 같은 텍스트 파일을 사용한다.
  • HTML 소스는 구조가 비교적 복잡하므로 상대적으로 단순한 구조를 가진 CSV, JSON, XML 등을 사용한다. 특히나 CSV보다는 JSON이나 XML이 다양한 구조를 생성할 수 있기 때문에 많이 사용된다.

파이썬에서 JSON 데이터 다루기

  • JSON은 마치 python의 dictionary와 list를 중첩해 놓은 것과 비슷하다.
    ex) {"name":"혼자 공부하는 데이터 분석"} 과 같이, 파이썬 딕셔너리와 잘 호환된다.
  • 웹 기반 API로 데이터를 전달할 때는 파이썬 딕셔너리가 아니라 텍스트로 전달해야 한다.

파이썬 객체를 JSON 문자열로 변환하기 : json.dumps()

코드 출처 : https://github.com/rickiepark/hg-da

import json
d = {"name": "혼자 공부하는 데이터 분석"}
d_str = json.dumps(d, ensure_ascii=False)

위의 코드를 실행하면 딕셔너리가 JSON 형식의 문자열로 바뀌게 된다.
ensure_ascii = False는 딕셔너리에 포함된 한글이 저장된 그대로 출력되도록 한다.

print(type(d_str))

위 코드를 실행하면 <class 'str'>이 나온다. 딕셔너리가 문자열로 바뀌었다는 뜻이다.

JSON 문자열을 파이썬 객체로 변환하기 : json.loads()

  • HTTP 프로토콜이 텍스트 기반이기 때문에 데이터를 전송할 때는 텍스트로 바꾸어 전송한다. 이러한 과정을 직렬화(serialization)라고 한다. 반대로, 직렬화된 정보를 다시 프로그램에서 실행 가능한 객체로 변환하는 과정을 역직렬화(deserialization)라고 한다.
  • deserialization 과정을 위해 json.loads() 함수를 사용, 문자열을 파이썬 딕셔너리로 다시 바꾸어준다.

여러 개의 항목이 들어 있는 딕셔너리나, 딕셔너리 안에 리스트를 포함할 수 있는지 알아보자.

아래와 같이 JSON 객체 여러 개를 대괄호 안에 나열하면, JSON 배열을 만들 수 있다. 또한 json.loads() 함수를 사용해 파이썬 객체(딕셔너리)로 변환할 수 있다.

d4_str = """
[
  {"name": "혼자 공부하는 데이터 분석", "author": "박해선", "year": 2022},
  {"name": "혼자 공부하는 머신러닝+딥러닝", "author": "박해선", "year": 2020}
]
"""
d4 = json.loads(d4_str)

참고로, 세겹따옴표(""")를 사용하면 긴 문자열을 줄바꿈하여 입력할 수 있다.

JSON 문자열을 데이터프레임으로 변환하기 : read_json()

import pandas as pd
pd.read_json(d4_str)


아니면 파이썬 객체로 이미 벼환된 JSON 문자열에 DataFrame 클래스를 사용하는 방법도 있다.

pd.DataFrame(d4)

파이썬에서 XML 데이터 다루기

XML : eXtensible Markup Language 이며, 컴퓨터와 사람이 모두 읽고 쓰기 편한 문서 포맷을 위해 고안되었다.

  • 엘리먼트들이 계층 구조를 이루며 정보를 표현한다. (태그로 감싸져있음)
  • 부모 엘리먼트 (혹은 부모 노드), 자식 엘리먼트 등으로 표현된다.

XML 문자열을 파이썬 객체로 변환하기 : fromstring()

x_str = """
<book>
    <name>혼자 공부하는 데이터 분석</name>
    <author>박해선</author>
    <year>2022</year>
</book>
"""

위의 코드를 실행해 XML 문자열을 x_str 변수에 저장한다. 세겹따옴표를 사용해 XML을 문자열로 만든다.

import xml.etree.ElementTree as et
book = et.fromstring(x_str)

XML 패키지는 XML 문서를 읽고 쓸 수 있는 간편한 API를 제공한다.
xml.etree.ElementTree 모듈의 fromstring() 함수를 사용해 x_str 문자열을 XML로 변환한다. fromstring() 함수가 반환하는 객체는 단순한 파이썬 객체가 아니라, ElementTree 모듈 아래에 정의된 Element 클래스의 객체이다.
실제로 type() 함수를 사용해서 확인해보면 book은 <class 'xml.etree.ElementTree.Element'>인 것을 확인할 수 있다.
그리고 book 객체는 x_str에서 가장 먼저 등장하는 부모 엘리먼트인 book tag에 해당한다. book.tag를 사용해 book 객체의 tag 속성을 출력하면 엘리먼트 이름을 쉽게 확인할 수 있다.

자식 엘리먼트 확인하기 : findtext()

book_childs = list(book)
name, author, year = book_childs
print(name.text)
print(author.text)
print(year.text)

위의 코드를 실행하면 각각의 엘리먼트에 있는 텍스트가 출력된다.
'혼자 공부하는 데이터 분석', '박해선', '2022'가 출력된다.
하지만 XML은 자식 엘리먼트의 순서가 항상 일정하다는 것을 보장하지 않는다. 위처럼 book_childs에서 순서대로 자식 엘리먼트를 찾는 것은 위험하다.
findtext() 메서드를 사용하면 해당하는 자식 엘리먼트를 탐색해 자동으로 텍스트를 반환할 수 있다.

name = book.findtext('name')
author = book.findtext('author')
year = book.findtext('year')
print(name)
print(author)
print(year)

findtext() 메서드에 찾으려는 태그 이름을 넣어주면 자동으로 해당하는 엘리먼트를 찾아 텍스트를 반환한다. 이 방식은 자식 엘리먼트의 순서가 어떻든지 상관없기 때문에 안전하다.


두 개의 book 엘리먼트가 있는 경우 또한 존재한다. 하지만 JSON과 달리 XML은 배열 같은 구조가 없다. book 엘리먼트들을 감싸는 또 다른 부모 엘리먼트를 만들어야 한다.

x2_str = """
<books>
    <book>
        <name>혼자 공부하는 데이터 분석</name>
        <author>박해선</author>
        <year>2022</year>
    </book>
    <book>
        <name>혼자 공부하는 머신러닝+딥러닝</name>
        <author>박해선</author>
        <year>2020</year>
    </book>
</books>
"""
books = et.fromstring(x2_str)
print(books.tag)

위의 코드를 사용해 books는 x2_str에서 가장 먼저 등장하는 부모 엘리먼트인 books에 해당한다는 것을 알 수 있다.

여러 개의 자식 엘리먼트 확인하기 : findall(), for문

동일한 이름을 가진 여러 개의 자식 엘리먼트를 찾을 때는 findall() 메서드와 for문을 함께 사용한다.

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()


이렇게 되면 books의 자식 엘리먼트를 모두 찾아 그 안에 담긴 텍스트들을 잘 출력했다고 할 수 있다.
+) read_json() 함수를 사용하면 JSON 문자열을 바로 DataFrame으로 변환할 수 있었듯이, XML도 read_xml() 함수를 사용하면 XML을 DataFrame으로 변환해준다.

API로 20대가 가장 좋아하는 도서 찾기

  • 도서관 정부나루에 접속해 OpenAPI 활용방법을 찾아본다. API 매뉴얼을 보니 연령별 데이터를 제공한다. 이를 사용한다.

API를 호출하는 URL 작성하기

조회할 값은 호출 URL 뒤에 파라미터를 연결하여 찾는다. 파라미터와 값은 = 문자로, 파라미터 사이는 & 문자로 연결한다. 호출 URL과 파라미터는 ? 문자로 연결한다. 이와 같은 방식을 HTTP GET 방식이라고 한다.

url = "http://data4library.kr/api/loanItemSrch?format=json&startDt=2021-04-01&endDt=2021-04-30&age=20&authKey=인증키"

위와 같은 방식으로 호출 URL을 만들고 마지막에 발급받은 API 인증키를 추가한다. 그리고 이 주소로 접속하면 API가 JSON 형태의 값을 반환하여 준다(format=json).
웹 브라우저를 사용하지 않고 JSON 데이터를 자동으로 추출해주는 프로그램을 만들어보자.

파이썬으로 API 호출하기 : requests 패키지

import requests
url = "http://data4library.kr/api/loanItemSrch?format=json&startDt=2021-04-01&endDt=2021-04-30&age=20&authKey=인증키"
r = requests.get(url)

위의 코드에서 url은 http get 방식으로 파라미터 값을 전달하기 때문에 URL을 requests.get() 함수에 전달한다.
get() 함수가 반환하는 값은 API 호출의 결과를 담고 있는 requests 패키지의 Response 클래스 객체이다.
이 객체에는 여러 메서드를 사용할 수 있는데, json() 메서드는 웹 서버로부터 받은 JSON 문자열을 파이썬 객체로 변환하여 반환한다.

data = r.json()
print(data)

결과값을 보면 브라우저에서 보았던 데이터와 받은 데이터가 일치하는 것을 알 수 있다.
근데 받은 JSON 데이터의 구조를 분석한 후, DataFrame으로 손쉽게 변환하기 위해 data dictionary의 구조를 아래와 같은 코드를 사용하여 바꾼다.

books = []
for d in data['response']['docs']:
    books.append(d['doc'])
books_df = pd.DataFrame(books)

books_df.to_json('20s_best_book.json')

이렇게 되면 구체적인 도서 정보들만 dictionary의 형태로 담긴 books라는 list가 만들어졌고, 이를 DataFrame으로 변환하였다는 것을 알 수 있다.
그리고 마지막에는 Dataframe을 to_json() 메서드를 사용해 JSON 파일로 저장하였다.

02-2 웹 스크래핑 사용하기

웹사이트의 페이지를 옮겨 가면서 데이터를 추출하는 작업을 웹 스크래핑(web scraping) 혹은 웹 크롤링(web crawling)이라고 부른다.

검색 결과 페이지 가져오기

먼저 20대가 가장 좋아하는 도서 목록을 사용한다. gdown을 사용해 코랩으로 다운로드한다.

import gdown
gdown.download('https://bit.ly/3q9SZix', '20s_best_book.json', quiet=False)

그리고 read_json() 함수를 사용해 JSON 데이터를 데이터프레임으로 가져온다.

import pandas as pd
books_df = pd.read_json('20s_best_book.json')

데이터프레임에서 특정 열들만 사용해서 새로운 데이터프레임을 만들어보겠다.

books = books_df[['no','ranking','bookname','authors','publisher',
                 'publication_year','isbn13']]

이렇게 되면 no, ranking, bookname, authors, publisher, publication_year, isbn13의 열들로만 이루어진 새로운 데이터프레임이 만들어진다.

데이터프레임 행과 열 선택하기 : loc 메서드

+) 판다스가 제공하는 loc method를 사용한다면 행과 열을 조금 더 쉽게 선택할 수 있다. loc은 메서드이지만 대괄호를 사용하여 행과 열의 목록을 받는다.

books = books_df.loc[:, 'no':'isbn13']

위의 코드를 쳤을 때 똑같은 데이터프레임이 나온다. 파이썬의 slicing과 비슷한데, 마지막 항목도 포함된다는 점이 다르다. 그래서 step 또한 지정할 수 있다. (::2)

검색 결과 페이지 HTML 가져오기 : requests.get() 함수

import requests
isbn = 9791190090018      # '우리가 빛의 속도로 갈 수 없다면'의 ISBN
url = 'http://www.yes24.com/Product/Search?domain=BOOK&query={}'
r = requests.get(url.format(isbn))

r.text()를 print 해보면 도서 검색 결과 페이지의 HTML이 출력된다.

HTML에서 데이터 추출하기 : BeautifulSoup

웹 페이지나 웹 기반 API를 호출할 때 requests 패키지를 사용하는 것처럼, HTML 안에 있는 내용을 찾을 때는 뷰티풀수프(Beautiful Soup)가 널리 사용된다. Scrapy 같은 스크래핑 패키지도 있지만 코랩에 설치되어 있지 않다.

크롬 개발자 도구로 HTML 태그 찾기

크롬 개발자 도구를 사용해 원하는 데이터, 즉 도서 상세 페이지 링크가 HTML 어디에 위치해 있는지를 알아보자.
크롬 개발자 도구를 연 후(F12) 도서 검색 결과 페이지 중 도서의 이름 위에 마우스 커서를 올리면 자동으로 개발자 도구에 HTML 위치가 나타난다. a 태그 안에 상세 페이지의 링크가 있음을 알아냈다.

뷰티풀수프 패키지에서 BeautifulSoup 클래스를 임포트하고, 클래스의 객체를 생성한다.
r.text는 parsing할 HTML 문서이고 두 번째는 parsing에 사용할 parser이다.
+) 여기서 parser란 입력 데이터를 받아 데이터 구조를 만드는 소프트웨어 라이브러리이다. 그리고 그러한 과정을 parsing이라고 한다. json 패키지, xml 패키지가 각각 JSON과 XML을 위한 parser이다. html.parser는 파이썬에 기본 내장된 HTML parser이다.

from bs4 import BeautifulSoup
soup = BeautifulSoup(r.text, 'html.parser')

태그 위치 찾기 : find() 메서드

prd_link = soup.find('a', attrs={'class':'gd_name'})

2주차 기본미션 : p. 150의 확인 문제 1번 풀고 인증하기

답 -> 4. df.loc[::2, 'col1':'col2']

profile
CS공부 하고 있는 수빈입니다.

0개의 댓글