본문 바로가기
코드리뷰/chatGPT(Python)코드

웹 크롤링 기초 - 네이버 쇼핑몰 상품 정보 추출하기

by 디마드 2024. 3. 24.

BeautifulSoup, Selenium을 이용해 네이버 쇼핑몰 상품 정보를 추출해 보자. requests는 처리속도는 좋지만 동적인 페이지 소싱이 어려워 Selenium을 이용한다. 

네이버 상품 정보를 추출하는 연습만으로 웹 크롤링 이해하는 데 크게 도움이 될 것이다. 제대로 익히면 다른 사이트 데이터 추출 역시 식은 죽 먹는 것처럼 쉬워질 것이다. 

1.네이버 쇼핑몰 화면 분석하자.

네이버 쇼핑몰에 노트북으로 검색한다. 상품 이미지, 상품명, 가격, 속성 등이 포함된 리스트가 나타난다. 

https://search.shopping.naver.com/search/all?query=노트북

개발자 도구(F12)를 열어 데이터 추출할 키를 찾는다. 

상품 리스트에 광고제품은 제외하자. class명이 광고와 일반상품을 구별하게 네이밍 되어있다. 친절하다.

2. 코드 작성하기

(1) 셀레니움 설정

from bs4 import BeautifulSoup
from selenium import webdriver
from seleniuhttp://m.webdriver.common.by import By
from seleniuhttp://m.webdriver.common.keys import Keys
from seleniuhttp://m.webdriver.chrome.options import Options

...

options = Options()
options.add_argument("--start-maximized")
options.add_argument("User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36")
options.add_experimental_option("detach",True)
options.add_experimental_option("excludeSwitches",["enable-logging","enable-automation"])

driver = webdriver.Chrome(options=options)
driver.get(url)

(2) 동적 데이터 가져오기 : 페이지다운이나 end키를 던져서 동적 데이터 추출한다. 

for i in range(3):
    # driver.find_element(By.TAG_NAME, "body").send_keys(Keys.END)
    driver.find_element(By.TAG_NAME, "body").send_keys(Keys.END)
    time.sleep(3)

(3) 데이터 추출

html = driver.page_source

soup = BeautifulSoup(html, 'html.parser')
# items = soup.select(".product_item_inner__EIIz_")
items = soup.select("[class^=product_item]")
for rank,item in enumerate(items,1) :
    # title = item.select_one(".product_info_tit__c5_pb")    
    title = item.select_one("[class^=product_title]")    
    price = item.select_one(".price")
    detail_box = item.select_one(".product_detail_box__QjZP8")
    print(f"{rank}위 : {title.text} {price.text} ")
    # print(detail_box.text)
    if detail_box:
        print(detail_box.get_text("  "))
    # try:
    #     print(detail_box.get_text("  "))
    # except:
    #     pass
    print()

아래는 같은 데이터를 추출한다. 첫 번째는 class 풀네임이고 둘째는 product_title로 시작되는 클래스명을 가져오게 하는 것이다. 이는 클래스명 뒷부분이 쉽게 변경되거나 자동으로 생성되는 경우를 대비한 코드다. 마치 sql의 like 쿼리 같다고 보면 이해하기 쉽겠다. 

# title = item.select_one(".product_info_tit__c5_pb")    
    title = item.select_one("[class^=product_title]")    

테스트 데이터에 구분 기호 넣기

클래스에서 가져온 데이터가 여러 태그로 나누어져 있다면, 아래처럼 구분 기호를 넣어 추출하자. 상품 속성 같은 특징을 잘 구별하게 해 준다. 다만 주의할 점은 해당 클래스가 없는 경우를 대비해 예외코드 또는 조건절을 넣어 주는 게 좋다. 

이런 식으로
 
 

말이다. 

if detail_box:
        print(detail_box.get_text("  "))

또는

try:
    print(detail_box.get_text("  "))
except:
    pass

(4) 추출 결과 확인하기

 

소스코드

from bs4 import BeautifulSoup
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
import time


keyword = input("검색할 제품을 입력하세요: ")

# url = f"https://msearch.shopping.naver.com/search/all?query={keyword}&vertical=search"
url = f"https://search.shopping.naver.com/search/all?query={keyword}"

options = Options()
options.add_argument("--start-maximized")
options.add_argument("User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36")
options.add_experimental_option("detach",True)
options.add_experimental_option("excludeSwitches",["enable-logging","enable-automation"])

driver = webdriver.Chrome(options=options)
driver.get(url)
time.sleep(1)

for i in range(3):
    # driver.find_element(By.TAG_NAME, "body").send_keys(Keys.END)
    driver.find_element(By.TAG_NAME, "body").send_keys(Keys.END)
    time.sleep(3)

html = driver.page_source

soup = BeautifulSoup(html, 'html.parser')
# items = soup.select(".product_item_inner__EIIz_")
items = soup.select("[class^=product_item]")
for rank,item in enumerate(items,1) :
    # title = item.select_one(".product_info_tit__c5_pb")    
    title = item.select_one("[class^=product_title]")    
    price = item.select_one(".price")
    detail_box = item.select_one(".product_detail_box__QjZP8")
    print(f"{rank}위 : {title.text} {price.text} ")
    # print(detail_box.text)
    if detail_box:
        print(detail_box.get_text("  "))
    # try:
    #     print(detail_box.get_text("  "))
    # except:
    #     pass
    print()
반응형

댓글