맛집 추천시스템을 위한 프로젝트를 진행하며
추천을 위해 필요한 정보를 네이버 지도로부터 얻고자 했습니다.
아래 블로그의 코드를 참고했고, 지피티가 정말 많은 것을 도와줬습니다 :)
[Python] 네이버 플레이스(naver place) 리뷰 크롤링
지난 번 네이버 플레이스를 통해 크롤링을 해봤는데,이번에는 리뷰를 가져오는 코드를 실습해보았다. 특히 수집된 데이터를 다시 자연어 처리해 다른 분석을 해볼 때도 유용할 것 같다. 그리
jinooh.tistory.com
https://rkckskdk.tistory.com/297
네이버플레이스 후기 데이터 마이닝으로, 마케팅 방향 잡기 - (1) 웹크롤링
** (수정 2024.02.18.) 네이버 플레이스의 후기를 뽑아보고 싶다고 개인적으로 메일 주신 분들이 많았다. 그래서 플레이스 추출을 해드려서 보내드렸다. 생각보다 수요가 많아서, 정식적으로 내 홈
rkckskdk.tistory.com
환경 세팅하기
네이버 지도가 아닌 네이버 플레이스에서 리뷰를 크롤링하는 방식입니다.
네이버 지도
자동차/대중교통/자전거/도보 길찾기, 실시간 교통 및 버스위치, CCTV, 지하철, 버스노선, 거리뷰, 뮤지엄뷰 제공.
m.map.naver.com
모바일 버전 네이버 지도에 접속 ⇒ 가게명 검색 ⇒ 리뷰 탭 클릭 후 url 얻기
만약 최신순으로 리뷰를 크롤링하고 싶다면 url 마지막에 ?reviewSort=recent 붙이거나 최신순을 클릭하면 됩니다.
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
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from openpyxl import Workbook
import datetime
import time
# WebDriver 설정
options = Options()
options.add_argument("window-size=1920x1080")
service = Service(executable_path=ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=options)
driver.get("https://m.place.naver.com/restaurant/1008629511/review/visitor?reviewSort=recent")
driver.implicitly_wait(10)
라이브러리를 불러오고 WebDriver 설정을 해줍니다.
이 단계에서 이런저런 오류가 많이 났는데... 블로그 댓글과 챗지피티의 도움으로 어찌저찌 해결했습니다.
정확히 어떤 오류를 어떻게 해결했는지는 저한테 물어보셔도 유의미한 답을 드릴 수 없을 것 같네요 🥲
얻고자 한 정보
① 유저 닉네임 = nickname
② 리뷰 내용 (텍스트) = content
③ 방문 날짜 = date
④ 방문 횟수 = revisit
⑤ 리뷰 태그 = tags
⑥ 해당 유저의 리뷰 개수 = review_cnt
⑦ 해당 유저의 프로필 링크 = url
여기서 빨간색 글씨는 새로 코드를 추가해야 했던 부분입니다.
엑셀 파일 열기
# 엑셀 파일 설정
now = datetime.datetime.now()
xlsx = Workbook()
list_sheet = xlsx.create_sheet('output')
list_sheet.append(['nickname', 'content', 'date', 'revisit', 'tags', 'review_cnt', 'url'])
column을 위와 같이 구성하여 엑셀 파일을 만들어주는 코드입니다. 이제 더보기를 계속 눌러 페이지를 로드하고 데이터를 파싱해 엑셀 파일에 넣어주는 과정이 필요합니다.
전체 더보기 버튼 누르고 데이터 파싱하기 (+ 태그 더보기 버튼)
# 전체 더보기 버튼 클릭하여 모든 리뷰 로드
try:
while True:
try:
more_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, 'a.fvwqf'))
)
driver.execute_script("arguments[0].click();", more_button)
time.sleep(3) # 새로운 리뷰 로드 대기
except Exception as e:
print("No more pages to load:", e)
break
# 모든 페이지가 로드되었으므로, 이제 리뷰 데이터와 태그를 수집
reviews = driver.find_elements(By.CSS_SELECTOR, 'li.pui__X35jYm.EjjAW')
for r in reviews:
nickname = r.find_element(By.CSS_SELECTOR, 'span.pui__uslU0d').text.strip()
content = r.find_element(By.CSS_SELECTOR, 'div.pui__vn15t2').text.strip()
date = r.find_element(By.CSS_SELECTOR, 'span.pui__gfuUIT > time').text.strip()
revisit_elements = r.find_elements(By.CSS_SELECTOR, 'span.pui__gfuUIT')
revisit = revisit_elements[1].text.strip() if len(revisit_elements) > 1 else ''
review_cnt = r.find_element(By.CSS_SELECTOR, 'span.pui__WN-kAf').text.strip()
url = r.find_element(By.CSS_SELECTOR, 'a[href*="/my"]').get_attribute('href')
# revisit "번째 방문" 문자 제거
if revisit:
revisit = int(revisit[:-5])
# review_cnt "리뷰 " 문자 제거
if review_cnt:
review_cnt = int(review_cnt[3:])
# 태그 저장
i_tags = [tag.text.strip() for tag in r.find_elements(By.CSS_SELECTOR, 'div.pui__HLNvmI')]
i_tags = str(i_tags)
if "+" not in i_tags: # 태그 0개, 1개일 때
i_tag = [tag.text.strip() for tag in r.find_elements(By.CSS_SELECTOR, 'div.pui__HLNvmI')]
else: # 태그 2개 이상일 때
# 태그 더보기 버튼 누르기
tag_button = r.find_element(By.CSS_SELECTOR, 'a.pui__jhpEyP.pui__ggzZJ8')
driver.execute_script("arguments[0].click();", tag_button)
time.sleep(1)
# 태그 여러 개 잘라서 리스트에 저장
i_tag = [tag.text.strip() for tag in r.find_elements(By.CSS_SELECTOR, 'div.pui__HLNvmI span.pui__jhpEyP')]
# 중복 없이 리뷰 데이터 저장
list_sheet.append([nickname, content, date, revisit, ", ".join(i_tag), review_cnt, url])
except Exception as e:
print('Error:', e)
finally:
# Excel 파일 저장 및 드라이버 종료
file_name = f'naver_review_{now.strftime("%Y-%m-%d_%H-%M-%S")}.xlsx'
xlsx.save(file_name)
driver.quit()
print("Data collection completed and saved to Excel.")
태그 주소가 계속 바뀌기 때문에 만약 이 코드로 작동이 안 된다면 개발자 도구를 열어 바뀐 태그를 확인해야 합니다. 새로 추가한 항목 중 리뷰 개수나 프로필 링크는 어렵지 않게 코드를 작성할 수 있었는데, 리뷰 태그('커피가 맛있어요', ...)를 받아오는 게 쉽지 않았습니다.
태그를 바탕으로 유저의 성향을 파악하고자 했기 때문에 각 리뷰마다 유저가 남긴 태그를 받아야 했는데요.
태그를 2개 이상 선택했을 시, 태그 더보기 버튼을 눌러야 모든 태그가 보입니다.
따라서 태그 더보기 버튼을 눌러주는 코드를 추가해야 합니다.
코드를 돌려보면 결과가 엑셀 파일에 이렇게 잘 저장되는 것을 알 수 있습니다.
전체 코드
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
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from openpyxl import Workbook
import datetime
import time
# WebDriver 설정
options = Options()
options.add_argument("window-size=1920x1080")
service = Service(executable_path=ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=options)
driver.get("https://m.place.naver.com/restaurant/1008629511/review/visitor?reviewSort=recent")
driver.implicitly_wait(10)
# 엑셀 파일 설정
now = datetime.datetime.now()
xlsx = Workbook()
list_sheet = xlsx.create_sheet('output')
list_sheet.append(['nickname', 'content', 'date', 'revisit', 'tags', 'review_cnt', 'url'])
# 전체 더보기 버튼 클릭하여 모든 리뷰 로드
try:
while True:
try:
more_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, 'a.fvwqf'))
)
driver.execute_script("arguments[0].click();", more_button)
time.sleep(3) # 새로운 리뷰 로드 대기
except Exception as e:
print("No more pages to load:", e)
break
# 모든 페이지가 로드되었으므로, 이제 리뷰 데이터와 태그를 수집
reviews = driver.find_elements(By.CSS_SELECTOR, 'li.pui__X35jYm.EjjAW')
for r in reviews:
nickname = r.find_element(By.CSS_SELECTOR, 'span.pui__uslU0d').text.strip()
content = r.find_element(By.CSS_SELECTOR, 'div.pui__vn15t2').text.strip()
date = r.find_element(By.CSS_SELECTOR, 'span.pui__gfuUIT > time').text.strip()
revisit_elements = r.find_elements(By.CSS_SELECTOR, 'span.pui__gfuUIT')
revisit = revisit_elements[1].text.strip() if len(revisit_elements) > 1 else ''
review_cnt = r.find_element(By.CSS_SELECTOR, 'span.pui__WN-kAf').text.strip()
url = r.find_element(By.CSS_SELECTOR, 'a[href*="/my"]').get_attribute('href')
# revisit "번째 방문" 문자 제거
if revisit:
revisit = int(revisit[:-5])
# review_cnt "리뷰 " 문자 제거
if review_cnt:
review_cnt = int(review_cnt[3:])
# 태그 저장
i_tags = [tag.text.strip() for tag in r.find_elements(By.CSS_SELECTOR, 'div.pui__HLNvmI')]
i_tags = str(i_tags)
if "+" not in i_tags: # 태그 0개, 1개일 때
i_tag = [tag.text.strip() for tag in r.find_elements(By.CSS_SELECTOR, 'div.pui__HLNvmI')]
else: # 태그 2개 이상일 때
# 태그 더보기 버튼 누르기
tag_button = r.find_element(By.CSS_SELECTOR, 'a.pui__jhpEyP.pui__ggzZJ8')
driver.execute_script("arguments[0].click();", tag_button)
time.sleep(1)
# 태그 여러 개 잘라서 리스트에 저장
i_tag = [tag.text.strip() for tag in r.find_elements(By.CSS_SELECTOR, 'div.pui__HLNvmI span.pui__jhpEyP')]
# 중복 없이 리뷰 데이터 저장
list_sheet.append([nickname, content, date, revisit, ", ".join(i_tag), review_cnt, url])
except Exception as e:
print('Error:', e)
finally:
# Excel 파일 저장 및 드라이버 종료
file_name = f'naver_review_{now.strftime("%Y-%m-%d_%H-%M-%S")}.xlsx'
xlsx.save(file_name)
driver.quit()
print("Data collection completed and saved to Excel.")
오늘은 네이버 플레이스에서 가게별 리뷰를 크롤링하는 코드를 정리해 보았습니다.
다음 글에서는 유저별 리뷰를 크롤링하는 코드를 정리해볼 계획입니다.
* 질문이나 피드백 환영입니다!
'code' 카테고리의 다른 글
Python | 웹 크롤링 | 네이버 플레이스 리뷰 크롤링 (2) (22) | 2024.09.09 |
---|