728x90
셀레니움
이번에는 "구글맵에서 미국 음식점 이름 크롤링 2"에서 설명한 코드의 전체코드를 업로드 한다.
혹시 전체 코드에 대한 더 상세한 설명이 필요하면 아래 링크를 참고해주세요.
https://zeuskwon-ds.tistory.com/65?category=1022463
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
'Python > DataCrawling' 카테고리의 다른 글
[selenium] 크롤링 no such element 오류 해결 (6) | 2022.05.13 |
---|---|
[selenium실습] 구글맵에서 미국 음식점 이름 크롤링 2 (2) | 2022.05.13 |
[selenium실습] 구글맵에서 미국 음식점 이름 크롤링 1 (0) | 2022.05.12 |
[selenium]셀레니움 크롤링 데이터 가져오는 방법 정리 (0) | 2022.04.30 |
[selenium]셀레니움 크롤링 옵션 및 기능 - python (0) | 2022.04.30 |