교보문고 크롤링
- 교보문고 API를 통해서 데이터 받기
import requests as req
import urllib.parse
from bs4 import BeautifulSoup
# def kyobo_crawling(keyword):#, page):
keyword = "파이썬"
encrypt_word = urllib.parse.quote(keyword)
url = "https://search.kyobobook.co.kr/search?keyword="+ encrypt_word + "&target=total&gbCode=TOT&page=1"#{}".format(page)
req_header = {'user_agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'}
res = req.get(url)
html = res.text
soup = BeautifulSoup(html)1. 책 제목들 가져오기
title = soup.find('li',class_='prod_item').find('a', class_='prod_info').find_all('span')[-1].text- 간결하게
'li',class_='prod_item'에 대한 리스트 만든다 - for문 돌리며 title 나오게 하는 초석
rows = soup.find_all('li', class_ = "prod_item")
row = rows[0].find('a',class_ = 'prod_info').find_all('span')[-1].text
row- Output:
'파이썬 한권으로 끝내기: 데이터분석전문가(ADP) + 빅데이터분석기사 실기대비'
- 문제발생
rows를 출력했을 때 밑에 추천상품까지 뜨게 됨.
- 해결방법
- 추천상품에는
prod_list라는 class가 없는 것을 확인하여 고침
- 추천상품에는
rows = soup.find('ul', class_ = 'prod_list').find_all('li', class_= 'prod_item')- for문을 통해서 책 제목들 가져오기
for i in range(len(rows)):
row = rows[i].find('a', class_ = 'prod_info').find_all('span')[-1].text2. 책 가격 가지고 오기
-
책 가격을 가져오기전 생각해봐야하는 것들
- 어차피 책 제목, 가격, 저자는 for문을 통해서 가지고 올 것이다.
- 그렇다면 같이 돌려야하기 때문에
rows를 통해서 같이 돌려주면 편하다. - 그리고
rows는 한 칸의 책 제목, 책 저자, 책 가격을 담고 있기 때문에 편하다.
-
책 가격을 for문을 통해 전부 출력하기
for i in range(len(rows)):
price = rows[i].find('span', class_ = 'price').find('span', class_ = 'val').text3. 책 저자 가져오기
-
미션
- 책 저자가 한명 이상인 경우가 있으므로 list로 받아서 가져오기
-
문제 발생
author을 받을 때 1명이상인 것을 고려하여span태그에 있는class_='type'(저자(글)을 출력)의 갯수를 구하여 그 갯수만큼range()를 돌려author을 출력할려고 했다.- !! 여기서 문제 발생 !!
class_='type'의 갯수를 구할 때 for문을 돌려가며 그다음 갯수를 구할려고 했지만 오류가 뜸
-
해결 방법
- 나래 연구원님께서 그것의 상위 태그에서 불러오라고 하셨다.
- 하지만 상위 태그(
'div',class_='auto_overflow_inner')를 불러보니 책 제목도 출력이 됨 'div',class_='auto_overflow_inner'이 태그가 책 제목과 책 저자에 같은 이름으로 되어 있었다.- 연구원님이 첫번째 요소는 책 제목 두번째 요소는 책 저자로 해서 받으라고 하셨다.
for i in range(len(rows)):
temp_rows = rows[i].find_all('div', class_='auto_overflow_inner')
title = temp_rows[0].find('a',class_='prod_info').find_all('span')[-1]
author = temp_rows[1].find_all('a', class_='author')- 출력할 때 list comprehension을 써서 리스트로 만들고
','.join()을 이용해서 리스트를 없애고 출력하였다. 그 결과
for i in range(len(rows)):
temp_rows = rows[i].find_all('div', class_='auto_overflow_inner')
title = temp_rows[0].find('a',class_='prod_info').find_all('span')[-1]
author = temp_rows[1].find_all('a', class_='author')
price = rows[i].find('span', class_ = 'price').find('span', class_ = 'val').text
print(','.join([k.text for k in title]), price + "원", "\n", ','.join([x.text for x in author]), "\n")- 이런 방식이 있는 것을 참고!!!
4. 최종본 만들기

url을 함수 밖으로 꺼내서 사용한다url을 매개변수로 사용하여 함수를 사용한다.
page를 쓰기 위해 for문을 사용한다.- for문의
range값이page 숫자가 된다.
- for문의
for i in range(1, page+1):
url = "https://search.kyobobook.co.kr/search?keyword="+ encrypt_word + "&target=total&gbCode=TOT&page={}".format(i)dict_res라는 딕셔너리를 만들어서 함수 결과값으로 지정해놓는다.
dict_res = kyobo_crawling(url)kyobo_dict라는 빈 딕셔너리를 만든다.
kyobo_dict = {"title":[],"author":[],"price":[]}- 이후
dict_res에서 받은'title', 'author', 'price'키의value값을 for문을 돌려kyobo_dict에 넣어준다.
for i in range(1, page+1):
kyobo_dict["title"].extend(dict_res["title"])
kyobo_dict["author"].extend(dict_res["author"])
kyobo_dict["price"].extend(dict_res["price"])-
최종 목표는

-
'title'키에 그림과 같은 1, 2, 3 형식으로value값이 들어간다.
번외
-
혹시 내가 나중에 이해를 하지 못할까봐 적는다.
-
dict_res딕셔너리가 아니라kyobo_dict를 쓰는 이유- 이것은
dict_res를 출력해보면 이유를 알 수 있다. dict_res를DataFrame으로 만들어 본다면
- 이것은
temp_df = pd.DataFrame(dict_res)
temp_df
page마다 데이터가 초기화되어 새로 받기 때문에 저장할 공간이 필요하다.- 이를
kyobo_dict가 역할 수행을 한다.
- 이후
kyobo_dict를DataFrame으로 바꾸게 되면
kyobo_df = pd.DataFrame(kyobo_dict)
kyobo_df- 출력값

5. Extra Work(자료형 변환)
- 위의 데이터프레임을 쓸려면
'price'항목은int형으로 자료형이 되어있어야한다. - 하지만
kyobo_dict.info()를 사용하면object로 나오는 것을 확인할 수 있다.
kyobo_df.info()-
출력값

-
'price'의 자료형을int형으로 바꿔주기 위해'price'항목에 있는무료도서를 0으로 바꿔서int형으로 변환이 되도록 한다. -
replace()함수를 사용하여무료도서를 0으로 바꿔준다.
kyobo_df = kyobo_df.replace('무료도서','0')- 바뀐
kyobo_df의'price'항목의 데이터들을int형으로 바꿔준다.
kyobo_df['price'] = kyobo_df['price'].astype('int')- 이후
info()를 써서 출력되는 값을 보면int형으로 잘 변환된것을 알 수 있다.
kyobo_df.info()
최종코드
import requests as req
import urllib.parse
import pandas as pd
from bs4 import BeautifulSoup
# 함수
def kyobo_crawling(url):
temp_dict = {"title": [], "author": [], "price": []}
req_header = {'user_agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'}
res = req.get(url)
html = res.text
soup = BeautifulSoup(html)
# 책들의 항목을 나눠주었다.
rows = soup.find('ul', class_ = 'prod_list').find_all('li', class_= 'prod_item')
# title과 author의 값을 하나의 태그에서 나눠서 만들어줬다
# price는 .split(',')을 사용하여 숫자에 있는 ','를 없애주고 나중에 자료형 변환이 되기
# 쉽게 만들어주었다.
for i in range(len(rows)):
temp_rows = rows[i].find_all('div', class_='auto_overflow_inner')
title = temp_rows[0].find('a',class_='prod_info').find_all('span')[-1]
author = temp_rows[1].find_all('a', class_='author')
price = rows[i].find('span', class_ = 'price').find('span', class_ = 'val').text.split(',')
# 웹사이트에서 받는 데이터들을 temp_dict 딕셔너리에 넣어 저장한다.
temp_dict["title"].append(','.join([k.text for k in title]))
temp_dict["author"].append(','.join([x.text for x in author]))
temp_dict["price"].append(''.join(price))
return temp_dict
# 설정값
keyword = "파이썬"
encrypt_word = urllib.parse.quote(keyword)
page = 3
# 데이터프레임으로 만들 최종 딕셔너리를 만들어준다.
kyobo_dict = {"title":[],"author":[],"price":[]}
# 출력
# i가 1일때, url의 주소가 &page=1이 되고
# kyobo_crawling함수에 들어가 dict_res 딕셔너리에 저장해준다.
# 이후 만들어둔 빈 딕셔너리 kyobo_dict에 데이터를 받아둔 dict_res를 extend를 써서 저장한다.
# kyobo_dict에 넣어두는 이유는 dict_res는 페이지가 바뀔때마다 새로운 데이터를 받는다.
# 모든 데이터를 넣어줄 딕셔너리가 필요하고 이게 kyobo_dict의 이유이다.
for i in range(1, page+1):
url = "https://search.kyobobook.co.kr/search?keyword="+ encrypt_word + "&target=total&gbCode=TOT&page={}".format(i)
dict_res = kyobo_crawling(url)
kyobo_dict["title"].extend(dict_res["title"])
kyobo_dict["author"].extend(dict_res["author"])
kyobo_dict["price"].extend(dict_res["price"])
kyobo_dict
# DataFrame 만들기
kyobo_df = pd.DataFrame(kyobo_dict)
kyobo_df
# .info()를 사용하여 자료형 확인
kyobo_df.info()
# 무료도서 부분을 0으로 바꾸어 int 자료형을 받을 수 있게 한다.
# 무료도서 부분을 안바꿔준다면 자료형을 아무리 바꿔도 object로 남는다.
# 만약 바꿀시, float 자료형으로 남는다.
kyobo_df = kyobo_df.replace('무료도서','0')
# price 항목의 데이터들을 int형으로 바꿔준다.
kyobo_df['price'] = kyobo_df['price'].astype('int')
# 잘바뀌었나 확인용
kyobo_df.info()