7/11 학습일지 | 파이썬 네이버쇼핑 웹크롤링
class="adProduct_item__1zC9h"부트캠프에서 사전에 제공해준 강의를 들으면서 공부하고 있는데, 2022년 강의고 지금은 2024년... 또르륵
그래서 코드를 따라하면 그때는 됐지만, 지금은 안되는 부분들이 조금씩 있다. 특히 지금 애를 먹고 있는 웹크롤링같은 경우는 html 구조(?)가 달라져서 정말 어렵다. 일단 할 수 있는 데까지 해본 거라도 기록해보았다.
Q.
네이버 쇼핑에서 사과를 검색해서 1페이지에 나온 상품명과 가격을 가져와 저장하자. (원래 문제는 5페이지를 넘어가면서 전체 상품리스트의 이름, 가격, 구매건수, 찜, 리뷰숫자를 기록하는 것이였는데. 하다가 일단 한계에 부딪혀 일단 가격과 상품명까지만 했다.)
필요한 라이브러리를 먼저 불러와주기. 왜케 많아... (몇 가지는 하다가 중간에 넣은것들)
import requests
import bs4
import pandas as pd
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
from tqdm.notebook import tqdm
service = Service(ChromeDriverManager().install())
네이버 쇼핑에 들어가자, 팝업창 광고가 뜬다. 이걸 닫기를 눌러주지 않으면 검색을 할 수가 없다.
팝업창의 닫기 버튼을 확인하고, 주소를 넣은 뒤에 클릭을 누르게 한다.
driver = webdriver.Chrome(service=service)
driver.get("https://shopping.naver.com/home")
time.sleep(2)
#팝업창 버튼의 닫기 버튼을 클릭
popupclose=driver.find_element(By.XPATH, '//button[contains(@class, "_buttonArea_close_34bcm")]')
popupclose.click()
들어가면 팝업창(광고)이 뜨는데 닫기를 누르고 "사과"를 검색하고, 다시 클릭하게 한다. 네이버 쇼핑은 페이지가 한번에 다 로드되지 않고 스크롤을 끝까지 내리면 그 밑으로 다음 품목들이 뜨고, 다시 스크롤을 내리면 또 뜨고, 그런 형식이다. 그래서 스크롤을 끝까지 내리는 용도로 for scroll_down in range(7)을 써준다. 여기서 7은 임의로 정한 숫자인데 충분히 끝까지 내려갈 수 있을만큼으로 감으로 해보면 된다고.
#검색창에 사과 입력하고 클릭
time.sleep(2)
search_box=driver.find_element(By.CLASS_NAME, "_searchInput_search_text_3CUDs")
search_box.send_keys("사과")
search_box.send_keys(Keys.RETURN)
titles = []
prices = []
#스크롤 끝까지 내리기
for scroll_down in range(7):
driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')
time.sleep(2)
구조를 보면 상품을 보여주는 전체 박스는 class="basicList_list_basis__uNBZx" 에 담겨 있다. 그리고 개별적인 상품 하나하나에 대해서는 클래스가 두 가지 종류가 있는데, class="adProduct_item__1zC9h", class="adProduct_inner__W_nuz"(광고가 붙은 것)과 (광고가 붙지 않은 것) class="product_item__MDtDF", class="product_inner__gr8QR" 이렇게 4개가 있다.
강의에서는 광고 있는거랑 없는거랑 둘다 inner 부분이 똑같아서 그걸로 크롤링을 하는데, 2024년에는 그럴 수가 없는 듯.. 그래서 일단 광고 붙은 애들은 몇 개 없어서 광고 빼고 모으기로 했다.
list_basis = driver.find_element(By.CLASS_NAME, "basicList_list_basis__uNBZx")
item_list=list_basis.find_elements(By.CLASS_NAME, "product_inner__gr8QR")
items = []
for i in tqdm(range(len(item_list))):
item = item_list[i]
title= item.find_element(By.CLASS_NAME, "product_title__Mmw2K")
titles.append(title.text)
#'원'이랑 ','빼기
price = item.find_element(By.CLASS_NAME, 'price_num__S2p_v').text[:-1].replace(',', '')
prices.append(int(price)) #숫자로 바꿔서 저장
상품명과 가격을 가져오는 것까지는 괜찮았다.. 상품명은 똑같이 클래스이름 넣고 find_element를 하고, .text로 형식만 바꿔주면 됐다.
가격도 속해 있는 클래스를 넣고 텍스트로 받은 뒤에 마지막 글자는 지우고, 쉼표도 없앤다.
사실 여기까지는 강의 보면서 따라가면서 해서 문제가 없었는데, 그 다음부터가 진짜 고난이도 문제였다.
별점과 리뷰, 구매, 찜, 등록일 모두 product_etc_box__ElfVA 라는 클래스 안에 담겨 있다. 그런데 (광고 건 제외하더라도) 별점이 빠진 것, 구매건수가 빠진 것들이 있다. 찜과 등록일은 다 있다.
product_num__fafe5 안에
"("
"3.3만"
")"
1만
1,377
이 들어가 있고,
"(" "3.3만" ")" ->reviews
1만 -> buy_counts
1,377 -> favorites
에 넣어야하는데, 이게 reviews.append(convert_to_int(extramore[0:2].text))를 했을 때는 안된다.
일단 엉망진창이고 실행시켜봤는데, 제대로 값이 들어가지는 않았지만.. 일단 실행은 되는 코드를 올려놓는다.
extrabox = item.find_element(By.CLASS_NAME, "product_etc_box__ElfVA") # 이전 /
extramore= extrabox.find_elements(By. CLASS_NAME, "product_num__fafe5")
try:
if "별점" in extrabox.text:
star=item.find_element(By.CLASS_NAME, "product_grade__IzyU3").text
stars.append(float(star.split()[1])) #'별점\n4.45'에서 숫자만 추출
reviews.append(convert_to_int(extramore[0].text))
buy_counts.append(convert_to_int(extramore[1].text))
else:
reviews.append(convert_to_int(extramore[0].text))
buy_counts.append(convert_to_int(extramore[1].text))
except IndexError:
stars.append(int(0))
reviews.append(convert_to_int(extramore[0].text))
buy_counts.append(convert_to_int(extramore[1].text))
driver.quit()
투 비 컨틴뉴