스터디 노트🖊️_Day 24(EDA)

정설령·2023년 4월 4일
0

EDA

목록 보기
7/11
post-thumbnail

⭐ selenium 기초

1. selenium 설치 및 webdriver 사용하기

  • 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()

2. 화면 스크롤

  • 스크롤 가능한 높이(길이)
# 자바스크립트 코드 실행
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()

3. 검색어 입력

  • 크롬화면 띄우기
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome('../driver/chromedriver.exe')
driver.get('https://www.naver.com/')

CSS_SELECTOR

  • 검색창에 '딥러닝' 입력하기
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()

XPATH

'//': 최상위
'*' : 자손태그
'/': 자식태그
'div[1]': div 중에서 1번째 태그
    
'//*[@id="NM_NEWSSTAND_DEFAULT_THUMB"]/div[1]/div[1]/div/div[2]/div[10]/a/img'
  • 검색창에 'xpath' 입력하기
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')
  1. 돋보기 버튼 선택
from selenium.webdriver import ActionChains

search_tag = driver.find_element(By.CSS_SELECTOR, '.search')
action = ActionChains(driver)
action.click(search_tag)
action.perform()
  1. 검색어 입력
key_word = driver.find_element(By.CSS_SELECTOR, '#header > div.search.on > input[type=text]')
key_word.clear()
key_word.send_keys('딥러닝')
  1. 검색 버튼 클릭
driver.find_element(By.CSS_SELECTOR, '#header > div.search.on > button').click()

4. selenium + beautifulsoup

  • 현재 화면의 html 코드 가져오기
from bs4 import BeautifulSoup

req = driver.page_source
soup = BeautifulSoup(req, 'html.parser')

contents = soup.select('.inner')
print(len(contents))		# 9

✔️ 유가분석 1~5

1. '셀프 주유소가 정말 저렴한가?'

2. selenium으로 페이지 접근

  • 페이지 접근
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, '제주')
  • text가 아닌 value값 추출
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)
  • 시/군/구 키워드('강남구)' 변경 - test 용
gu_list_raw.send_keys(gu_names[0])
  • 엑셀 저장 - test 용
# 방법 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) 

3. 데이터 정리하기

  • glob : 여러 파일 한번에 불러오기
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
  • concat을 이용하여 25개 주유소 가격 정보를 하나로 합침
stations_raw = pd.concat(tmp_raw)
stations_raw

  • 데이터프레임 속성 확인
stations_raw.info()

stations_raw.columns
  • 필요한 값 만 추출하여 새로운 데이터프레임('station') 생성
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

  • unique()로 확인
stations['구'].unique(), len(stations['구'].unique())

  • '가격' 컬럼을 float 데이터형으로 변환
# 가격 정보가 있는 주유소만 사용
stations = stations[stations['가격'] != '-']
stations.info()

  • 인덱스 재정렬
stations.reset_index(drop=True, inplace=True)
# drop=True는 인덱스를 정렬할 때 기존 인덱스가 컬럼으로 추가되는 것을 방지

stations.tail()

4. 주유 가격 정보 시각화

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')
  • boxplot(feat. pandas)
stations.boxplot(column='가격', by='셀프', figsize=(10, 7));

  • boxplot(feat. seaborn)
plt.figure(figsize=(10, 7))
sns.boxplot(x='셀프', y='가격', data=stations, palette='Set3')
plt.grid()
plt.show()

→ 2가지 boxplot을 이용한 시각화를 통해 셀프주유소가 대체적으로 저렴하다는 것을 보이고 있다.

  • boxplot(feat. seaborn)
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)
  • '구'별 평균 가격을 pivot_table로 구하기
import numpy as np

gu_data = pd.pivot_table(data=stations, index='구', values='가격', aggfunc=np.mean)
gu_data.head()

  • 우리나라 위도/경도가 담긴 json 파일을 이용하여 지도 시각화
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

→ 서울시의 구 별 평균 주유소 가격은 짙은 색으로 표시 된 용산구가 가장 높은 것으로 나타났다.


"이 글은 제로베이스 데이터 취업 스쿨의 강의 자료 일부를 발췌하여 작성되었습니다."

profile
데이터 분석가

0개의 댓글