셀레니움 공식문서 참고
https://www.selenium.dev/documentation/
https://selenium-python.readthedocs.io/
셀레니움을 사용하는 이유
- windows, mac(intel)
- conda install selenium
- mac(m1)
- pip install selenium
- chrome driver chrome
- 본인 버전에 맞는 드라이버 설치
from selenium import webdriver
driver = webdriver.Chrome('../driver/chromedriver.exe')
driver.get('https://www.naver.com') # chrome 화면이 뜨면 정상적으로 설치된 것
driver.quit()
driver.maximize_window()
driver.minimize_window()
driver.set_window_size(600, 600)
driver.refresh()
driver.back()
driver.forward()
from selenium.webdriver.common.by import By
first_content = driver.find_element(By.CSS_SELECTOR, '#content > div.cover-masonry > div > ul > li:nth-child(1)')
#으로 시작 : id 태그
first_content.click()
driver.execute_script('window.open("https://www.naver.com")')
driver.switch_to.window(driver.window_handles[1])
print(len(driver.window_handles)) # 2
driver.close()
driver.quit()
# 자바스크립트 코드 실행
driver.execute_script('return document.body.scrollHeight') # 9970
driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')
driver.save_screenshot('./last_height.png') # True
driver.execute_script('window.scrollTo(0,0)')
from selenium.webdriver import ActionChains
some_tag = driver.find_element(By.CSS_SELECTOR, '#content > div.cover-list > div > ul > li:nth-child(1)')
action = ActionChains(driver)
action.move_to_element(some_tag).perform()
driver.quit()
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome('../driver/chromedriver.exe')
driver.get('https://www.naver.com/')
keyword = driver.find_element(By.CSS_SELECTOR, '#query')
keyword.clear()
keyword.send_keys('딥러닝')
search_btn = driver.find_element(By.CSS_SELECTOR, '#search_btn')
search_btn.click()
'//': 최상위
'*' : 자손태그
'/': 자식태그
'div[1]': div 중에서 1번째 태그
'//*[@id="NM_NEWSSTAND_DEFAULT_THUMB"]/div[1]/div[1]/div/div[2]/div[10]/a/img'
driver.find_element(By.XPATH, '//*[@id="query"]').send_keys('xpath')
driver.find_element(By.XPATH, '//*[@id="search_btn"]').click()
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome('../driver/chromedriver.exe')
driver.get('https://pinkwink.kr')
from selenium.webdriver import ActionChains
search_tag = driver.find_element(By.CSS_SELECTOR, '.search')
action = ActionChains(driver)
action.click(search_tag)
action.perform()
key_word = driver.find_element(By.CSS_SELECTOR, '#header > div.search.on > input[type=text]')
key_word.clear()
key_word.send_keys('딥러닝')
driver.find_element(By.CSS_SELECTOR, '#header > div.search.on > button').click()
from bs4 import BeautifulSoup
req = driver.page_source
soup = BeautifulSoup(req, 'html.parser')
contents = soup.select('.inner')
print(len(contents)) # 9
from selenium import webdriver
url = 'https://www.opinet.co.kr/searRgSelect.do'
driver = webdriver.Chrome('../driver/chromedriver.exe')
driver.get(url)
→ 문제
1) 해당 url로 한번에 접근이 안됨.
2) 메인 페이지로 접속이 되고, 팝업창도 나옴.
import time
def main_get():
# 페이지 접근
url = 'https://www.opinet.co.kr/searRgSelect.do'
driver = webdriver.Chrome('../driver/chromedriver.exe')
driver.get(url)
time.sleep(3)
# 팝업창으로 전환
driver.switch_to_window(driver.window_handles[-1])
time.sleep(3)
# 팝업창 닫아주기
driver.close()
time.sleep(3)
# 메인화면 창으로 전환
driver.switch_to_window(driver.window_handles[-1])
# 접근 URL 다시 요청
driver.get(url)
main_get()
→ time.sleep()을 주는 이유
: selenium에서 페이지를 반환하는 속도가 상대적으로 느려 차근차근 팝업창을 닫아주기 위함
sido_list_raw = driver.find_element_by_id('SIDO_NM0')
sido_list_raw.text
→ 활용하기 어려운 형태로 출력된 결과를 볼 수 있음
from selenium.webdriver.common.by import By
sido_list = sido_list_raw.find_elements(By.TAG_NAME, 'option')
len(sido_list), sido_list[17].text
# (18, '제주')
sido_names = []
# 방법 1.
for option in sido_list:
sido_names.append(option.get_attribute('value'))
sido_names
# 방법 2. list comprehension
sido_names = [option.get_attribute('value') for option in sido_list]
sido_names
→ 첫번째 공백 값 제거 필요
sido_names = sido_names[1:]
sido_list_raw.send_keys(sido_names[0])
# 부모 태그
gu_list_raw = driver.find_element(By.ID, 'SIGUNGU_NM0')
# 자식 태그
gu_list = gu_list_raw.find_elements(By.TAG_NAME, 'option')
gu_names = [option.get_attribute('value') for option in gu_list]
gu_names = gu_names[1:]
gu_names[:5], len(gu_names)
# (['강남구', '강동구', '강북구', '강서구', '관악구'], 25)
gu_list_raw.send_keys(gu_names[0])
# 방법 1.
driver.find_element(By.CSS_SELECTOR, '#glopopd_excel').click()
# 방법 2.
driver.find_element(By.XPATH, '//*[@id="glopopd_excel"]').click()
# 방법 3.
element_get_excel = driver.find_element(By.ID, 'glopopd_excel')
element_get_excel.click()
import time
from tqdm import tqdm_notebook
for gu in tqdm_notebook(gu_names):
element = driver.find_element(By.ID, 'SIGUNGU_NM0')
element.send_keys(gu)
time.sleep(3)
element_get_excel = driver.find_element(By.XPATH, '//*[@id="glopopd_excel"]').click()
time.sleep(3)
import pandas as pd
from glob import glob
# 파일명 저장
station_files = glob('../data/oil/지역_*.xls')
station_files[:5]
# ['../data/oil\\지역_위치별(주유소) (1).xls',
# '../data/oil\\지역_위치별(주유소) (10).xls',
# '../data/oil\\지역_위치별(주유소) (11).xls',
# '../data/oil\\지역_위치별(주유소) (12).xls',
# '../data/oil\\지역_위치별(주유소) (13).xls']
# 실제 엑셀파일에서 2행까지 컬럼 내용이 없기 때문에 header는 3행(=2)로 지정
tmp = pd.read_excel(station_files[0], header=2)
tmp.tail(2)
tmp_raw = []
for file in station_files:
tmp = pd.read_excel(file, header=2)
tmp_raw.append(tmp)
len(tmp_raw) # 25
stations_raw = pd.concat(tmp_raw)
stations_raw
stations_raw.info()
stations_raw.columns
stations = pd.DataFrame({
'상호': stations_raw['상호'],
'주소': stations_raw['주소'],
'가격': stations_raw['휘발유'],
'셀프': stations_raw['셀프여부'],
'상표': stations_raw['상표']
})
stations.tail()
# 테스트 용
for address in stations['주소']:
print(address.split())
# 전체 적용
stations['구'] = [address.split()[1] for address in stations['주소']]
stations
stations['구'].unique(), len(stations['구'].unique())
# 가격 정보가 있는 주유소만 사용
stations = stations[stations['가격'] != '-']
stations.info()
stations.reset_index(drop=True, inplace=True)
# drop=True는 인덱스를 정렬할 때 기존 인덱스가 컬럼으로 추가되는 것을 방지
stations.tail()
import matplotlib.pyplot as plt
import seaborn as sns
import platform
from matplotlib import font_manager, rc
path = 'C:/Windows/Fonts/malgun.ttf'
if platform.system == 'Darwin':
rc('font', family='Arial Unicode MS')
elif platform.system() == 'Windows':
font_name = font_manager.FontProperties(fname=path).get_name()
rc('font', family=font_name)
else:
print('Unkown system. sorry')
stations.boxplot(column='가격', by='셀프', figsize=(10, 7));
plt.figure(figsize=(10, 7))
sns.boxplot(x='셀프', y='가격', data=stations, palette='Set3')
plt.grid()
plt.show()
→ 2가지 boxplot을 이용한 시각화를 통해 셀프주유소가 대체적으로 저렴하다는 것을 보이고 있다.
plt.figure(figsize=(10, 7))
sns.boxplot(x='상표', y='가격', hue='셀프', data=stations, palette='Set3')
plt.grid()
plt.show()
→ 브랜드 별로 셀프주유소와 일반주유소의 가격 차이를 알 수 있고, 서울에서 일반주유소의 가격이 대체적으로 가장 비싼 브랜드는 GS칼텍스라고 나타났다.
import json
import folium
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
import numpy as np
gu_data = pd.pivot_table(data=stations, index='구', values='가격', aggfunc=np.mean)
gu_data.head()
geo_path = '../data/02. skorea_municipalities_geo_simple.json'
geo_str = json.load(open(geo_path, encoding='utf-8'))
my_map = folium.Map(location=[37.5602, 126.992], zoom_start=10.5, tiles='Stamen Toner')
# 경계선 표시
my_map.choropleth(
geo_data = geo_str,
data=gu_data,
columns=[gu_data.index, '가격'],
key_on='feature.id',
fill_color='PuRd'
)
my_map
→ 서울시의 구 별 평균 주유소 가격은 짙은 색으로 표시 된 용산구가 가장 높은 것으로 나타났다.
"이 글은 제로베이스 데이터 취업 스쿨의 강의 자료 일부를 발췌하여 작성되었습니다."