웹사이트는 웹 페이지 서비스를 위해 웹 서버 소프트웨어를 사용하는데, 이러한 웹 서버 프로그램은 웹 브라우저와 통신 시 HTTP란 프로토콜을 사용한다.
코드 출처 : 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 배열을 만들 수 있다. 또한 json.loads() 함수를 사용해 파이썬 객체(딕셔너리)로 변환할 수 있다.
d4_str = """
[
{"name": "혼자 공부하는 데이터 분석", "author": "박해선", "year": 2022},
{"name": "혼자 공부하는 머신러닝+딥러닝", "author": "박해선", "year": 2020}
]
"""
d4 = json.loads(d4_str)
참고로, 세겹따옴표(""")를 사용하면 긴 문자열을 줄바꿈하여 입력할 수 있다.
import pandas as pd
pd.read_json(d4_str)
아니면 파이썬 객체로 이미 벼환된 JSON 문자열에 DataFrame 클래스를 사용하는 방법도 있다.
pd.DataFrame(d4)
XML : eXtensible Markup Language 이며, 컴퓨터와 사람이 모두 읽고 쓰기 편한 문서 포맷을 위해 고안되었다.
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 속성을 출력하면 엘리먼트 이름을 쉽게 확인할 수 있다.
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문을 함께 사용한다.
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으로 변환해준다.
조회할 값은 호출 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 데이터를 자동으로 추출해주는 프로그램을 만들어보자.
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 파일로 저장하였다.
웹사이트의 페이지를 옮겨 가면서 데이터를 추출하는 작업을 웹 스크래핑(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 method를 사용한다면 행과 열을 조금 더 쉽게 선택할 수 있다. loc은 메서드이지만 대괄호를 사용하여 행과 열의 목록을 받는다.
books = books_df.loc[:, 'no':'isbn13']
위의 코드를 쳤을 때 똑같은 데이터프레임이 나온다. 파이썬의 slicing과 비슷한데, 마지막 항목도 포함된다는 점이 다르다. 그래서 step 또한 지정할 수 있다. (::2)
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이 출력된다.
웹 페이지나 웹 기반 API를 호출할 때 requests 패키지를 사용하는 것처럼, HTML 안에 있는 내용을 찾을 때는 뷰티풀수프(Beautiful Soup)가 널리 사용된다. Scrapy 같은 스크래핑 패키지도 있지만 코랩에 설치되어 있지 않다.
크롬 개발자 도구를 사용해 원하는 데이터, 즉 도서 상세 페이지 링크가 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')
prd_link = soup.find('a', attrs={'class':'gd_name'})
답 -> 4. df.loc[::2, 'col1':'col2']