[ PROJECT ] 카카오프렌즈샵 클론코딩 - #02 웹 크롤링이라 쓰고 web scraping이라 읽는다!

이 글을 다 작성하고, 크롤링 파일들을 이미 만들었거나, 완성 단계에 있는 그 상태에서

저작권 문제로 크롤링 금지!

라는 소리를 들었다.

물론 마음 속 한구석으로는 알고있었지만.. 팀 멘토님께 여쭤보니 카카오프렌즈샵 같은 경우는 워낙 카카오 캐릭터들이 카카오프렌즈샵의 핵심 아이덴티티이기 때문에 크롤링을 하지 않을 수 없다고 하셨다. (그래서 이 말을 듣고) 안된다는걸 알았지만 밀어붙였던거지...

아무튼, 그래서 오늘 탭 크롤링 파일은 아마 완성이었던 것 같은데
카카오 캐릭터, 카테고리에 따른 크롤링 파일은 미완성이었던 것 같다.
하지만 거의 다 만들어뒀는데 어떤 방식으로 크롤링을 진행할 것인지 결정하느라 더 코드를 작성하지 못한 것이었기 때무네
원하는 사람은 가져다가.. 코드 몇줄 더 적고 완성해서 돌려보세요.. 네..

이게 오픈소스인걸까.. 구려

아무튼, 기존에 실습해보았던 방식과, 내가 알지 못했던 방식으로 web scraping 진행해보기!


(python) selenium에서 xpath를 이용해 크롤링 하기
Web Scraping using Selenium and Python

기본적으로 사용했던 라이브러리는 BeautifulSoup4,Selenium!

이전에는 find_element_by_css_selector만을 사용해서, 페이지 이동없이
단일 페이지 내에서 카테고리의 개수를 통해 각 카테고리 내 음료들의 썸네일과 이름을 가져오는 실습을 했었다.

이번에는 WebElement라는 속성이 자주 나와서 get_attribute메서드를 통해 html 요소 내 속성을 가져오는 방법,
xpath를 사용한 find_element_by_xpath 메서드를 통한 방법 등을 통해서 진행했으며,
여러 페이지 간 이동, 버튼 클릭을 자유 자재로 진행해보았다.

개발이 늘 그랬듯이, 생각보다 크롤링의 세계는 너무 방대하고 신기한 메서드가 많았으며 하다보니까 정말 재미있어졌다.

(사실 수요일을 기준으로 더이상 크롤링은 하지 못하게 되었지만 계속 하고싶은 청개구리 심보가 생겼다 - 물론 하지는 않음)

추후에는 검색할 값을 입력한 뒤 버튼 클릭, 페이지 이동 등 모든 동작들을 실행하는 크롤링도 진행해보고 싶다.
프로젝트 진행에 있어서 크롤링이 주가 되면 안된다고 하셨는데, 요상하게 크롤링의 매력에 빠져버렸다.


메인페이지의 '오늘' 탭 스크랩하기

from bs4 import BeautifulSoup
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

import csv
import time

#1. csv file open
csv_name = "main_today.csv"
csv_open = open(csv_name, "w+", encoding="utf-8")
csv_writer = csv.writer(csv_open)
csv_writer.writerow(("profile_image", "name", "display_date", "image", "like_count", "title", "sub_copy"))


#2. Driver & BeautifulSoup
driver = webdriver.Chrome(ChromeDriverManager().install())

crawling_url = "https://store.kakaofriends.com/kr/index?tab=today"
driver.get(crawling_url)


#3. Parsing html code
full_html = driver.page_source
soup = BeautifulSoup(full_html, 'html.parser')
time.sleep(2)


#4. Get element selector (1)
articles = soup.select('#mArticle > main > div.today__Wrap-sc-1gh0i9h-0.fCbncI > article') 

#5. Get element selector (2)
for i in range(1, len(articles)+1):
    profile_image   = driver.find_element_by_css_selector(f'#mArticle > main > div.today__Wrap-sc-1gh0i9h-0.fCbncI > article:nth-child({i}) > section.header__Wrap-sc-1uyrtg9-0.hXrGqX > div.header__ImageWrap-sc-1uyrtg9-1.kmIBex > img')
    name            = driver.find_element_by_css_selector(f'#mArticle > main > div.today__Wrap-sc-1gh0i9h-0.fCbncI > article:nth-child({i}) > section.header__Wrap-sc-1uyrtg9-0.hXrGqX > div:nth-child(2) > p')
    display_date    = driver.find_element_by_css_selector(f'#mArticle > main > div.today__Wrap-sc-1gh0i9h-0.fCbncI > article:nth-child({i}) > section.header__Wrap-sc-1uyrtg9-0.hXrGqX > div:nth-child(2) > div > span.header__DisplayDate-sc-1uyrtg9-7.bbyqry')
    like_count      = driver.find_element_by_css_selector(f'#mArticle > main > div.today__Wrap-sc-1gh0i9h-0.fCbncI > article:nth-child({i}) > section:nth-child(2) > div.contents__LikeCountWrap-sc-1b0iw5u-2.fDHkJk > span > span > span')
    title           = driver.find_element_by_css_selector(f'#mArticle > main > div.today__Wrap-sc-1gh0i9h-0.fCbncI > article:nth-child({i}) > section:nth-child(2) > p')
    sub_copy        = driver.find_element_by_css_selector(f'#mArticle > main > div.today__Wrap-sc-1gh0i9h-0.fCbncI > article:nth-child({i}) > section:nth-child(2) > div.contents__SubCopy-sc-1b0iw5u-6.dLrCHR')

    images = soup.select(f'#mArticle > main > div.today__Wrap-sc-1gh0i9h-0.fCbncI > article:nth-child({i}) > section:nth-child(2) > div.media-slider__Wrap-bw8abp-0.ksgZQS > div > div > div')
    
    #6. Get image url
    for j in range(1, len(images)+1):
        image = driver.find_element_by_css_selector(f'#mArticle > main > div.today__Wrap-sc-1gh0i9h-0.fCbncI > article:nth-child({i}) > section:nth-child(2) > div.media-slider__Wrap-bw8abp-0.ksgZQS > div > div > div:nth-child({j}) > div > div > img')

        img_url = image.get_attribute('src')

        #7. Create csv file    
        if i == 0:
                csv_writer.writerow((profile_image.get_attribute('src'), name.text, display_date.text, img_url, like_count.text, title.text, sub_copy.text))
        else:
            csv_writer.writerow((profile_image.get_attribute('src'), name.text, display_date.text, img_url, like_count.text, title.text, sub_copy.text))

캐릭터 관련 스크랩하기

1. 캐릭터 썸네일, 이름 크롤링

import csv
import time

from bs4 import BeautifulSoup
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

#1. csv file open
csv_name = "character_type.csv"
csv_open = open(csv_name, "w+", encoding='utf-8')
csv_writer = csv.writer(csv_open)
csv_writer.writerow(('categorySeq','name')) 

#2. Driver & BeautifulSoup 
driver = webdriver.Chrome(ChromeDriverManager().install())

org_crawling_url = "https://store.kakaofriends.com/kr/index?tab=today"
driver.get(org_crawling_url)

#3. Parsing html code
full_html = driver.page_source
soup = BeautifulSoup(full_html, 'html.parser')

time.sleep(3)

#4. Get element selector (1)
hamburger_button    = driver.find_element_by_xpath('//*[@id="innerHead"]/div/button[2]').click()
time.sleep(2)
char_button         = driver.find_element_by_xpath('/html/body/div[6]/div/div/div/ul/li[3]/button').click()
time.sleep(2)
#char                = soup.selector(f'body > div:nth-child(7) > div > div > div > ul > li:nth-child(3) > ul > li > a')
char         = driver.find_elements_by_xpath('/html/body/div[6]/div/div/div/ul/li[3]/ul/li/a')

for i in char:
    character = i.get_attribute('href').split("categorySeq=",1)[1]
    name = i.text
    
    csv_writer.writerow((character, name))

driver.quit()

2. 캐릭터별 전체 상품목록 크롤링

import csv
import time

from bs4 import BeautifulSoup
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

#1. csv file open
csv_name = "character.csv"
csv_open = open(csv_name, "w+", encoding='utf-8')
csv_writer = csv.writer(csv_open)
csv_writer.writerow(('categorySeq','name')) 

#2. Driver & BeautifulSoup 
driver = webdriver.Chrome(ChromeDriverManager().install())

org_crawling_url = "https://store.kakaofriends.com/kr/index?tab=today"
driver.get(org_crawling_url)

#3. Parsing html code
full_html = driver.page_source
soup = BeautifulSoup(full_html, 'html.parser')
time.sleep(3)

#4. Get element selector 
#4-1. Get character list
hamburger_button    = driver.find_element_by_xpath('//*[@id="innerHead"]/div/button[2]').click()
time.sleep(2)
char_button         = driver.find_element_by_xpath('/html/body/div[6]/div/div/div/ul/li[3]/button').click()
time.sleep(2)
char                = driver.find_elements_by_xpath('/html/body/div[6]/div/div/div/ul/li[3]/ul/li/a')

char_list = []
for i in char:
    character = i.get_attribute('href').split("categorySeq=",1)[1]
    char_list.append(character)

#4-2. Get Product_num from main view
product_num = []        
for seq in char_list:
    url1 = "https://store.kakaofriends.com/kr/products/category/character?categorySeq="+ seq +"&sort=createDatetime,desc"
    driver.get(url1)
    full_html = driver.page_source
    soup = BeautifulSoup(full_html, 'html.parser')

    product_num += driver.find_elements_by_xpath('//*[@id="mArticle"]/div[3]/ul/li/a').get_attribute('href').split("products/",1)[1]   

print(product_num) 
    
    
    ㅁㅣ완성 area
    
    
#csv_writer.writerow((character, name))

#driver.quit()

캐릭터별 상품 상세조회는 결국 카테고리별 상품 상세조회 화면과 똑같기 때문에
바로 카테고리로 넘어갔다.


카테고리 관련 스크랩하기

1. 카테고리 목록 크롤링

import csv
import time

from bs4 import BeautifulSoup
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

#1. csv file open
csv_name = "type.csv"
csv_open = open(csv_name, "w+", encoding='utf-8')
csv_writer = csv.writer(csv_open)
csv_writer.writerow(('categorySeq','name')) 

#2. Driver & BeautifulSoup 
driver = webdriver.Chrome(ChromeDriverManager().install())

org_crawling_url = "https://store.kakaofriends.com/kr/index?tab=today"
driver.get(org_crawling_url)

#3. Parsing html code
full_html = driver.page_source
soup = BeautifulSoup(full_html, 'html.parser')

time.sleep(3)

#4. Get element selector
hamburger_button    = driver.find_element_by_xpath('//*[@id="innerHead"]/div/button[2]').click()
time.sleep(2)
char_button         = driver.find_element_by_xpath('/html/body/div[6]/div/div/div/ul/li[4]/button').click()
time.sleep(2)
#char                = soup.selector(f'body > div:nth-child(7) > div > div > div > ul > li:nth-child(3) > ul > li > a')
char         = driver.find_elements_by_xpath('/html/body/div[6]/div/div/div/ul/li[4]/ul/li/a')

del char[0]
for i in char:
    categorySeq = i.get_attribute('href').split("categorySeq=",1)[1]
    name        = i.text
    
    csv_writer.writerow((categorySeq, name))
driver.quit()

2. 상품 상세조회 크롤링


원래는 상품 목록대로 각 상품 id랑 썸네일 추출하려고했는데

생각해보니 상세조회 시 나오는 첫 사진 = 썸네일 이라서
그냥 카테고리별 상품 전체개수와 id들을 추출한 뒤, 추출해낸 상품 전체 리스트를 반복하며 url 뒷 부분만 바꿔가면서 상세조회 페이지 내 정보들을 크롤링 하려 했다.

import csv
import time

from bs4 import BeautifulSoup
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

#1. csv file open
csv_name = "category_all.csv"
csv_open = open(csv_name, "w+", encoding='utf-8')
csv_writer = csv.writer(csv_open)
csv_writer.writerow(('product_id','sub_category','content_name','price')) 

#2. Driver & BeautifulSoup 
driver = webdriver.Chrome(ChromeDriverManager().install())

org_crawling_url = "https://store.kakaofriends.com/kr/index?tab=today"
driver.get(org_crawling_url)

#3. Parsing html code
full_html = driver.page_source
soup = BeautifulSoup(full_html, 'html.parser')
time.sleep(3)

#4. Get element selector
#4-1. Get category list
hamburger_button    = driver.find_element_by_xpath('//*[@id="innerHead"]/div/button[2]').click()
time.sleep(3)
category_button     = driver.find_element_by_xpath('/html/body/div[6]/div/div/div/ul/li[4]/button').click()
time.sleep(3)
category            = driver.find_elements_by_xpath('/html/body/div[6]/div/div/div/ul/li[4]/ul/li/a')

del category[0]

category_list = []
for i in category:
    categorySeq = i.get_attribute('href').split("categorySeq=",1)[1]
    category_list.append(categorySeq)

#4-2. Get Product_num from main view
url1 = "https://store.kakaofriends.com/kr/products/category/subject?sort=createDatetime,desc"
driver.get(url1)
full_html   = driver.page_source
soup        = BeautifulSoup(full_html, 'html.parser')
time.sleep(3)

products = driver.find_elements_by_xpath('//*[@id="mArticle"]/div[3]/ul/li/a')

product_num = []      
for i in products:
    p_code = i.get_attribute('href').split("products/")[1]
    product_num.append(p_code)

#4-3. Get Product_detail from detail view
for i in product_num:
    url2        = "https://store.kakaofriends.com/kr/products/"+i
    driver.get(url2)
    full_html   = driver.page_source
    soup        = BeautifulSoup(full_html, 'html.parser')
    time.sleep(3) 
    
    script_text = driver.find_element_by_xpath("/html/body/script[2]").get_attribute('innerHTML')
    ### 이쯤부터 미완이었던거같다,....? ###
    print(script_text[script_text.find('{')-1 : script_text.find('}')+1])

#print(script_text)

#csv_writer.writerow(('product_id','sub_category','content_name','price'))
#driver.quit()

아 참고로 카카오 프렌즈샵은 개발자도구 elements 탭을 통해서 상품 정보를 파악할 수 있었다.

보통 보안때문에 이런거 안보여주려고 할 것 같은데, 별로 그렇게 중요한 내용이 아니어서 그랬는지..
무튼 덕택에 나는 script에서 해당 상품 관련한 정보를 보다 편하게 추출할 수 있었다.
script_text 변수가 해당 부분!!


여기까지가 몸소 체험한 날이었다..!! 무엇을? 이것들을 👇🏻👇🏻👇🏻

  1. xpath, css selector 메서드 활용
  2. web element는 어떻게 가공?
  3. 크롤링을 하기 위한 정보만 준비 되어있다면 수집하지 못할 정보는 없다

이 모든 것을 새벽에 다 끝내버리겠다고 불태웠지만
다음날 아침에 크롤링 금지 소리를 듣고.. 모든 의지를 잃어버린.. 그래서 미완성으로 남은.. 내 코드...

쓰려면 누가 가져다가 쓰세요.. (현타)
..난 위코드 다 끝나면 완성할래.. 하하핳

좋은 웹페이지 즐겨찾기