네이버 지도 방문자 리뷰 스크래핑하기 #1 | 지독한 대기업... 취업으로 혼쭐내주러 갑니다🔥(제발)

BLO·2022년 10월 19일
0
post-thumbnail

참고 사이트👀
https://jenn1won.tistory.com/15

📄 리뷰 가져오고 싶은 상호명 리스트화

원래는 코드로 짜서 상호명을 가져오고 싶었는데,
일단 리뷰를 가져올 수 있는 지 확인하는 게 우선이라...

한 팀원분이 LISTLY 확장 프로그램으로 열심히 만들어 주셨다.
지금은 그 파일을 활용해서 방문자 리뷰를 먼저 가져와보겠다.
(상호명, 리뷰수 가져오는 것은 다음 게시글에 작성 예정)

참고로, 결과물은 이런 식으로 출력된다.

🔎 주피터에 불러와서 url 만들기

상호명을 pandas 로 불러온 후,
상호명을 주소 사이에 끼워넣어서 일반 map에 검색한다.
그렇게 열린 페이지 주소의 고유번호를 가져온다.

네이버의 치밀함 덕분에...
일반적으로 검색해서 나오는 url은
나중에 리뷰 크롤링할 때 안 먹는다고 한다.

위 방법을 통해 크롤링 시도가 가능한 pcmap 주소로 가공하는 와중,
일부 데이터는 주소가 만들어지지 않아 none 으로 뜨곤 했다.

심지어 어떤 때는 되는데, 어떤 때는 안되는 애매한 상황이었다.

내가 처음부터 짠 게 아니라 좀 당황스러웠는데,
이 코드 짜신 분의 블로그를 보니

검색했을 때 매장이 두개 이상 뜨면 none 처리를 했다.

라고 적혀있어서 최대한 구체적으로 검색을 하는 방법으로 접근했다.
물론 컴퓨터 말고 내가 스스로...ㅎㅎ

원래 이름에는 없지만 뒤에 도로명 주소나 지역명, 혹은 "빵집"을 붙였다.
검색하면 한 번에 그 매장이 나올 수 있도록!

이 방법으로 대부분의 url은 획득했다.
하지만 여전히 안 되는 항목이 존재했는데,
그건 time.sleep()의 시간을 늘려주면 해결된다.

💻 방문자 리뷰 가져오기

우리가 필요한 데이터는 리뷰 내용 데이터 뿐이기 때문에,
위 블로그에서 사용한 작성자 ID, 이미지 등을 긁어오는 코드는 싹 지웠다.

그리고 셀렉터 이름이나 태그 이름이
내 컴퓨터 상황과 달라서 그것도 하나하나 수정해주었다.

참고로 네이버가 스크래핑 막으려고(아마)
셀렉터 이름 등을 지속적으로 바꾼다고 한다.
참 지독하다^^

수정 후 돌리고 있는데 새삼 오래 걸리더라...
리뷰가 많은 매장은 거의 리뷰가 몇 천개라서
더보기 버튼을 누르고 로딩되는 데 시간이 걸리니 당연하지 하며
일단 얌전히 기다려보았다.


하지만 나는 한국인👎
기다리다 못 참아서 결국 일시중지를 했다.

어차피 샘플 스크래핑이니 리뷰 나오는지만 보자! 해서
while문에 조건을 걸어서 가져올 리뷰 수를 조정해 주었다.

더보기 한 번당 10개 게시글이 나오니 50개만 뽑자는 마음으로!

돌리기 전에는 모두 똑같이 50개씩 나올 줄 알았는데
리뷰 게시글 길이가 달라서 그런지
가져와지는 리뷰 개수가 들쭉날쭉하더라.

그러면 데이터프레임 만들 때 오류가 나서,
가장 적은 개수에 맞춰서 리뷰 수를 조정했다.

내 경우에는, 최소 40개는 나오길래 40개씩 잘라서 넣어주었다.
(200개 아님 40개임)

마지막으로 결과 데이터프레임은
매장이름을 컬럼명으로, 리뷰들을 아래 value로 넣어서 만들었다.

이 때, copy() 해서 넣어야 리스트를 리셋했을 때
데이터프레임 안의 리스트도 사라지는 불상사를 막을 수 있다.

마지막으로 결과 데이터프레임을 엑셀로 내보내면 끝!

✔ 사용코드

import pandas as pd
import selenium
from selenium import webdriver
from selenium.webdriver.common.keys import Keys 
from selenium.common.exceptions import NoSuchElementException 

from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

import time
import re
from bs4 import BeautifulSoup 
from tqdm import tqdm
df = pd.read_excel('[상호명파일].xlsx') 
df['naver_map_url'] = ''
chrome_options = webdriver.ChromeOptions()
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
for i, keyword in enumerate(df['검색어'].tolist()): 
    
    print("이번에 찾을 키워드 :", i, f"/ {df.shape[0]} 행", keyword) 
    
    try: 
        naver_map_search_url = f'https://map.naver.com/v5/search/{keyword}/place' # 검색 url 만들기 
        driver.get(naver_map_search_url)
        time.sleep(7)

        cu = driver.current_url
        res_code = re.findall(r"place/(\d+)", cu)
        final_url = 'https://pcmap.place.naver.com/restaurant/'+res_code[0]+'/review/visitor#' 
        
        print(final_url)
        df['naver_map_url'][i]=final_url 
        
    except IndexError: 
        df['naver_map_url'][i]= ''
        print('none')
        from lxml import etree
from selenium.webdriver.common.by import By

df_result=pd.DataFrame()

for i in range(len(df)): 
    review_list= []
    
    print('======================================================')
    
    # url 접속
    driver.get(df['naver_map_url'][i]) 
    thisurl = df['naver_map_url'][i]
    time.sleep(2) 
    
    # 더보기버튼 5번
    num=0
    while num<5:
        try: 
            time.sleep(1) 
            driver.find_element(By.TAG_NAME, 'body').send_keys(Keys.END)
            time.sleep(3) 
            
            driver.find_element(By.CSS_SELECTOR, '#app-root > div > div > div > div:nth-child(7) > div:nth-child(2) > div.place_section.lcndr > div.lfH3O > a').send_keys(Keys.ENTER) 
            time.sleep(3) 
            driver.find_element(By.TAG_NAME, 'body').send_keys(Keys.END) 
            time.sleep(1) 
            num += 1
            
        except NoSuchElementException: # 지금은 사용X
            print('-더보기 버튼 모두 클릭 완료-') 
            break 
    

    # 파싱
    html = driver.page_source 
    soup = BeautifulSoup(html, 'lxml') 
    time.sleep(1) 
    
    # 식당 이름, 구분, 총 개수 출력
    restaurant_name = df['검색어'][i]
    print('식당 이름 : '+restaurant_name)

    
    try: 
        restaurant_classificaton = soup.find_all('span',attrs = {'class':'DJJvD'})[0].text 
    
    except: 
        restaurant_classificaton = 'none'
    
    print('식당 구분 : '+restaurant_classificaton)
    print('----------------------------------------------')
    
    try: 
        one_review = soup.find_all('div', attrs = {'class':'ZZ4OK IwhtZ'})
        review_num = len(one_review) # 특정 식당의 리뷰 총 개수 
        print('리뷰 총 개수 : '+str(review_num)) 
        
        # 리뷰 40개 모으기
        for i in range(40):
            
            try: 
                review_content = one_review[i].find('span', attrs = {'class':'zPfVt'}).text
                review_list.append(review_content)
            except:
                review_content = "" 
            print('리뷰 내용 : '+review_content) 
            
      
    except NoSuchElementException: 
        none_review = "네이버 리뷰 없음" 
        print(none_review)
        review_num = 0 
        
    # 데이터 프레임 만들기
    df_result[f"{restaurant_name}"] = review_list.copy()
    
    df_result.to_excel('리뷰모음.xlsx')

0개의 댓글