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

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

728x90

셀레니움

이번에는 이전에 포스팅한 "구글맵에서 미국 음식점 이름 크롤링 1"에서 설명한 내용을 코딩해본다.

혹시 코드에 대한 내용을 파악하시려면 아래 링크를 참고해주세요

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

 

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

셀레니움 셀레니움을 사용해서 실제로 데이터를 가져오는 실습을 진행해보자 내용이 많을 수 있기 때문에 내용을 나눠서 포스팅한다 혹시 셀레니움이 처음이라면 먼저 셀레니움의 기본셋팅을

zeuskwon-ds.tistory.com

코드는 조각조각 나눠서 코드 설명하고 전체코드를 올리는 순서로 진행한다.

그리고 전체 코드는 기능별로 함수화 해서 __name__ == "__main__" 로 실행한다.

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 pandas as pd


# 옵션 생성
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)

미국 음식점 주소로 가져올거라서 언어를 영어로 설정하는 옵션을 추가함

 

▷ 검색할 목록 가져오기

구글맵에서 미국 특정 주(CA)의 음식점 정보를 검색할 것이기 때문에 검색할 데이터를 불러오는 코드를 작성한다. ( 자세한 설명은 이전 포스팅 참고)

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

pandas 라이브러리로 csv파일을 불러와서 food_city, food_code, food_state 정보를 저장해서 search_name 리스트에 food_name + food_code + "Restaurants" 형태로 넣어준다. (ex. Los Banos 93635 restaurant)

 

 검색어 입력창 확인

셀레니움에서 구글맵을 켰을때 네트워크 지연이나 컴퓨터 속도 때문에 로딩이 되는경우가 있는데 그 때 크롤링 코드가 실행되면 오류가 발생함

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

그래서 검색어 입력창 class_name이 찾아지면 입력창이 존재한다는 뜻이니까 크롤링코드가 정상적으로 실행된다.

 

 구글맵에서 입력창에 검색어 입력

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" 입력

위에서 만든 search_name을 불러와서 id값으로 입력창 element에 접근한다.

그리고 send_keys메서드로 search_name을 하나씩 입력하고 

Keys.ENTER로 enter버튼을 누른다.

그럼 위 사진처럼 검색어에 대한 음식점 목록 리스트가 출력 된다.

 

 음식점 정보 크롤링 메인 코드

이제 본격적으로 음식점 정보(이름, 별점, 리뷰수, 달러, 주소)를 긁어오는 코드를 작성한다.

def main_search(number,food_names,food_codes,error_search,food_code,driver,search_name):
    #for값으로 크롤링 개수 조절
    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)

                    #한 칸 전체 데이터 가져오기
                    elements = driver.find_elements_by_class_name('CJY91c-jRmmHf-aVTXAb-haAclf-HSrbLb')
                    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()
                    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

가장 먼저 스크롤을 내리고 20개 음식점 데이터를 가져와서

다음 버튼 클릭하는 과정을 마지막 페이지까지 반복

그러면 food_names데이터에 리스트 형식으로 음식점 정보가 들어감

 

데이터 나누는 코드

이 데이터들은 쉼표(,)로 1차 구분이 되고 다음 엔터(\n)로 구분된다.

데이터를 가져와서 우리는 필요한 데이터만 추출할 것이기 때문에 데이터를 나누는 코드가 필요하다.

(매장이름, 별점, 리뷰수, 달러, 주소)

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

food_name = 매장이름

food_name_code = 지역번호 

rating = 별점

reviews = 리뷰수

doller = 달러

address = 주소

리뷰와 별점이 없는 매장도 있기 때문에 없을 경우 공백(' ')을 입력하도록 예외처리를 해주었다.

 

데이터 로컬에 저장

내 필요에 맞게 가져온 데이터를 dataframe형식으로 변환해서 로컬에 csv 파일 형식으로 저장한다.

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.csv', encoding='utf-8-sig')

이 코드가 실행되면 로컬에 foodinfo_zeuskwon.csv라는 파일이 생긴다.

 

전체 코드는 다음 포스팅에서 업로드 하므로 궁금하면 아래 포스트 링크 누르면 확인가능하다.

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

 

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

셀레니움 이번에는 "구글맵에서 미국 음식점 이름 크롤링 2"에서 설명한 코드의 전체코드를 업로드 한다. 혹시 전체 코드에 대한 더 상세한 설명이 필요하면 아래 링크를 참고해주세요. https://zeu

zeuskwon-ds.tistory.com

728x90