- Selenium을 활용한 네이버 항공권 크롤링 -
<개발 목적>
폴리텍 하이테크 AI Engineering 과정 중 짝꿍 한명이 매주 제주도를 가야만 했다.
그래서 주말이 다가올때쯤이면 매번 항공권을 예매하기 위해 가격을 비교하고 있었다.
매주 비행기표를 예매해야만 했기에 값 비싼 비행기표를 예매하는 것은 부담이라고 했다.
그래서 나는 값이 싼 항공권 정보를 자동으로 찾아주는 코드를 구현하여 도움을 주고 싶었다.
짝꿍이 원하는 항공권 정보의 priority 는 다음과 같았다.
1. 짝꿍이 원하는 시간
2. 그 시간대에서의 싼 가격대의 항공권
3. 항공사는 중요하지 않음
사실 네이버 항공권 사이트에 이러한 기능이 다 있지만,
웹 크롤링과 파이썬 리스트 정렬을 활용하여 직접 구현해보고 싶었다.
<개요>
1. 크롬 드라이버를 통해 네이버 항공권 예매 사이트 접속
2. userInput을 통해 원하는 날짜 및 시간 선택
3. 항공권 데이터를 크롤링하여 리스트에 저장
4. 데이터 전처리 후 원하는 데이터만 출력
# Selenium
셀레니움은 파이어폭스, 인터넷 익스플로어, 크롬등과 같은 브라우저를 컨트롤 할 수 있게 해주는 프레임워크
# Crawling
웹 페이지를 그대로 가져와서 거기서 데이터를 추출해 내는 행위
<코드 설명>
from selenium import webdriver
import time
필요한 라이브러리 import
# 스크롤 다운 함수
def scroll_down():
SCROLL_PAUSE_SEC = 1
# 스크롤 높이 가져옴
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
# 끝까지 스크롤 다운
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 1초 대기
time.sleep(SCROLL_PAUSE_SEC)
# 스크롤 다운 후 스크롤 높이 다시 가져옴
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height
웹 페이지 특성 상 스크롤 다운을 해야 모든 정보 크롤링 가능하므로 스크롤 다운 함수 정의
-> 항공권 데이터 크롤링 하기 전에 사용할 것임.
# 네이버 항공권 사이트 접속
driver = webdriver.Chrome('./chromedriver.exe')
driver.get('https://flight.naver.com/flights/?'
'trip=OW&scity1=TAE&ecity1=CJU&adult=1&child=0&infant=0&fareTy'
'pe=YC&airlineCode=&nxQuery=%ED%95%AD%EA%B3%B5%EA%B6%8C')
selenium webdriver를 통해 크롬 드라이버를 실행 및 웹 페이지 접속
# 날짜 선택란 클릭
driver.find_element_by_xpath("/html/body/div/div/div[2]/div[1]/fieldset/div[2]/div[1]/div/div[1]/a").click()
time.sleep(1)
# 날짜 선택 - input 형식으로 숫자를 받아서 html 주소에 숫자를 넣을 것임.
# 월 선택
months = ['이번 달', '다음 달']
for i, month in enumerate(months):
print(f'{i + 1}. {month}\t', end='\t')
print()
monthInput = int(input("몇월에 떠나시나요? : "))
print()
# 주 선택
weeks = ['첫째 주', '둘째 주', '셋째 주', '넷째 주', '다섯째 주', '여섯째 주']
for i, week in enumerate(weeks):
print(f'{i + 1}. {week}\t', end='\t')
print()
weekInput = int(input("몇째 주에 떠나시나요? : "))
print()
# 요일 선택
days = ['일', '월', '화', '수', '목', '금', '토']
for i, day in enumerate(days):
print(f'{i + 1}. {day}\t', end='\t')
print()
dayInput = int(input("무슨 요일에 떠나시나요? : "))
print()
# 지정한 날짜 선택하기 - input 을 통해 원하는 html 주소 (날짜 선택) 를 클릭.
driver.find_element_by_xpath(f"/html/body/div/div/div[2]/div[1]/"
f"fieldset/div[2]/div[1]/div/div[3]/"
f"div/div[2]/div[1]/div/div[{monthInput}]/"
f"div[2]/table/tbody/tr[{weekInput}]/td[{dayInput}]/a").click()
# 항공권 검색 클릭
driver.find_element_by_xpath("/html/body/div/div/div[2]/div[1]/fieldset/a").click()
time.sleep(4)
원하는 날짜 선택 -> 웹 페이지 상의 table 정보를 가져와서 선택 (개발자 도구 (F12) 를 활용하여 코드를 읽을 수 있음)
# 출발 시간항목 지정
departure_time = ['전체', '00:00 ~ 06:00', '06:00 ~ 09:00', '09:00 ~ 12:00',
'12:00 ~ 15:00', '15:00 ~ 18:00', '18:00 ~ 24:00']
for i, d_time in enumerate(departure_time):
print(f"{i + 1}. {d_time}", end='\t')
print()
timeInput = int(input("출발 시간을 선택하세요 : "))
print()
# 출발 시간 선택
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]/div/div[2]/ul/li[2]/a/span[1]").click()
if timeInput == 1:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[1]/span").click()
# 시간항목이 전체일 경우 : 스크롤 다운 함수 실행
scroll_down()
elif timeInput == 2:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[2]/span").click()
elif timeInput == 3:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[3]/span").click()
elif timeInput == 4:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[4]/span").click()
elif timeInput == 5:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[5]/span").click()
elif timeInput == 6:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[6]/span").click()
elif timeInput == 7:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[7]/span").click()
원하는 시간 선택 -> 날짜 선택과 비슷한 개념
시간 선택이 '전체'일 경우 모든 데이터를 보기 위해 스크롤 다운 함수 실행
# 전체 flight 정보들
flights = driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]/div/div[4]")
# 텍스트 형태로 info 에 저장
info = flights.text
# 띄어쓰기로 스플릿한 것들을 flight list 에 저장
flight_list = info.split()
데이터를 text 형태로 스플릿하여 리스트에 저장
['티웨이항공', '출발지', 'TAE', '12:20', '도착지', 'CJU', '13:20', '총', '소요시간', '01시간', '00분', '할인석', '편도', '34,400원', '편도', '32,556원', '(네이버페이', '결제시', '1%+1,500원', '적립)', '성인이벤트혜택', '1%', '적립', '티웨이항공', '출발지', 'TAE', '12:20', '도착지', 'CJU', '13:20', '총', '소요시간', '01시간', '00분', '일반석', '편도', '78,500원', '편도', '76,215원', '(네이버페이', '결제시', '1%+1,500원', '적립)', '성인이벤트혜택', '1%', '적립', '아시아나항공', '출발지', 'TAE', '13:25', '도착지', 'CJU', '14:30', '총', '소요시간', '01시간', '05분', '특가석', '편도', '35,400원', '편도', '33,546원', '(네이버페이', '결제시', '1%+1,500원', '적립)', '성인이벤트혜택', '1%', '적립', '아시아나항공', '출발지', 'TAE', '13:25', '도착지', 'CJU', '14:30', '총', '소요시간', '01시간', '05분', '할인석', '편도', '46,400원', '편도', '44,436원', '(네이버페이', '결제시', '1%+1,500원', '적립)', '성인이벤트혜택', '1%', '적립', '아시아나항공', '출발지', 'TAE', '13:25', '도착지', 'CJU', '14:30', '총', '소요시간', '01시간', '05분', '일반석', '편도', '83,400원', '편도', '81,066원', '(네이버페이', '결제시', '1%+1,500원', '적립)', '성인이벤트혜택', '1%', '적립', '제주항공', '출발지', 'TAE', '13:40', '도착지', 'CJU', '14:50', '총', '소요시간', '01시간', '10분', '할인석', '편도', '27,300원', '편도', '27,040원', '(KB국민카드', '결제시', '1%', '청구할인)', '성인이벤트혜택', '제주항공', '출발지', 'TAE', '13:40', '도착지', 'CJU', '14:50', '총', '소요시간', '01시간', '10분', '일반석', '편도', '76,400원', '편도', '75,650원', '(KB국민카드', '결제시', '1%', '청구할인)', '성인이벤트혜택', '진에어', '출발지', 'TAE', '13:45', '도착지', 'CJU', '14:50', '총', '소요시간', '01시간', '05분', '특가석', '편도', '29,200원', '편도', '27,408원', '(네이버페이', '결제시', '1%+1,500원', '적립)', '성인이벤트혜택', '1%', '적립', '진에어', '출발지', 'TAE', '13:45', '도착지', 'CJU', '14:50', '총', '소요시간', '01시간', '05분', '할인석', '편도', '33,700원', '편도', '31,863원', '(네이버페이', '결제시', '1%+1,500원', '적립)', '성인이벤트혜택', '1%', '적립', '진에어', '출발지', 'TAE', '13:45', '도착지', 'CJU', '14:50', '총', '소요시간', '01시간', '05분', '일반석', '편도', '77,400원', '편도', '75,126원', '(네이버페이', '결제시', '1%+1,500원', '적립)', '성인이벤트혜택', '1%', '적립', '진에어', '출발지', 'TAE', '14:55', '도착지', 'CJU', '15:55', '총', '소요시간', '01시간', '00분', '특가석', '편도', '21,200원', '편도', '19,488원', '(네이버페이', '결제시', '1%+1,500원', '적립)', '성인이벤트혜택', '1%', '적립', '진에어', '출발지', 'TAE', '14:55', '도착지', 'CJU', '15:55', '총', '소요시간', '01시간', '00분', '할인석', '편도', '35,200원', '편도', '33,348원', '(네이버페이', '결제시', '1%+1,500원', '적립)', '성인이벤트혜택', '1%', '적립', '진에어', '출발지', 'TAE', '14:55', '도착지', 'CJU', '15:55', '총', '소요시간', '01시간', '00분', '일반석', '편도', '77,400원', '편도', '75,126원', '(네이버페이', '결제시', '1%+1,500원', '적립)', '성인이벤트혜택', '1%', '적립']
↑↑
print(flight_list)
price_list = []
print("<< 시간 순 >>")
# 항공사, 출발 시각, 가격 -> 내가 필요한 정보만 추출하기 위한 슬라이싱
for i in range(len(flight_list)-1):
if flight_list[i] == '제주항공':
# 항공사 / 출발 시간 / 가격 출력력
print(f'{flight_list[i]}\t\t\t{flight_list[i + 3]}\t\t{flight_list[i + 13]}')
price_list.append([flight_list[i], flight_list[i + 3], flight_list[i + 13]])
elif flight_list[i] =='티웨이항공':
print(f'{flight_list[i]}\t\t{flight_list[i + 3]}\t\t{flight_list[i + 13]}')
price_list.append([flight_list[i], flight_list[i + 3], flight_list[i + 13]])
elif flight_list[i] == '진에어':
print(f'{flight_list[i]}\t\t\t{flight_list[i + 3]}\t\t{flight_list[i + 13]}')
price_list.append([flight_list[i], flight_list[i + 3], flight_list[i + 13]])
elif flight_list[i] == '아시아나항공':
print(f'{flight_list[i]}\t\t{flight_list[i + 3]}\t\t{flight_list[i + 13]}')
price_list.append([flight_list[i], flight_list[i + 3], flight_list[i + 13]])
원하는 데이터만 출력하기위해 리스트의 규칙성을 이용해 슬라이싱 진행
가격순으로 정렬하기 위해 새로운 리스트에 데이터 추가
for i in price_list:
# price_list 속 가격을 int 화 시키기
str_price = i[2]
price = str_price[:-1]
price = int(price.replace(',', ''))
# int 화 시킨 가격으로 리스트 다시 작성
i.insert(0, price)
sort_price_list = sorted(price_list)
print("<< 가격 낮은 순 >>")
for i in sort_price_list:
if i[1] == '제주항공':
print(f'{i[1]}\t\t\t{i[2]}\t\t{i[3]}')
elif i[1] == '티웨이항공':
print(f'{i[1]}\t\t{i[2]}\t\t{i[3]}')
elif i[1] == '진에어':
print(f'{i[1]}\t\t\t{i[2]}\t\t{i[3]}')
elif i[1] == '아시아나항공':
print(f'{i[1]}\t\t{i[2]}\t\t{i[3]}')
driver.close()
리스트 안의 데이터를 가격순으로 정렬후 출력
드라이버 종료
[[21200, '진에어', '14:55', '21,200원'], [27300, '제주항공', '13:40', '27,300원'],
[29200, '진에어', '13:45', '29,200원'], [33700, '진에어', '13:45', '33,700원'],
[34400, '티웨이항공', '12:20', '34,400원'], [35200, '진에어', '14:55', '35,200원'],
[35400, '아시아나항공', '13:25', '35,400원'], [46400, '아시아나항공', '13:25', '46,400원'],
[76400, '제주항공', '13:40', '76,400원'], [77400, '진에어', '13:45', '77,400원'],
[77400, '진에어', '14:55', '77,400원'], [78500, '티웨이항공', '12:20', '78,500원'],
[83400, '아시아나항공', '13:25', '83,400원']]
↑↑
print(sort_price_list)
<전체 코드>
from selenium import webdriver
import time
# 스크롤 다운 함수
def scroll_down():
SCROLL_PAUSE_SEC = 1
# 스크롤 높이 가져옴
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
# 끝까지 스크롤 다운
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 1초 대기
time.sleep(SCROLL_PAUSE_SEC)
# 스크롤 다운 후 스크롤 높이 다시 가져옴
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height
if __name__ == '__main__':
# 네이버 항공권 사이트 접속
driver = webdriver.Chrome('./chromedriver.exe')
driver.get('https://flight.naver.com/flights/?'
'trip=OW&scity1=TAE&ecity1=CJU&adult=1&child=0&infant=0&fareTy'
'pe=YC&airlineCode=&nxQuery=%ED%95%AD%EA%B3%B5%EA%B6%8C')
# 날짜 선택란 클릭
driver.find_element_by_xpath("/html/body/div/div/div[2]/div[1]/fieldset/div[2]/div[1]/div/div[1]/a").click()
time.sleep(1)
# 날짜 선택 - input 형식으로 숫자를 받아서 html 주소에 숫자를 넣을 것임.
# 월 선택
months = ['이번 달', '다음 달']
for i, month in enumerate(months):
print(f'{i + 1}. {month}\t', end='\t')
print()
monthInput = int(input("몇월에 떠나시나요? : "))
print()
# 주 선택
weeks = ['첫째 주', '둘째 주', '셋째 주', '넷째 주', '다섯째 주', '여섯째 주']
for i, week in enumerate(weeks):
print(f'{i + 1}. {week}\t', end='\t')
print()
weekInput = int(input("몇째 주에 떠나시나요? : "))
print()
# 요일 선택
days = ['일', '월', '화', '수', '목', '금', '토']
for i, day in enumerate(days):
print(f'{i + 1}. {day}\t', end='\t')
print()
dayInput = int(input("무슨 요일에 떠나시나요? : "))
print()
# 지정한 날짜 선택하기 - input 을 통해 원하는 html 주소 (날짜 선택) 를 클릭.
driver.find_element_by_xpath(f"/html/body/div/div/div[2]/div[1]/"
f"fieldset/div[2]/div[1]/div/div[3]/"
f"div/div[2]/div[1]/div/div[{monthInput}]/"
f"div[2]/table/tbody/tr[{weekInput}]/td[{dayInput}]/a").click()
# 항공권 검색 클릭
driver.find_element_by_xpath("/html/body/div/div/div[2]/div[1]/fieldset/a").click()
time.sleep(4)
# 출발 시간항목 지정
departure_time = ['전체', '00:00 ~ 06:00', '06:00 ~ 09:00', '09:00 ~ 12:00',
'12:00 ~ 15:00', '15:00 ~ 18:00', '18:00 ~ 24:00']
for i, d_time in enumerate(departure_time):
print(f"{i + 1}. {d_time}", end='\t')
print()
timeInput = int(input("출발 시간을 선택하세요 : "))
print()
# 출발 시간 선택
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]/div/div[2]/ul/li[2]/a/span[1]").click()
if timeInput == 1:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[1]/span").click()
# 시간항목이 전체일 경우 : 스크롤 다운 함수 실행
scroll_down()
elif timeInput == 2:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[2]/span").click()
elif timeInput == 3:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[3]/span").click()
elif timeInput == 4:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[4]/span").click()
elif timeInput == 5:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[5]/span").click()
elif timeInput == 6:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[6]/span").click()
elif timeInput == 7:
driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]"
"/div/div[2]/ul/li[2]/div/ul/li[7]/span").click()
flights = driver.find_element_by_xpath("/html/body/div/div/div[1]/div[2]/div[2]/div/div[4]")
info = flights.text
flight_list = info.split()
print(flight_list)
price_list = []
print()
print("<< 시간 순 >>")
# 항공사, 출발 시각, 가격 -> 내가 필요한 정보만 추출하기 위한 슬라이싱
for i in range(len(flight_list)-1):
if flight_list[i] == '제주항공':
# 항공사 / 출발 시간 / 가격 출력력
print(f'{flight_list[i]}\t\t\t{flight_list[i + 3]}\t\t{flight_list[i + 13]}')
price_list.append([flight_list[i], flight_list[i + 3], flight_list[i + 13]])
elif flight_list[i] =='티웨이항공':
print(f'{flight_list[i]}\t\t{flight_list[i + 3]}\t\t{flight_list[i + 13]}')
price_list.append([flight_list[i], flight_list[i + 3], flight_list[i + 13]])
elif flight_list[i] == '진에어':
print(f'{flight_list[i]}\t\t\t{flight_list[i + 3]}\t\t{flight_list[i + 13]}')
price_list.append([flight_list[i], flight_list[i + 3], flight_list[i + 13]])
elif flight_list[i] == '아시아나항공':
print(f'{flight_list[i]}\t\t{flight_list[i + 3]}\t\t{flight_list[i + 13]}')
price_list.append([flight_list[i], flight_list[i + 3], flight_list[i + 13]])
print()
for i in price_list:
# price_list 속 가격을 int 화 시키기
str_price = i[2]
price = str_price[:-1]
price = int(price.replace(',', ''))
# int 화 시킨 가격으로 리스트 다시 작성
i.insert(0, price)
sort_price_list = sorted(price_list)
print()
print("<< 가격 낮은 순 >>")
for i in sort_price_list:
# print(i)
if i[1] == '제주항공':
print(f'{i[1]}\t\t\t{i[2]}\t\t{i[3]}')
elif i[1] == '티웨이항공':
print(f'{i[1]}\t\t{i[2]}\t\t{i[3]}')
elif i[1] == '진에어':
print(f'{i[1]}\t\t\t{i[2]}\t\t{i[3]}')
elif i[1] == '아시아나항공':
print(f'{i[1]}\t\t{i[2]}\t\t{i[3]}')
driver.close()
<실행 화면>
- Just Do It -
'Python > Web_crawling' 카테고리의 다른 글
[Python] 식단정보 크롤링 (2) | 2021.06.20 |
---|