일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- SQLD
- 클러스터링
- 히트맵
- Python
- da
- 프롬프트 엔지니어링
- 데이터 분석
- pandas
- 기초통계
- 팀프로젝트
- 시각화
- 데이터분석
- cross join
- 서브쿼리
- 크롤링
- jd
- data analyst
- If
- 최종 프로젝트
- 군집화
- lambda
- 머신러닝
- 태블로
- GA4
- streamlit
- Chat GPT
- SQL
- 프로젝트
- 전처리
- 기초프로젝트
Archives
- Today
- Total
세조목
최종 프로젝트 4일차(24.03.29) 본문
최종 프로젝트 4일차입니다.
금일은 어제에 이어 네이버 지도 리뷰 데이터 크롤링 코드 작성을 했습니다.
다행히 구글링을 통해 확인한 코드들을 조합하여 코드를 작성할 수 있었고,
결과값 확인까지 했습니다.
def switch_left():
############## iframe으로 왼쪽 포커스 맞추기 ##############
#driver.switch_to.parent_frame()
driver.switch_to.default_content()
iframe = driver.find_element(By.XPATH,'//*[@id="searchIframe"]')
driver.switch_to.frame(iframe)
def switch_right():
############## iframe으로 오른쪽 포커스 맞추기 ##############
#driver.switch_to.parent_frame()
driver.switch_to.default_content()
iframe = driver.find_element(By.XPATH,'//*[@id="entryIframe"]')
driver.switch_to.frame(iframe)
def page_down(num):
body = driver.find_element(By.CSS_SELECTOR, 'body')
body.click()
for i in range(num):
body.send_keys(Keys.PAGE_DOWN)
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.chrome.options import Options
from time import sleep
import random
import re
from selenium import webdriver
import sys
options = Options()
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_argument('window-size=1380,850')
driver = webdriver.Chrome(options=options)
# 대기 시간
driver.implicitly_wait(time_to_wait=3)
# 반복 종료 조건
loop = True
URL = 'https://map.naver.com/p/search/%EC%A2%85%EB%A1%9C%EA%B5%AC%20%EB%B9%B5?c=13.00,0,0,0,dh'
driver.get(url=URL)
while(True):
switch_left()
# 페이지 숫자를 초기에 체크 [ True / False ]
# 이건 페이지 넘어갈때마다 계속 확인해줘야 함 (페이지 새로 로드 될때마다 버튼 상태 값이 바뀜)
next_page = driver.find_element(By.XPATH,'//*[@id="app-root"]/div/div[2]/div[2]/a[7]').get_attribute('aria-disabled')
if(next_page == 'true'):
break
############## 맨 밑까지 스크롤 ##############
scrollable_element = driver.find_element(By.CLASS_NAME, "Ryr1F")
last_height = driver.execute_script("return arguments[0].scrollHeight", scrollable_element)
while True:
# 요소 내에서 아래로 600px 스크롤
driver.execute_script("arguments[0].scrollTop += 600;", scrollable_element)
# 페이지 로드를 기다림
sleep(1) # 동적 콘텐츠 로드 시간에 따라 조절
# 새 높이 계산
new_height = driver.execute_script("return arguments[0].scrollHeight", scrollable_element)
# 스크롤이 더 이상 늘어나지 않으면 루프 종료
if new_height == last_height:
break
last_height = new_height
############## 현재 page number 가져오기 - 1 페이지 ##############
page_no = driver.find_element(By.XPATH,'//a[contains(@class, "mBN2s qxokY")]').text
# 현재 페이지에 등록된 모든 가게 조회
# 첫페이지 광고 2개 때문에 첫페이지는 앞 2개를 빼야함
if(page_no == '1'):
elemets = driver.find_elements(By.XPATH,'//*[@id="_pcmap_list_scroll_container"]//li')[2:]
else:
elemets = driver.find_elements(By.XPATH,'//*[@id="_pcmap_list_scroll_container"]//li')
print('현재 ' + '\033[95m' + str(page_no) + '\033[0m' + ' 페이지 / '+ '총 ' + '\033[95m' + str(len(elemets)) + '\033[0m' + '개의 가게를 찾았습니다.\n')
for index, e in enumerate(elemets, start=1):
final_element = e.find_element(By.CLASS_NAME,'CHC5F').find_element(By.XPATH, ".//a/div/div/span")
print(str(index) + ". " + final_element.text)
print("-"*50)
switch_left()
sleep(2)
for index, e in enumerate(elemets, start=1):
store_name = '' # 가게 이름
category = '' # 카테고리
new_open = '' # 새로 오픈
rating = 0.0 # 평점
visited_review = 0 # 방문자 리뷰
blog_review = 0 # 블로그 리뷰
switch_left()
# 순서대로 값을 하나씩 클릭
#e.find_element(By.CLASS_NAME,'CHC5F').find_element(By.XPATH, ".//a/div/div/span").click() ← 원본
try:
e.find_element(By.CLASS_NAME,'ZUcHo').find_element(By.XPATH, ".//div/a").click()
sleep(2)
switch_right()
# 우측 프레임 스크롤 다운 & 더보기 버튼 클릭
for i in range(10):
page_down(8)
sleep(2)
driver.find_element(By.CLASS_NAME,'NSTUp').find_element(By.XPATH, ".//div/a/span").click()
sleep(2)
except:
e.find_element(By.CLASS_NAME,'ZUcHo').find_element(By.XPATH, ".//div/a").click()
sleep(2)
switch_right()
# 우측 프레임 스크롤 다운 & 더보기 버튼 클릭
for i in range(10):
page_down(8)
sleep(2)
driver.find_element(By.CLASS_NAME,'NSTUp').find_element(By.XPATH, ".//div/a/span").click()
sleep(2)
################### 여기부터 크롤링 시작 ##################
# 리뷰글 外 수집용
title = driver.find_element(By.XPATH,'//div[@class="zD5Nm undefined"]')
store_info = title.find_elements(By.XPATH,'//div[@class="YouOG DZucB"]/div/span')
# 리뷰글 수집용
#review_content = driver.find_element(By.XPATH,'//div[@class="place_section_content"]')
#real_reviews = review_content.find_element(By.XPATH,'//ul')
# 가게 이름
store_name = title.find_element(By.XPATH,'.//div[1]/div[1]/span[1]').text
# 카테고리
category = title.find_element(By.XPATH,'.//div[1]/div[1]/span[2]').text
if(len(store_info) > 2):
# 새로 오픈
new_open = title.find_element(By.XPATH,'.//div[1]/div[1]/span[3]').text
###############################
review = title.find_elements(By.XPATH,'.//div[2]/span')
# 인덱스 변수 값
_index = 1
# 리뷰 ROW의 갯수가 3개 이상일 경우 [별점, 방문자 리뷰, 블로그 리뷰]
if len(review) > 2:
rating_xpath = f'.//div[2]/span[{_index}]'
rating_element = title.find_element(By.XPATH, rating_xpath)
rating = rating_element.text.replace("\n", " ")
_index += 1
try:
# 방문자 리뷰
visited_review = title.find_element(By.XPATH,f'.//div[2]/span[{_index}]/a').text
# 인덱스를 다시 +1 증가 시킴
_index += 1
# 블로그 리뷰
blog_review = title.find_element(By.XPATH,f'.//div[2]/span[{_index}]/a').text
# 리뷰 내용
review_box = []
review_nums = driver.find_elements(By.CLASS_NAME,'owAeM')
for review_num in review_nums:
review_content = review_num.find_element(By.CLASS_NAME,'zPfVt').text
review_box.append(review_content)
except:
print('------------ 리뷰 없음 ------------')
try:
print(f'{index}. ' + str(store_name) + ' · ' + str(category) + str(new_open))
print('평점 ' + str(rating) + ' / ' + visited_review + ' · ' + blog_review)
print(review_box)
print("-"*50)
except:
print(f'{index}. ' + str(store_name) + ' · ' + str(category) + str(new_open))
print('------------ 리뷰 없음 ------------')
switch_left()
# 페이지 다음 버튼이 활성화 상태일 경우 계속 진행
if(next_page == 'false'):
driver.find_element(By.XPATH,'//*[@id="app-root"]/div/div[2]/div[2]/a[7]').click()
# 아닐 경우 루프 정지
else:
loop = False
그러나 네이버 지도에서 '더보기'를 클릭했을때 '거리뷰'가 함께 클릭되는 오류가 발생하고 있으며
지금 작성한 코드로는 한 가게에 대해 작성된 리뷰들이 하나의 리스트에 들어가서 출력되고 있으므로
오류 해결 및 리뷰들을 각각의 행에 저장하도록 코드를 수정해야합니다.
* 위에 작성한 코드에 대해서는 코드가 최종적으로 작성 완료된 후 하나 하나 뜯어보며 설명하겠습니다.
크롤링 코드 참조 블로그
1. https://baka9131.tistory.com/14
3. https://jinooh.tistory.com/89
4. https://dutchcoffee.tistory.com/30
5. https://jenn1won.tistory.com/15
'데이터 분석 공부 > 프로젝트' 카테고리의 다른 글
최종 프로젝트 6일차(24.04.01) (1) | 2024.04.01 |
---|---|
최종 프로젝트 5일차(24.03.31) (0) | 2024.03.31 |
최종 프로젝트 3일차(24.03.28) (0) | 2024.03.28 |
최종 프로젝트 2일차(24.03.27) (1) | 2024.03.27 |
실전 프로젝트 회고 (0) | 2024.03.13 |