[selenium실습] 구글맵에서 미국 음식점 이름 크롤링 3
Python/DataCrawling

[selenium실습] 구글맵에서 미국 음식점 이름 크롤링 3

728x90

셀레니움

이번에는 "구글맵에서 미국 음식점 이름 크롤링 2"에서 설명한 코드의 전체코드를 업로드 한다.

혹시 전체 코드에 대한 더 상세한 설명이 필요하면 아래 링크를 참고해주세요.

https://zeuskwon-ds.tistory.com/65?category=1022463

 

[selenium실습] 구글맵에서 미국 음식점 이름 크롤링 2

셀레니움 이번에는 이전에 포스팅한 "구글맵에서 미국 음식점 이름 크롤링 1"에서 설명한 내용을 코딩해본다. 혹시 코드에 대한 내용을 파악하시려면 아래 링크를 참고해주세요 https://zeuskwon-ds.t

zeuskwon-ds.tistory.com

 

2. 미국 음식점 크롤링 전체코드 

#1단계 검색어로 매장이름 데이터 만들기
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 

#selenium에서 사용할 모듈 import
import time
import requests
from bs4 import BeautifulSoup
import re
import csv
import pandas as pd

def search_bulit():
    """
    구글맵 검색어 정의(지역 + 코드 + restaurants)
    """
    df = pd.read_csv('bayareazipcode.csv', encoding='utf-8')
    food_city = df['po_name']
    food_code = df['zip']
    food_state = df['state']
    search_name = []
    for i in range(len(food_city)):
            name = food_city[i] + " " + str(food_code[i]) + " Restaurants" 
            search_name.append(name)
    return search_name, food_code

def wait_input(driver):
    try:
        element = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CLASS_NAME, "tactile-searchbox-input"))
        ) #입력창이 뜰 때까지 대기
    finally:
        pass

def input_funtion(n,driver,search_name):
    print(search_name[n])
    search_box = driver.find_element_by_id("searchboxinput")
    search_box.send_keys(search_name[n])
    search_box.send_keys(Keys.ENTER) #검색창에 "Los Banos 93635 Restaurants" 입력

def main_search(number,food_names,food_codes,error_search,food_code,driver,search_name):
    #1차 100까지 2차 200
    for n in range(0, number):
        input_funtion(n,driver,search_name)
        time.sleep(5)
        while True:
            try:
                state = driver.find_element_by_id("ppdPk-Ej1Yeb-LgbsSe-tJiF1e").get_attribute('disabled')
            except:
                error_search.append(search_name[n])
                break
                
            if state != True:
                try:
                    #검색 결과로 나타나는 scroll-bar 포함한 div 잡고 스크롤 내리기
                    scroll_div = driver.find_element_by_xpath('//*[@id="pane"]/div/div[1]/div/div/div[2]/div[1]')
                    driver.execute_script("arguments[0].scrollBy(0,2000)", scroll_div)
                    time.sleep(0.9)
                    driver.execute_script("arguments[0].scrollBy(0,2000)", scroll_div)
                    time.sleep(0.9)
                    driver.execute_script("arguments[0].scrollBy(0,2000)", scroll_div)

    #                 name = driver.find_elements_by_class_name("NrDZNb")
                    #한 칸 전체 데이터 가져오기
                    elements = driver.find_elements_by_class_name('y7PRA')
                    for i in range(20):
                        try:
                            food_codes.append(food_code[n])
                            food_names.append(elements[i].text)
                        except:
                            break

                    next_button = driver.find_element_by_id('ppdPk-Ej1Yeb-LgbsSe-tJiF1e')
                    next_button.click()
                    print(food_names)
                    time.sleep(2.8)
                except:
                    break
            else:
                break
                
        try:
            driver.find_element_by_class_name("sbcb_a").click()
        except:
            pass

    return food_names, food_codes

def data_split(food_names,food_codes): # food_name 데이터를 필요한 정보만 저장하는 코드

    food_name, food_name_code, rating, reviews, dollar, address = [], [], [], [], [], []

    for i in range(len(food_names)):
        food_name.append(food_names[i].split('\n')[0])
        food_name_code.append(food_codes[i])
        if food_names[i].split('\n')[1] == 'No reviews':
            
            rating.append(' ')
            reviews.append(' ')
            dollar.append(' ')
        else:
            try:
                rating.append(food_names[i].split('\n')[1].split(' · ')[0].split('(')[0])
            except:
                try:
                    rating.append(food_names[i].split('\n')[1].split('(')[0])
                except:
                    rating.append(' ')
            try:
                reviews.append(food_names[i].split('\n')[1].split(' · ')[0].split('(')[1][:-1])
            except: 
                try:
                    reviews.append(food_names[i].split('\n')[1].split('(')[1][:-1])
                except:
                    reviews.append(' ')
            try:
                dollar.append(food_names[i].split('\n')[1].split(' · ')[1])
            except:

                dollar.append(' ')
        try:
            address.append(food_names[i].split('\n')[2].split(' · ')[1])
        except:
            address.append(' ')
    return food_names, food_name, food_name_code, rating, reviews, dollar, address

def datafram_make(food_name,food_name_code,rating, reviews, dollar, address):
    df = pd.DataFrame({
                        'food_name' : food_name,
                        'codezip' : food_name_code,
                        'rating' : rating,
                        'reviews' : reviews,
                        'dollar' : dollar,
                        'address' : address,
                        })
    df.to_csv('foodinfo_zeuskwon_200-끝.csv', encoding='utf-8-sig')
    df.to_csv('H:\\내 드라이브\\foodinfo_zeuskwon_200-끝.csv', encoding='utf-8-sig')

if __name__ == "__main__":

    search_name,food_code = search_bulit() #매장이름, zipcode 데이터 불러오기

    #언어변경
    # 옵션 생성
    options = webdriver.ChromeOptions()

    # 옵션 추가
    options.add_argument("--lang=en-GB")
    options.add_argument('disable-gpu') # GPU를 사용하지 않도록 설정
    options.add_argument('headless')

    # 브라우저 옵션을 적용하여 드라이버 생성
    driver = webdriver.Chrome('chromedriver.exe', options=options) 

    link = 'https://www.google.com/maps'

    driver.get(link)

    wait_input(driver) #검색창 나올때까지 기다리기
    
    # driver , link = selenium_setting() # selenium사용을 위한 셋팅

    number = len(search_name) # 검색할 데이터 수 

    food_names,food_codes,error_search = [], [], [] # 음식점 이름 저장
    food_names, food_codes = main_search(number,food_names,food_codes,error_search,food_code,driver,search_name)
    food_names, food_name, food_name_code, rating, reviews, dollar, address = data_split(food_names,food_codes) # 이름저장한거 가져와서 데이터 가공하기 
    datafram_make(food_name,food_name_code,rating, reviews, dollar, address)
    driver.quit()

지금 코드에서는 number = len(search_name)으로 처음부터 끝까지 데이터(약 300개)를 한번에 크롤링 하는데 생각보다 시간이 오래걸리기 때문에 나는 100개씩 끊어서 사용했다.

만약 100개씩 하고싶을때는 main_search에 있는 for반복문의 범위를 조절하면 된다.

저장되는 csv파일이름을 수정 필요 (ex food_name_0-100.csv)

최종데이터

최종 데이터는 이렇게 만들어진다. 

최종 데이터가 생각보다 많았다. (약 10만개)

하지만 중복되는 데이터를 삭제하니 약 2만개 정도 데이터가 남았다.

(데이터 전처리는 주피터노트북으로 실시)

그리고 이 데이터를 구글맵에 food_name + address로 검색해서 나오는 상세주소를 크롤링 했다.

이 상세코드 크롤링도 추후 포스팅 예정이다.

 

*주의

내 코드를 그대로 실행해보는 경우 현재는 오류없이 잘 되지만 시간이 지나면 class_name이 계속 변경되기 때문에 오류가 나거나 데이터가 안들어갈 수 있음

그럴 경우 element에 접근하는 코드를 수정해보는것을 추천한다.

(class_name, id, xpath, css_selector)

만일 해봐도 안될 경우 댓글, 코드적으로 궁금한 부분도 댓글

728x90