교보문고 크롤링

  • 교보문고 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].text

2. 책 가격 가지고 오기

  • 책 가격을 가져오기전 생각해봐야하는 것들

    • 어차피 책 제목, 가격, 저자는 for문을 통해서 가지고 올 것이다.
    • 그렇다면 같이 돌려야하기 때문에 rows를 통해서 같이 돌려주면 편하다.
    • 그리고 rows는 한 칸의 책 제목, 책 저자, 책 가격을 담고 있기 때문에 편하다.
  • 책 가격을 for문을 통해 전부 출력하기

for i in range(len(rows)):
    price = rows[i].find('span', class_ = 'price').find('span', class_ = 'val').text

3. 책 저자 가져오기

  • 미션

    • 책 저자가 한명 이상인 경우가 있으므로 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. 최종본 만들기

400*400

  • url을 함수 밖으로 꺼내서 사용한다
    • url을 매개변수로 사용하여 함수를 사용한다.
  • page를 쓰기 위해 for문을 사용한다.
    • for문의 range값이 page 숫자가 된다.
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_resDataFrame으로 만들어 본다면
temp_df = pd.DataFrame(dict_res)
temp_df

  • page마다 데이터가 초기화되어 새로 받기 때문에 저장할 공간이 필요하다.
  • 이를 kyobo_dict가 역할 수행을 한다.

  • 이후 kyobo_dictDataFrame으로 바꾸게 되면
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()