여기까지 다뤄보았습니다.
이번에는 오류를 어떻게 수정하였는지, 추가적으로 작성된 코드는 무엇인지 작성해보겠습니다.
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
from urllib.parse import quote
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import re
import pandas as pd
def switch_frame(frame):
browser.switch_to.default_content() # frame 초기화
browser.switch_to.frame(frame) # frame 변경
# 각 iframe들 [searchIframe / entryIframe / ]
ls2 = ['강남구', '강동구', '강북구', '강서구', '관악구', '광진구', '구로구',' 금천구', '노원구', '도봉구', '동대문구', '동작구', '마포구',
'서대문구', '서초구', '성동구', '성북구', '송파구', '양천구', '영등포구', '용산구', '은평구', '종로구', '중구', '중랑구']
# -----------------------------------25개의 구를 한번에 하면 인터넷 문제로 오류가 자주남-----------------------------------
# -----------------------------------5개 구로 쪼개서 하나씩 돌리며 파일을 만듬-----------------------------------
ls = ['강남구']
cafe_name_list = []
cafe_classification_list = []
cafe_review_count_list = []
cafe_address_list = []
cafe_review_list = []
background_image_url_list = []
cafe_menu_ls_list = []
# 처음 모든구를 한번에 돌릴려고 했으나 인터넷문제로 에러가 자주남. for문 제거
# for i in range(len(ls)): # 모든 자치구에 있는 카페를 알아보기 위해 반복
# 브라우저 열기
keyword = quote(f'{ls[i]} 카페')
browser = webdriver.Chrome()
browser.get(url)
browser.implicitly_wait(10)
# 스위치 변경
switch_frame("searchIframe")
time.sleep(1)
# 버튼 변수들
next_btn = browser.find_elements(By.CSS_SELECTOR, '.zRM9F> a')
browser.implicitly_wait(10)
# 버튼길이만큼 반복 첫번재는 이전버튼 이므로 제외
for btn in range(len(next_btn))[1:]:
print(f'------------------------------------{btn}/{len(next_btn)-1}------------------------------------')
#body부분을 잡기 위해 쓸데없는 버튼을 클릭해줌
browser.find_element(By.XPATH, '//*[@id="_pcmap_list_scroll_container"]/ul/li[1]/div[1]/div[1]/div').click()
#검색결과가 모두 보이지 않기 때문에 page down을 눌러 끝까지 펼쳐준다.
for scroll_1 in range(8):
browser.find_element(By.TAG_NAME, 'body').send_keys(Keys.END)
resp = browser.page_source # 처음 브라우저 소스와, 버튼을 누를때마다 그것에 관한 페이지 소스 가져옴
soup = BeautifulSoup(resp, 'html.parser') # 브라우저소스를 html로 변환하여 가져옴
length = len(soup.select('#_pcmap_list_scroll_container > ul > li'))+1 # 한페이지에 보이는 카페들의 개수 반환
# 카페들의 개수만큼 반복
for j in range(1, length+1):
# 스위치 변경
switch_frame("searchIframe")
# 해당하는 카페에 정보를 알기위해 그 카페를 클릭해줌
# 구마다 /html/body/div[3]/div/div[3]....../sapn[1] or /html/body/div[3]/div/div[4]....../sapn[1] 가 있음
try:
browser.find_element(By.XPATH, f'/html/body/div[3]/div/div[3]/div[1]/ul/li[{j}]/div[1]/a/div/div/span[1]').click()
except NoSuchElementException:
browser.find_element(By.XPATH, f'/html/body/div[3]/div/div[4]/div[1]/ul/li[{j}]/div[1]/a/div/div/span[1]').click()
finally:
# 카페정보를 받아오는 시간 충분하게 받아줌 인터넷이 느려 충분히 시간 줘야됌
time.sleep(3)
# 스위치 변경
switch_frame("entryIframe")
# 버튼이 누를 필요 없어서 제거
#---------------------------------------------------------------------------------------
# browser.find_element(By.CLASS_NAME,'_UCia').click()
# browser.implicitly_wait(10)
#---------------------------------------------------------------------------------------
print(f'-------------------------------{j}번째-------------------------------')
# 카페 주소 저장
cafe_addr = WebDriverWait(browser,1000).until(EC.presence_of_element_located((By.XPATH,'/html/body/div[3]/div/div/div/div[5]/div/div[2]/div[1]/div/div[1]/div/a/span[1]')))
cafe_address = cafe_addr.text
# 이미지 가져오기
background_image_style = browser.find_element(By.XPATH,'/html/body/div[3]/div/div/div/div[1]/div/div[1]/div/a/div').get_attribute('style')
background_image_url = re.search(r'url\("([^"]+)"\)', background_image_style).group(1)
# 위에서 버튼을 누르지 않으니 스크롤이 제대로 돌아가지 않음 entryIframe 내의 element 클릭 그래야 스크롤이 내려감
browser.find_element(By.ID, '_title').click()
for scroll in range(0,10):
browser.find_element(By.TAG_NAME, 'body').send_keys(Keys.PAGE_DOWN)
resp = browser.page_source
soup = BeautifulSoup(resp, 'html.parser')
cafe_menu_ls = []
cafe_menu = soup.select('div.MN48z > div.erVoL > div.MENyI > span.VQvNX')
if len(cafe_menu) == 0:
cafe_menu = soup.select('div.YzCTi > div.Fi0vA > div.RhpMT > a.place_bluelink.ihmWt')
for menu in cafe_menu:
cafe_menu_ls.append(menu.text)
else:
for menu in cafe_menu:
cafe_menu_ls.append(menu.text)
# 리뷰 높은순 3개 가져오기.
cafe_review = []
try:
for k in range(1,4):
cafe_review.append(soup.select(f'div.place_section_content > div.iqjjt > a > ul > li:nth-child({k}) > div.CsBE9 > span.nWiXa')[0].text[1:-1])
except:
cafe_review.append('리뷰 참여자가 10명이 되지 않습니다.')
# 스위치 변경
switch_frame("searchIframe")
resp = browser.page_source
soup = BeautifulSoup(resp, 'lxml')
# --------------------------------------------------------평점이 없는 매장이 훨신 많아 평점 제거--------------------------------------------------
# 딕셔너리에 담을 변수들 생성
cafe_name = soup.select(f'#_pcmap_list_scroll_container > ul > li:nth-child({j}) > div.CHC5F > a.tzwk0 > div > div > span.TYaxT')[0].text
cafe_classification = soup.select(f'#_pcmap_list_scroll_container > ul > li:nth-child({j}) > div.CHC5F > a.tzwk0 > div > div > span.KCMnt')[0].text
cafe_review_count = soup.select(f'#_pcmap_list_scroll_container > ul > li:nth-child({j}) > div.CHC5F > div > div > span:nth-child(2)')[0].text
if cafe_review_count[:2] == '리뷰':
cafe_review_count = cafe_review_count[3:]
elif cafe_review_count[:2] != '리뷰':
try:
cafe_review_count = soup.select(f'#_pcmap_list_scroll_container > ul > li:nth-child({j}) > div.CHC5F > div > div > span:nth-child(3)')[0].text[3:]
except:
cafe_review_count = soup.select(f'#_pcmap_list_scroll_container > ul > li:nth-child({j}) > div.CHC5F > div > div > span:nth-child(1)')[0].text[3:]
else :
cafe_review_count = '0'
cafe_name_list.append(cafe_name)
cafe_classification_list.append(cafe_classification)
cafe_review_count_list.append(cafe_review_count)
cafe_address_list.append(cafe_address)
cafe_review_list.append(cafe_review)
background_image_url_list.append(background_image_url)
cafe_menu_ls_list.append(cafe_menu_ls)
dict_temp = {
'name':cafe_name_list,
'class':cafe_classification_list,
'review_count':cafe_review_count_list,
'address':cafe_address_list,
'review_top3':cafe_review_list,
'background_image_url':background_image_url_list,
'cafe_menu':cafe_menu_ls_list
}
next_btn[-1].click() # 다음 버튼 클릭
time.sleep(5)
# 버튼이 눌리지 않으면 종료
if not next_btn[-1].is_enabled():
break
browser.implicitly_wait(10)
browser.close()
df = pd.DataFrame(dict_temp)
df.to_csv('C:/Users/user/crawling_project/crawling_강남구.csv',index = False, encoding='utf-8-sig')
이제 불러들인 값들을 딕셔너리에 저장한 후 csv파일에 저장을 하도록 하였습니다.
코드를 한번 돌리면 한 자치구가 끝나면 다음구가 자동으로 넘어가면서 파일을 저장하게 만들었었는데, 이를 한개의 자치구씩 직접 코드를 실행하였습니다.
저걸 클릭하는 이부분을 제거해주었습니다.
이렇게 예외 처리를 해줌으로써 해결하였습니다.
아직 화면이 나오지 않았는데 그 화면에 해당하는 요소를 찾을때 발생하는 오류를 없애주기 위해서입니다.
pandas를 활용하여 csv파일로 저장해주었습니다.
pandas란 파이썬의 데이터 분석 라이브러리입니다.
수치형 테이블과 시계열 데이터를 조작하고 운영하기 위한 데이터를 제공합니다.
이분의 블로그를 참고하여 사용하였습니다.
4일차에서는 추가적으로 django를 이용하여 간단하게 웹페이지를 구현해보도록 하겠습니다.