특정 지역의 데이터셋을 가지고 공부해보고 싶은게 있어서 지역 정보가 필요했다.
그런데 무식하게 긁어올 수 없어서 웹크롤러를 만들어보기로 했다.
바로 떠오른 생각은 네이버 지도에서 가져오는 것인데, 이게 생각보다 쉽지 않았다. 그래서 패쓰하고 네이버 플레이스 서비스로 접근했다.
(OPEN API도 있었는데 전화번호 정보는 가져오지 못하는 한계가 있었다.)
우선 기본적인 라이브러리를 불러온다.
네이버에서는 일단 크롤링에 대해서 관대하지 않기 때문에 몇 가지 주의사항이 있다.
from selenium.webdriver.common.by import By
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
from bs4 import BeautifulSoup
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import re
from selenium.webdriver.common.keys import Keys
import time
import requests
원래는 크롤링 후 저장할 xlsx파일 준비도 필요하지만 여기선 생략하겠다.
크롬 웹드라이버를 먼저 열어준다. 예전에는 이것도 버전별로 관리하면서 구동환경에 따라 고장나는 경우가 많았는데 요즘은 ChromeDriverManager로 내 구동환경에는 영향을 받지 않는다.
driver.implicitly_wait(20)는 묵시적 대기로 해당 값만큼 응답을 기다려준다.
혹시나 오류날까봐 적어두는 나름대로의 예외처리이다.
#크롬 웹드라이버 불러오기
driver = webdriver.Chrome(ChromeDriverManager().install())
res = driver.get('https://m.place.naver.com/place/list?query=%EA%B0%95%EB%82%A8%EA%B5%AC%20%EC%B9%B4%ED%8E%98&level=top')
driver.implicitly_wait(20)
네이버 플레이스 검색결과에서 모든 정보를 가져올 수 없기 때문에, 검색되어 나온 값의 특정 플레이스로 들어가서 나머지 정보를 가져온다.
그러기 위해서는 두 번의 크롤링이 필요한데, 첫 번째와 달리 bs4로도 충분히 가능하기에 bs4으로 셋팅해준다.
여기서도 몇 가지 주의사항이 필요한데, headers부분과 retry부분이다.
#2차 크롤링을 위한 bs4 셋팅
session = requests.Session()
headers = {"User-Agent": "useragent값 넣어주기"}
retries = Retry(total=5,
backoff_factor=0.1,
status_forcelist=[ 500, 502, 503, 504 ])
session.mount('http://', HTTPAdapter(max_retries=retries))
검색 결과에서 모든 결과를 보여주지 않기 때문에 페이지를 강제로 내려 데이터를 전부 펼쳐지도록 만들어준다.
#body부분을 잡기 위해 쓸데없이 버튼을 클릭해줌
driver.find_element(By.XPATH, '//*[@id="_list_scroll_container"]/div/div/div[1]/div/div/a[2]').click()
driver.find_element(By.XPATH, '//*[@id="_list_scroll_container"]/div/div/div[1]/div/div/a[1]').click()
#검색결과가 모두 보이지 않기 때문에 page down을 눌러 끝까지 펼쳐준다.
for scroll in range(0,30):
driver.find_element(By.TAG_NAME, 'body').send_keys(Keys.PAGE_DOWN)
time.sleep(0.2)
이제 본격적인 크롤링을 시작한다.
네이버는 주기적으로 class/tag명 변경되기 때문에 몇 달 아니 몇 일만 지나도 레거시코드가 될 수 있다.
html = driver.page_source
bs = BeautifulSoup(html, 'html.parser')
soup = bs.select_one('div.YluNG')
naver_info = soup.select('li.VLTHu')
#2차 크롤링을 위한 url
url = 'https://m.place.naver.com'
for info in naver_info:
store_name = info.select_one('div.C6RjW').text
mart_cate = info.select_one('span.YzBgS').text
link = info.select_one('div.ouxiq').select_one('a').attrs['href']
time.sleep(0.06)
#네이버 플레이스로 이동(place ID로 접속)
N_res = session.get(url+link, headers=headers)
N_soup_srch = BeautifulSoup(N_res.content, 'html.parser')
mart_oldtel = N_soup_srch.select_one('span.yxkiA > a').attrs['href']
mart_tel = str(re.sub('tel:', '', mart_oldtel)) # 'tel:' 삭제
#주소는 '공유'에서 파싱
address = N_soup_srch.select('span.yxkiA > a')[3].attrs['data-line-description']
print(store_name, '/',store_cate, '/', url+link, '/', store_tel, '/', address )
time.sleep(0.06)
실제 코드에서는 openpyxl를 활용하여 xlsx파일로 담는 것까지 구현했다.
'아주 미비한 코딩 > Python' 카테고리의 다른 글
[Python] Selenium을 Webdriver-manager로 설정하기 (0) | 2024.08.17 |
---|---|
[Python] 네이버 플레이스(naver place) 리뷰 크롤링 (35) | 2024.08.11 |
[Python] json 파일 읽어서 csv로 저장하기 (1) | 2023.01.24 |
[Python] 두 좌표사이의 거리 구하기 - Haversine distance (0) | 2023.01.19 |
[Python] json 형식 읽기 (0) | 2022.12.14 |
댓글