Yours Ever, Data Chronicles
[Python Crawling] 네이버 쇼핑 검색결과 크롤링하기 (2) - Selenium, BeautifulSoup 본문
[Python Crawling] 네이버 쇼핑 검색결과 크롤링하기 (2) - Selenium, BeautifulSoup
Everly. 2022. 11. 22. 06:26저번 포스팅에서는 Python selenium, beautifulsoup를 활용하여 네이버 쇼핑에서 '샤인머스캣'을 검색한 결과 중 제목을 뽑아오는 데에 성공했다.
이번 포스팅에서는 판매자, 가격, 등록일, 상품 URL 정보를 뽑아보자!
이번에 사용하는 방법도 아까 전에 사용한 방법과 크게 다르지 않다. 크롬 개발자모드로 들어가 html을 보면서 beautifulsoup(bs) 를 활용해 값을 하나씩 쏙쏙 뽑아오면 된다.
먼저 전체 상품 40개(1페이지에 있는 상품이 40개이므로)에 대한 정보를 담은 'goods_list'를 만든다.
이는 이전 포스팅에서도 나왔지만 전체상품 정보가 있는 html 클래스 이름이 li.basicList_item__0T9JD 이므로 사용해주었다.
soup = BeautifulSoup(driver.page_source, 'html.parser')
goods_list = soup.select('li.basicList_item__0T9JD')
1. 판매가격 긁어오기
판매가격 위에 마우스를 두면 해당 html 코드로 자동으로 이동한다.
위 캡쳐본을 보면 알겠지만 판매가격은 basicList_price__euNoD 라는 strong 클래스 안에 "판매가격"과 "배송비" 정보가 들어있다.
이 2가지 정보는 각각 다음의 클래스로 되어 있다. (직접 찾아보고 맞는지 확인해보자!)
- 판매가격: price_num__S2p_v
- 배송비: deliveryInfo_info_delivery__3DAnV
나는 여기서 판매가격 정보만 가져올 것이므로 첫번째 클래스만 쓴다. 다만 맨 앞단의 strong 클래스 안에 2개의 span이 존재하므로 첫번째 span에서의 가격 정보 "17,900원" 을 가져온다. 이 값은 텍스트이므로 간단하게 다음과 같이 써주면 된다.
for v in goods_list:
item_name = v.select_one('div.basicList_title__VfX3c > a').get('title')
item_price = v.select_one('strong.basicList_price__euNoD > span').text
2. 판매일(등록일) 긁어오기
다음으로는 등록일이다. 마찬가지로 마우스 커서를 가져가 html 코드를 확인해보자.
저 [리뷰], [등록일], [찜하기], [신고하기] 가 모두 같은 클래스인 basicList_etc_box__5lkgg로 묶여 있다.
그 중에서 나는 [등록일] 값만 가져올 것이다.
앞에서 가격정보를 긁었던 것과 마찬가지로 첫번째 span (클래스 basicList_etc__LSkN_)에 등록일 정보가 있으므로, 여기에 텍스트 값인 "2022.11."을 가져온다.
(참고로, 리뷰를 가져온다면 리뷰는 a 안에 있으므로 a 로 가서 리뷰개수를 긁어오면 되겠지?)
그런데 여기서 주의할 점이 있다.
바로 텍스트는 "등록일"과 "2022.11." 이렇게 2개가 모두 있다는 점! 그래서 그냥 text로만 가져온다면 다음과 같은 상황이 벌어진다.
위처럼 등록일과 날짜 모두가 같이 나온다.
그러므로 split 메서드를 활용해, 공백을 사이에 두고 두 문자열을 분리한 후 두번째 부분(날짜)만 가져온다.
for v in goods_list:
item_name = v.select_one('div.basicList_title__VfX3c > a').get('title')
item_price = v.select_one('strong.basicList_price__euNoD > span').text
item_date = v.select_one('div.basicList_etc_box__5lkgg > span').text.split(' ')[1]
3. 판매자 긁어오기
판매자 부분의 html을 확인하면 위와 같다.
조금 간단해 보인다. basicList_mall_title__FDXX5 클래스에 판매자명 정보가 있으므로, 이 클래스 내에서 정보를 가져온다.
여기서 a 클래스 밑에 img 클래스가 있는데, img 내의 'alt'에 "이마트몰" 이라는 판매자 정보가 쓰여 있다.
그럼 코드는 다음과 같이 짜면 될 것이다.
for v in goods_list:
item_name = v.select_one('div.basicList_title__VfX3c > a').get('title')
item_price = v.select_one('strong.basicList_price__euNoD > span').text
item_date = v.select_one('div.basicList_etc_box__5lkgg > span').text.split(' ')[1]
item_seller = v.select_one('div.basicList_mall_title__FDXX5 > a > img').get('alt')
하지만 이처럼 짜게 되면 크롤링을 하다가 중간에 에러가 나게 된다. 왜 그럴까?
그 이유는 판매자 정보가 좀 다르기 때문이다.
네이버쇼핑에서는 이마트몰, 신세계몰처럼 좀 큰 쇼핑몰에 대해서는 그냥 "이마트몰" 이라는 판매자명 정보를 넣어주는 게 아니라, 위의 케이스처럼 먼저 이미지를 넣고, 그 이미지에 대한 이름을 "이마트몰"로 써준다.
하지만 좀 작은 쇼핑몰에 대해서는 이렇게 판매자명 이미지를 넣어주지 않는다.
예시로, '델푸룻' 이라는 스마트쇼핑몰에 대해 html 코드를 보면 이와 같이 나온다.
이처럼 img 라는 클래스가 없이, 그냥 a 클래스 밑에 '델푸룻' 이라는 텍스트 정보가 있다.
그러므로 <img> 클래스가 있는 경우와 없는 경우를 나누어 크롤링해주는 코드를 짜야 한다.
for v in goods_list:
item_name = v.select_one('div.basicList_title__VfX3c > a').get('title')
item_price = v.select_one('strong.basicList_price__euNoD > span').text
item_date = v.select_one('div.basicList_etc_box__5lkgg > span').text.split(' ')[1]
if v.select_one('div.basicList_mall_title__FDXX5 > a > img') == None:
item_seller = v.select_one('div.basicList_mall_title__FDXX5 > a').text
else:
item_seller = v.select_one('div.basicList_mall_title__FDXX5 > a > img').get('alt')
4. 상품 페이지 URL 긁어오기
드디어 마지막이다! 이번에는 각 상품 페이지 내의 URL을 한 번에 긁어와보자.
이 부분은 딱히 어렵지 않다. 바로 직전 포스팅에서 상품명(title)을 긁어왔을 때 사용한 클래스 내에 'href' 라는 이름으로 URL 정보가 들어 있었기 때문!
그래서 우리는 네이버쇼핑에 "신선식품 최대 50% 행사" 라는 문구를 클릭하면 해당 상품 페이지로 바로 이동할 수 있었던 것이다.
또는 저 샤인머스캣 상품 이미지를 클릭해도 상품 페이지로 이동이 된다. 그래서 이 상품이미지에도 URL 정보가 들어있다. 여기서는 상품명을 통해 URL을 긁어보자.
for v in goods_list:
item_name = v.select_one('div.basicList_title__VfX3c > a').get('title')
item_price = v.select_one('strong.basicList_price__euNoD > span').text
item_date = v.select_one('div.basicList_etc_box__5lkgg > span').text.split(' ')[1]
if v.select_one('div.basicList_mall_title__FDXX5 > a > img') == None:
item_seller = v.select_one('div.basicList_mall_title__FDXX5 > a').text
else:
item_seller = v.select_one('div.basicList_mall_title__FDXX5 > a > img').get('alt')
item_URL = v.select_one('div.basicList_title__VfX3c > a').get('href')
마무리
이렇게 해서 크롬드라이버와 python selenium, beautifulsoup를 활용해 자동으로 '샤인머스캣' 네이버쇼핑 페이지에 접속하고, 리뷰많은순으로 상품을 정렬한 후 데이터를 수집해보는 코드가 마무리되었다.
이제는 전체 코드를 이어붙여, 직접 데이터를 크롤링해보자.
위의 코드로는 한 상품에 대한 정보만 가져올 수 있으므로, for문을 활용하여 각 상품에 대한 정보를 list에 차곡차곡 담아 list를 반환해보자.
(코드를 복사하려면 오른쪽 상단의 'Copy' 를 누르면 복사된다.)
# 정리
import time
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
import pandas as pd
# chromedriver 위치에서 코드작업 필수
chrome_options = Options()
driver = webdriver.Chrome(service=Service('경로/chromedriver'), options=chrome_options)
URL = 'https://search.shopping.naver.com/search/all?frm=NVSHATC&origQuery=%EC%83%A4%EC%9D%B8%EB%A8%B8%EC%8A%A4%EC%BC%93&pagingIndex=1&pagingSize=40&productSet=total&query=%EC%83%A4%EC%9D%B8%EB%A8%B8%EC%8A%A4%EC%BC%93&sort=review×tamp=&viewType=list'
driver.get(URL)
soup = BeautifulSoup(driver.page_source, 'html.parser')
goods_list = soup.select('li.basicList_item__0T9JD')
# list들
list_name = []
list_price = []
list_date = []
list_seller = []
list_img = []
list_url = []
for v in goods_list:
item_name = v.select_one('div.basicList_title__VfX3c > a').get('title')
list_name.append(item_name)
item_price = v.select_one('strong.basicList_price__euNoD > span').text
list_price.append(item_price)
item_date = v.select_one('div.basicList_etc_box__5lkgg > span').text.split(' ')[1]
list_date.append(item_date)
if v.select_one('div.basicList_mall_title__FDXX5 > a > img') == None:
item_seller = v.select_one('div.basicList_mall_title__FDXX5 > a').text
else:
item_seller = v.select_one('div.basicList_mall_title__FDXX5 > a > img').get('alt')
list_seller.append(item_seller)
item_URL = v.select_one('div.basicList_title__VfX3c > a').get('href')
list_url.append(item_URL)
driver.close()
마지막으로 만들어진 list들로 데이터프레임을 구성하면?
df = pd.DataFrame(
{
'상품명': list_name,
'가격': list_price,
'등록일': list_date,
'판매자': list_seller,
'상품 URL': list_url
}
)
df
쨘! 위와 같이 크롤링이 완료되었다 :)
하지만 부족한 부분이 있다. 나는 분명 네이버쇼핑의 1페이지 내 상품을 전체 긁어오려고 했는데, 1페이지 내의 상품은 총 40개가 있었다.
그런데 왜 결과는 5개만 긁어와진 것일까?
결론부터 말하자면 html의 로드 속도 때문이다. 그래서 직접 네이버쇼핑 페이지를 맨 밑으로 끌어내려 줘야 모든 상품에 대한 정보를 가져올 수 있다.
이 부분은 다음 포스팅에서 이어진다!
'Skillset > Data Engineering' 카테고리의 다른 글
[Airflow] Airflow에 Slack 연동하여 메시지 호출하기 (0) | 2025.01.06 |
---|---|
[Python Crawling] 크롤링 웹사이트 밑으로 내리기 - window height, scrollheight (1) | 2024.02.29 |
[Python Crawling] 네이버 쇼핑 검색결과 크롤링하기 (3) - 네이버 API 활용하기 (1) | 2024.02.29 |
[Airflow] DAG에 스케줄 거는 방법 (DAG schedule_interval Setting) (2) | 2024.01.08 |
[Python Crawling] 네이버 쇼핑 검색결과 크롤링하기 (1) - Selenium, BeautifulSoup (3) | 2022.11.21 |