{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Selenium 사용 동적 크롤링 - 주유소(셀프로 넣는게 더 싼가?)\n", "- 셀프주유소의 기름값을 보자\n", "- 셀프인곳과 아닌곳의 차이를 보는게 목표" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: selenium in c:\\anaconda3\\lib\\site-packages (3.141.0)\n", "Requirement already satisfied: urllib3 in c:\\anaconda3\\lib\\site-packages (from selenium) (1.24.2)\n" ] } ], "source": [ "# Selenium 설치.\n", "!pip install selenium" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import bs4\n", "import time\n", "import os\n", "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from selenium.webdriver.common.keys import Keys\n", "from selenium import webdriver" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1. 사이트에 들어가서 탐색해 본다" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1. 먼저 다음 사이트에 들어가서 살펴본다: [Opinet](http://www.opinet.co.kr/user/main/mainView.do)\n", "2. 크롬에서 3점 메뉴 버튼을 누르고 **도구 더보기** ==> **개발자 도구**를 선택해서 개발자 도구를 연다.\n", "3. 개발자 도구 왼쪽 상단의 화살표 버튼을 눌러서 사이트 일부를 서택하고 해당 HTML코드를 볼 수 있다. \"[CTRL] + [SHIFT] + C\" 조합으로 대체할 수 있다." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "os.chdir(r'C:\\Users\\Gram\\Desktop\\myPyCode\\02 데이터 수집과 처리 - 실습')\n", "# 웹드라이버 로딩. \n", "my_driver = webdriver.Chrome('chromedriver.exe') " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# 사이트에 접속. \n", "my_driver.get(\"http://www.opinet.co.kr\") #창 닫으면 안됨" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# 세부 링크로 간다.\n", "my_driver.get(\"http://www.opinet.co.kr/searRgSelect.do\")" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "http://www.opinet.co.kr/searRgSelect.do\n" ] } ], "source": [ "# 현재 URL 출력해 본다.\n", "print(my_driver.current_url)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2. 시,도 리스트 가져오기" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['시/도',\n", " '서울',\n", " '부산',\n", " '대구',\n", " '인천',\n", " '광주',\n", " '대전',\n", " '울산',\n", " '세종',\n", " '경기',\n", " '강원',\n", " '충북',\n", " '충남',\n", " '전북',\n", " '전남',\n", " '경북',\n", " '경남',\n", " '제주']" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 시/도 리스트 가져와 본다.\n", "my_sido = my_driver.find_element_by_css_selector(\"#SIDO_NM0\") #ctrl,shift,c들어가서 sido_nmo로 가져오기(지역의 서울 칸)\n", "my_sido_list = my_sido.text.split() #split하고 sido_nmo가 셀렉트태그라 시도리스트로\n", "my_sido_list" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['서울', '부산', '대구', '인천', '광주', '대전', '울산', '세종', '경기', '강원', '충북', '충남', '전북', '전남', '경북', '경남', '제주']\n" ] } ], "source": [ "my_sido_list.pop(0) #첫 번째 값이 '시/도'라 불필요해 버림. #pop하면 마지막값을 버림 #pop(위치)하면 해당위치 버려짐\n", "print(my_sido_list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3. 서울시의 시/군/구 리스트 가져오기" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "#시/도 리스트 가져오기\n", "my_sido = my_driver.find_element_by_css_selector(\"#SIDO_NM0\") #ctrl,shift,c들어가서 sido_nmo로 가져오기(지역 서울 칸)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "#시/도에서 서울시를 선택하기\n", "my_sido.send_keys(my_sido_list[0]) #시/도에서 서울시를 선택해야 함 (시도셀렉트 잡아서)\n", " #시도에 가서 만들어놓은걸 샌드키로 넣어줘야함-서울시로가고\n", " #군구가서 리스트로 값을 가져오고 첫번째거 버리면 구 리스트만 나옴\n", " #값을 샌드키로 넣어 그 값을 넣어줌? #값을 직접 대입하면 갑에 해당하는 셀렉터\n", "time.sleep(1)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "#서울시의 시/군/구 리스트 가져오기\n", "my_gu = my_driver.find_element_by_css_selector(\"#SIGUNGU_NM0\") #ctrl,shift,c들어가서 sigungu_NMO가져오기(지역 서울 칸)\n", "my_gu_list = my_gu.text.split() #split하고 sigungu가 셀렉트태그라 시군구리스트로" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['강남구', '강동구', '강북구', '강서구', '관악구', '광진구', '구로구', '금천구', '노원구', '도봉구', '동대문구', '동작구', '마포구', '서대문구', '서초구', '성동구', '성북구', '송파구', '양천구', '영등포구', '용산구', '은평구', '종로구', '중구', '중랑구']\n" ] } ], "source": [ "my_gu_list.pop(0) # 첫 번째 값은 '시/군/구'라 의미 없어 버림 \n", "print(my_gu_list)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "n_gus = len(my_gu_list) #25개" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4. 서울시의 첫번째 구와 나머지 구 가져오기" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "# 서울시 첫 번째 구.\n", "my_sido = my_driver.find_element_by_css_selector(\"#SIDO_NM0\") #ctrl,shift,c들어가서 sido_nmo로 가져오기(지역 서울 칸)\n", "my_sido.send_keys(my_sido_list[0]) #시도리스트에 첫번째 [0]\n", "time.sleep(1) #sleep해야 쉬었다감\n", "\n", "my_gu = my_driver.find_element_by_css_selector(\"#SIGUNGU_NM0\")\n", "my_gu.send_keys(my_gu_list[0])\n", "time.sleep(1)\n", "\n", "my_download = my_driver.find_element_by_css_selector(\"div.desc_box a\") #클릭을해줘야 정보가 다운됬었음 사이트에서 desc는 함수 \n", "my_download.click() #사이트에서 파일저장버튼 누른것과 같음 #첫번째것이 엑셀로 다운로드됨 #휘발유와 셀프여부만 보면됨\n", "time.sleep(1)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "# 나머지 구.\n", "for i in range(n_gus): #gus은 구군 숫자?\n", " my_gu = my_driver.find_element_by_css_selector(\"#SIGUNGU_NM0\")\n", " \n", " if (i != 0): #첫번째 구는 위에서 다운했으니 스킵하고 2번째거부터\n", " my_gu.send_keys(Keys.DOWN) #키다운내려 하나씩 다운받아감 #구리스트에서 하나씩 값을 넣어줘도됨(샌드키로)\n", " time.sleep(1) \n", " my_download = my_driver.find_element_by_css_selector(\"div.desc_box a\") #버튼누러 \n", " my_download.click() #클릭\n", " time.sleep(1)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "# 다운로드 됬으니 브라우저 닫음\n", "my_driver.close() #미리 닫으면 오류남" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 5. 엑셀 문서를 불러와 데이터프레임으로 통합한다." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "# 엑셀 파일 이름을 모아둔다. \n", "os.chdir(r'C:\\Users\\Gram\\Downloads') #엑셀을 통합할거라 다운받은 경로지정\n", "file_list = os.listdir() #폴더안에 있는 파일들 이름을 리스트로 가져옴\n", "my_excel_files =[] \n", "for x in file_list:\n", " if x[-3:] == 'xls': #파일리스트에서 이름가져오되 마지막 3자리가 xls인거만 \n", " my_excel_files += [x] " ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['desktop.ini',\n", " '지역_위치별(주유소) (1).xls',\n", " '지역_위치별(주유소) (10).xls',\n", " '지역_위치별(주유소) (11).xls',\n", " '지역_위치별(주유소) (12).xls',\n", " '지역_위치별(주유소) (13).xls',\n", " '지역_위치별(주유소) (14).xls',\n", " '지역_위치별(주유소) (15).xls',\n", " '지역_위치별(주유소) (16).xls',\n", " '지역_위치별(주유소) (17).xls',\n", " '지역_위치별(주유소) (18).xls',\n", " '지역_위치별(주유소) (19).xls',\n", " '지역_위치별(주유소) (2).xls',\n", " '지역_위치별(주유소) (20).xls',\n", " '지역_위치별(주유소) (21).xls',\n", " '지역_위치별(주유소) (22).xls',\n", " '지역_위치별(주유소) (23).xls',\n", " '지역_위치별(주유소) (24).xls',\n", " '지역_위치별(주유소) (25).xls',\n", " '지역_위치별(주유소) (26).xls',\n", " '지역_위치별(주유소) (27).xls',\n", " '지역_위치별(주유소) (28).xls',\n", " '지역_위치별(주유소) (29).xls',\n", " '지역_위치별(주유소) (3).xls',\n", " '지역_위치별(주유소) (30).xls',\n", " '지역_위치별(주유소) (31).xls',\n", " '지역_위치별(주유소) (32).xls',\n", " '지역_위치별(주유소) (33).xls',\n", " '지역_위치별(주유소) (34).xls',\n", " '지역_위치별(주유소) (35).xls',\n", " '지역_위치별(주유소) (36).xls',\n", " '지역_위치별(주유소) (37).xls',\n", " '지역_위치별(주유소) (38).xls',\n", " '지역_위치별(주유소) (39).xls',\n", " '지역_위치별(주유소) (4).xls',\n", " '지역_위치별(주유소) (40).xls',\n", " '지역_위치별(주유소) (41).xls',\n", " '지역_위치별(주유소) (42).xls',\n", " '지역_위치별(주유소) (43).xls',\n", " '지역_위치별(주유소) (44).xls',\n", " '지역_위치별(주유소) (45).xls',\n", " '지역_위치별(주유소) (46).xls',\n", " '지역_위치별(주유소) (47).xls',\n", " '지역_위치별(주유소) (48).xls',\n", " '지역_위치별(주유소) (49).xls',\n", " '지역_위치별(주유소) (5).xls',\n", " '지역_위치별(주유소) (50).xls',\n", " '지역_위치별(주유소) (51).xls',\n", " '지역_위치별(주유소) (52).xls',\n", " '지역_위치별(주유소) (53).xls',\n", " '지역_위치별(주유소) (54).xls',\n", " '지역_위치별(주유소) (55).xls',\n", " '지역_위치별(주유소) (56).xls',\n", " '지역_위치별(주유소) (57).xls',\n", " '지역_위치별(주유소) (58).xls',\n", " '지역_위치별(주유소) (59).xls',\n", " '지역_위치별(주유소) (6).xls',\n", " '지역_위치별(주유소) (60).xls',\n", " '지역_위치별(주유소) (61).xls',\n", " '지역_위치별(주유소) (62).xls',\n", " '지역_위치별(주유소) (63).xls',\n", " '지역_위치별(주유소) (64).xls',\n", " '지역_위치별(주유소) (65).xls',\n", " '지역_위치별(주유소) (66).xls',\n", " '지역_위치별(주유소) (67).xls',\n", " '지역_위치별(주유소) (68).xls',\n", " '지역_위치별(주유소) (69).xls',\n", " '지역_위치별(주유소) (7).xls',\n", " '지역_위치별(주유소) (70).xls',\n", " '지역_위치별(주유소) (71).xls',\n", " '지역_위치별(주유소) (72).xls',\n", " '지역_위치별(주유소) (73).xls',\n", " '지역_위치별(주유소) (74).xls',\n", " '지역_위치별(주유소) (75).xls',\n", " '지역_위치별(주유소) (76).xls',\n", " '지역_위치별(주유소) (77).xls',\n", " '지역_위치별(주유소) (78).xls',\n", " '지역_위치별(주유소) (79).xls',\n", " '지역_위치별(주유소) (8).xls',\n", " '지역_위치별(주유소) (80).xls',\n", " '지역_위치별(주유소) (81).xls',\n", " '지역_위치별(주유소) (82).xls',\n", " '지역_위치별(주유소) (83).xls',\n", " '지역_위치별(주유소) (84).xls',\n", " '지역_위치별(주유소) (85).xls',\n", " '지역_위치별(주유소) (86).xls',\n", " '지역_위치별(주유소) (87).xls',\n", " '지역_위치별(주유소) (88).xls',\n", " '지역_위치별(주유소) (89).xls',\n", " '지역_위치별(주유소) (9).xls',\n", " '지역_위치별(주유소) (90).xls',\n", " '지역_위치별(주유소).xls']" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "file_list" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "# 읽어 들여서 하나의 데이터 프레임으로 통합한다.\n", "n_excels = len(my_excel_files)\n", "for i in range(n_excels): \n", " a_df = pd.read_excel(my_excel_files[i],header=2, na_values = [' ', '-'])#헤더가 2: 0,1을(불필요한게 잇었음) 제끼고 3행부터 가져옴\n", " #na_values: 엑셀보면 -있으니 결측치처리\n", " if i == 0:\n", " df = a_df #a 데이터프레임\n", " else:\n", " df = pd.concat([df,a_df], axis=0, ignore_index=True)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1918, 10)" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.shape" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | 지역 | \n", "상호 | \n", "주소 | \n", "상표 | \n", "전화번호 | \n", "셀프여부 | \n", "고급휘발유 | \n", "휘발유 | \n", "경유 | \n", "실내등유 | \n", "
---|---|---|---|---|---|---|---|---|---|---|
0 | \n", "서울특별시 | \n", "(주)석산에너지 | \n", "서울 강북구 삼양로 316 (수유동) | \n", "현대오일뱅크 | \n", "02-980-1448 | \n", "N | \n", "NaN | \n", "1509.0 | \n", "1349.0 | \n", "950.0 | \n", "
1 | \n", "서울특별시 | \n", "북서울고속주유소 | \n", "서울 강북구 삼양로 410 (수유동) | \n", "S-OIL | \n", "02-907-5182 | \n", "Y | \n", "NaN | \n", "1509.0 | \n", "1359.0 | \n", "NaN | \n", "
2 | \n", "서울특별시 | \n", "수유동주유소 | \n", "서울 강북구 도봉로 395 (수유동) | \n", "GS칼텍스 | \n", "02-902-9470 | \n", "Y | \n", "NaN | \n", "1509.0 | \n", "1349.0 | \n", "NaN | \n", "
\n", " | 지역 | \n", "상호 | \n", "주소 | \n", "상표 | \n", "전화번호 | \n", "셀프여부 | \n", "휘발유 | \n", "경유 | \n", "
---|---|---|---|---|---|---|---|---|
0 | \n", "서울특별시 | \n", "(주)석산에너지 | \n", "서울 강북구 삼양로 316 (수유동) | \n", "현대오일뱅크 | \n", "02-980-1448 | \n", "N | \n", "1509.0 | \n", "1349.0 | \n", "
1 | \n", "서울특별시 | \n", "북서울고속주유소 | \n", "서울 강북구 삼양로 410 (수유동) | \n", "S-OIL | \n", "02-907-5182 | \n", "Y | \n", "1509.0 | \n", "1359.0 | \n", "
2 | \n", "서울특별시 | \n", "수유동주유소 | \n", "서울 강북구 도봉로 395 (수유동) | \n", "GS칼텍스 | \n", "02-902-9470 | \n", "Y | \n", "1509.0 | \n", "1349.0 | \n", "
3 | \n", "서울특별시 | \n", "(주)에프알엔디 직영 송정주유소 | \n", "서울 강북구 인수봉로 185 (수유동) | \n", "SK에너지 | \n", "02-993-5189 | \n", "N | \n", "1535.0 | \n", "1375.0 | \n", "
4 | \n", "서울특별시 | \n", "현대오일뱅크(주)직영 미아셀프주유소 | \n", "서울 강북구 도봉로 200 (미아동) | \n", "현대오일뱅크 | \n", "02-945-7999 | \n", "Y | \n", "1538.0 | \n", "1379.0 | \n", "
... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
1913 | \n", "서울특별시 | \n", "대성석유(주)직영 길동주유소 | \n", "서울 강동구 천호대로 1168 | \n", "GS칼텍스 | \n", "02-474-7222 | \n", "N | \n", "1648.0 | \n", "1498.0 | \n", "
1914 | \n", "서울특별시 | \n", "광성주유소 | \n", "서울 강동구 올림픽로 673 (천호동) | \n", "S-OIL | \n", "02-470-5133 | \n", "N | \n", "1658.0 | \n", "1498.0 | \n", "
1915 | \n", "서울특별시 | \n", "SK네트웍스 명일셀프주유소 | \n", "서울 강동구 고덕로 168 (명일동) | \n", "SK에너지 | \n", "02-3428-1739 | \n", "N | \n", "1665.0 | \n", "1499.0 | \n", "
1916 | \n", "서울특별시 | \n", "(주)삼표에너지 고덕주유소 | \n", "서울 강동구 고덕로 39 (암사동) | \n", "GS칼텍스 | \n", "02-441-3327 | \n", "N | \n", "1698.0 | \n", "1529.0 | \n", "
1917 | \n", "서울특별시 | \n", "강동주유소 | \n", "서울 강동구 양재대로 1509 (길동) | \n", "SK에너지 | \n", "02-477-5101 | \n", "N | \n", "1993.0 | \n", "1797.0 | \n", "
1918 rows × 8 columns
\n", "