본문 바로가기

EDA/selenium

STR 자동 예매 후 카톡 보내는 매크로 만들기! (selenium + PyKakao)


패스트 캠퍼스 AI LAB 3기 과정 2주차에 하는 SRT 자동 예매 예제 입니다.
실제는 Slack에 보내는 법을 배우는데 솔찍히 slack보다는 카톡 으로 알려줘야 하지 않겠나 싶어 따로 PyKakao를 공부했습니다.
뭐 메세지 보내는 API야 대충 블로그들 보고 따라하니 너무 좋더라구요.

아무튼 하는 방법 하나씩 정리해 보겠습니다!!

1. KAKAO DEVELOPER 설정

https://developers.kakao.com/

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

카카오 디벨로퍼에 들어가서 설정 붙어 해야해요!!
들어가면 아래 같은 화면이 나올거에요.

# 1. 내 애플리케이션 클릭!!


# 2. 애플리케이션 추가


# 3 정보(앱이름, 사업자명, 카테고리) 설정


# 4. 카카오 로그인 활성화 설정 ON


# 5. Redirect URI 에 localhost 추가!!!
같은 카카오 로그인 페이지에서 아래로 스크롤 하면 있습니다!!


# 6. 동의 항목 설정
카카오 로그인 밑에 있는 동의 항목으로 이동후 다음과 같이 설정해주세요!


# 7 API KEY 가져오기


이러면 설정 끝입니다!!! 다음은 코드로 가겠습니다!!!

2. 코드 구현

https://github.com/tjsgh531/SRT_crawling/tree/main

 

GitHub - tjsgh531/SRT_crawling: -selenium

-selenium. Contribute to tjsgh531/SRT_crawling development by creating an account on GitHub.

github.com

완성본은 깃허브를 통해 받아 볼 수 있습니다!!

2-1 코드 Flow

SRT 페이지에 들어가서 예매를 광클 해주는 것은 Selenium 이란 라이브러리로 구현 하고
카카오톡으로 메세지 전송해 주는 것은 Pykakao 라이브러리로 구현합니다.

 

  • # 1. 카카오 로그인 (PyKakao)
  • # 2. 카카오로 너한테 메세지 보내도 되는지 auth 관련 code 받기 (PyKakao)
  • # 3. SRT에 들어가요! (selenium)
  • # 4. SRT 로그인을 합니다. (selenium)
  • # 5. 예매 페이지로 갑니다 (selenium)
  • # 6. 원하는 출발지/도착지/시간 을 입력 시킵니다. (selenium)
  • # 7. 매진이 없어질때 까지 광클 합니다! (selenium)
  • # 8. 예약을 성공적으로 누르면 카카오톡에 메세지를 보냅니다 (PyKakao)

2-2 코드

참고로 저는 jupyter notebook에서 실행 했습니다.
colab은 selenium 사용하기 위해서 귀찮은 설정을 많이 해줘야 해서 추천 안합니다. 저도 평소는 colab 파입니다.

selenium에서 요소를 찾을 때, wait.unitl(EC.presence_of_element_located()) 함수를 사용했습니다.
find_element() 아시는 분은 사용해도 상관 없습니다!!!
둘의 차이는 그저 명시적 기다림 유무라 제가 사용한 것이 안전하지만 아래로 적어도 왠만해서 오류 안나요.

# 0. 설치 및 환경 설정
   
- 라이브러리(selenium, webdriver-manager, pykakao) 설치

# selenium 설치
!pip install selenium

# webdriver manager 설치
!pip install WebDriver-Manager

# pykakao 설치
!pip install PyKakao

   
- 필요 모듈 import

# selenium & webdriver-manager 관련 

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

# pykakao 관련 
from PyKakao import Message


- 브라우저 띄우기

ChromeDriverManager().install()

# 크롬으로 창 띄우기
browser = webdriver.Chrome()
wait = WebDriverWait(browser, 10)

 

# 1. 카카오 로그인

- auth url 로 들어가자!

api_key = '복사해 둔 Kakao API KEY'

API = Message(service_key = api_key)
auth_url = API.get_url_for_generating_code()

browser.get(auth_url)


- kakao 로그인

import getpass

kakao_id = input("카카오 아이디 입력 : ")
kakao_pw = getpass.getpass("카카오 pw입력: ")

kakao_id_input = wait.until(EC.presence_of_element_located((By.ID, 'loginId--1')))
kakao_pw_input = wait.until(EC.presence_of_element_located((By.ID, 'password--2')))
kakao_submit_btn = browser.find_element(By.CLASS_NAME, 'btn_g')

kakao_id_input.clear()
kakao_pw_input.clear()

kakao_id_input.send_keys(kakao_id)
kakao_pw_input.send_keys(kakao_pw)
kakao_submit_btn.click()

print("카카오 앱에서 확인을 눌러주세요!")



# 2. 카카오로 너한테 메세지 보내도 되는지 auth 관련 code 받기

- 로그인 성공시 code 받는 url 들어갈 수 있다.

kakao_agree_btn = wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'btn_agree')))
kakao_agree_btn.click()


- code는 url 주소에서 'code=~' 라고 표시 되어 있음. 그래서 그 뒤 string을 가져오는 작업(이때 404 NOT FOUND 같은 창이 뜨는데 신경 안써도 됩니다!!! 우리에게 필요한건 오직 url 주소!!!)

import re

code_url = browser.current_url
print(f"현재 url : {code_url}")

code = re.search(r"code=(.+)", str(code_url))
code = code.group(1)
print(f"code : {code}")

 

# 3 SRT에 들어가요!

url = 'https://etk.srail.kr/cmc/01/selectLoginForm.do?pageId=TK0701000000' # SRT 로그인 페이지 URL

browser.get(url)



# 4. SRT 로그인 합시다!

email = input("ID(이메일)를 입력해 주세요 : ")
pw = getpass.getpass("PW를 입력해 주세요 : ")

email_login_btn = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="srchDvCd2"]')))
email_login_btn.click()

id_input = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="srchDvNm02"]')))
pw_input = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="hmpgPwdCphd02"]')))
submit_btn = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="login-form"]/fieldset/div[1]/div[1]/div[3]/div/div[2]/input')))

id_input.clear()
pw_input.clear()

id_input.send_keys(email)
pw_input.send_keys(pw)
submit_btn.click()



# 5. 예매 페이지 갑시다!

booking_url = 'https://etk.srail.kr/hpg/hra/01/selectScheduleList.do?pageId=TK0101010000'
browser.get(booking_url)



# 6. 원하는 출발지/도착지/출발시간 입력받습니다!

- 출발지 / 도착지 입력 받아 브라우저 입력 하는 부분에 전달

departure = input("어디서 출발하나요? : ")
destination = input("어디로 갈까요? : ") 

departure_input = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="dptRsStnCdNm"]')))
destination_input = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="arvRsStnCdNm"]')))

departure_input.clear()
destination_input.clear()

departure_input.send_keys(departure)
destination_input.send_keys(destination, Keys.ENTER)


- 시간 입력 받은 후 해당 정보로 검색

time_input = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="dptTm"]')))
times = time_input.find_elements(By.TAG_NAME, 'option')
search_btn = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="search_top_tag"]/input')))

for time in times:
    print(f"{time.text}시", end=" / ")
wanted_time = int(input("가 있습니다. 몇 시로 예매 할까요? : ")) 

for time in times:
    if wanted_time == int(time.text):
        time.click()
        break

search_btn.click()



# 7. 매진 아닐때 까지 광클!!

import time

while True:
    special_seat = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="result-form"]/fieldset/div[6]/table/tbody/tr[1]/td[6]')))
    economy_seat = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="result-form"]/fieldset/div[6]/table/tbody/tr[1]/td[7]')))
    
    is_special_seat = False
    is_economy_seat = False

    if '예약 하기' in special_seat.text:
        is_special_seat = True
    if '예약 하기' in economy_seat.text:
        is_economy_seat = True

    if is_special_seat:
        print("특실 자리를 예매할 수 있어요!!")
        special_seat_btn = special_seat.find_element(By.TAG_NAME, 'a')
        special_seat_btn.click()
        break
    if is_economy_seat:
        print("일반실 자리를 예매할 수 있어요!!")
        economy_seat_btn = economy_seat.find_element(By.TAG_NAME, 'a')
        economy_seat_btn.click()
        break
    print("예약 할 수 있는 표가 없어요.. 광클 합니다")
    browser.refresh()
    time.sleep(3)
    search_btn = wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'btn_large ')))
    search_btn.click()



# 8. 자리가 있으면 카톡으로 메세지를 보내자!!

import requests

url = 'https://kauth.kakao.com/oauth/token'
redirect_uri = 'https://localhost:5000'

data = {
    'grant_type' : 'authorization_code',
    'client_id' : api_key,
    'redirect_uri' : redirect_uri,
    'code' : code,
}

response = requests.post(url, data=data)
tokens = response.json()
import json

booking_url = browser.current_url
url="https://kapi.kakao.com/v2/api/talk/memo/default/send"

# kapi.kakao.com/v2/api/talk/memo/default/send 

headers={
    "Authorization" : "Bearer " + tokens["access_token"]
}

data={
    "template_object": json.dumps({
        "object_type":"text",
        "text":f"예약에 성공했습니다! 10분 내로 결제하러 가세요!! {booking_url}",
        "link":{
            "web_url":"www.naver.com"
        }
    })
}

response = requests.post(url, headers=headers, data=data)
response.status_code
print(response.status_code)
if response.json().get('result_code') == 0:
	print('메시지를 성공적으로 보냈습니다.')
else:
	print('메시지를 성공적으로 보내지 못했습니다. 오류메시지 : ' + str(response.json()))

'EDA > selenium' 카테고리의 다른 글

selenium 라이브러리 함수 정리  (0) 2024.04.04
selenium으로 크롤링 하기(실습 예제)  (0) 2024.04.04