본문 바로가기
Portfolio & Toy-Project

파이썬(셀레니움)자동화_(구글 스프레드시트/카카오톡API&엑셀저장)

by Mr.DonyStark 2024. 1. 25.

 

□ 상황

  ○ 사용자는 일일 시간별 매출 데이터를 웹 사이트에 직접 로그인하여 정보를 조회하고있음

  ○ 직접 로그인하지 않고 자동화하여 실시간으로 시간별 매출 데이터를 조회하고자함

 

 요구사항

  ○ 실시간 매출 데이터 추출/조회

  ○ 매출 데이터를 개인 구글 스프레드시트에 저장

  ○ 추출된 데이터를 주기적으로 카카오톡을 통해 알림받고 조회

  ○ 하루가 지나면 시간별 데이터 엑셀로 저장

 

개발개요(위 그림에 기재된 번호 순서대로 기재함)

  ○ 함수정의 → 함수호출   사용자가 설정한 주기시간에 맞춰 코드진행

  ○ 크롤링 

    - 사용 라이브러리 : 셀레니움(Selenium)

      → 매출 데이터가 있는 웹사이트에 로그인 및 해당 페이지에서 출력되는 데이터를 추출하기 위해 사용

    - 프로세스 : 로그인 페이지 접속 ▶ ID/PW 입력   총 매출금액, 시간대별 매출금액 추출

    - 구현코드

      → 셀레니움 구글 드라이버 실행시 웹 창 숨김처리 : options.add_argument("headless") # 창 숨기는 옵션 추가

    # 브라우저 자동 꺼짐옵션지정
    chrome_options = Options()
    chrome_options.add_experimental_option("detach", True)

    # 셀레니움옵션기능 활성화
    options = webdriver.ChromeOptions()
    options.add_argument("headless") # 창 숨기는 옵션 추가
    print('드라이버 실행 / 창옵션 숨김 완료')

    # 드라이버 변수 지정
    core_driver = webdriver.Chrome(options=options)

    # 접속 페이지 지정
    core_driver.get("https://www.orderqueen.kr/backoffice_admin/login.itp")

 

      → 로그인 input 창에 ID, PW 자동입력 : core_driver.find_element(by='태그', value = '속성값').send_keys(변수값)

    # 입력 : 아이디(.find_element, .send_keys) / find_element 중 id의 값이 id인 부분을 찾고 값을 입력
    core_driver.find_element(by='id', value = 'userId').send_keys(per_id)
    # 입력: 비밀번호(.find_element, .send_keys) / find_element 중 id의 값이 pw인 부분을 찾고 값을 입력
    core_driver.find_element(by='id', value = 'pw').send_keys(per_pw)

 

      → 로그인 버튼 자동클릭 : core_driver.find_element(by = '태그', value = '속성값').click()

    core_driver.find_element(by = 'id', value = 'btnLoginNew').click()
    print('계정/비번 입력완료')
    print('로그인 성공')
    print(f'현재 url 주소\t:\t{core_driver.current_url}')
    time.sleep(2)

 

      → 일자, 총 매출금액, 시간대별 매출금액 데이터 추출 : core_driver.find_element(By.태그, value = '태그값').text

    # 추출 : 데이터
    total_sale = core_driver.find_element(By.XPATH, value = '//*[@id="tbl-kiosk"]/tbody[2]/tr/td[2]').text
    print(f'{now} 누적매출액(당일기준)\t:\t{total_sale} 원')
    p = 0
    for v in range(1,25):
        time_zone = core_driver.find_element(By.XPATH, value = '//*[@id="tbl-time"]/tbody[1]/tr['+ str(v) + ']/td[1]').text
        sale_cnt =  core_driver.find_element(By.XPATH, value = '//*[@id="tbl-time"]/tbody[1]/tr['+ str(v) + ']/td[3]').text
        time_sale = core_driver.find_element(By.XPATH, value = '//*[@id="tbl-time"]/tbody[1]/tr[' + str(v) + ']/td[2]').text
        time_sale_int = int(time_sale.replace(',',''))
        p += time_sale_int
        excel_sheet.append([now, time_zone, sale_cnt, time_sale, p])
        print(f'시간대 : {time_zone}\t 판매건수 : {sale_cnt}\t 매출액 : {time_sale} 원\t 소계 : {p} 원')
    print(f'{now} 데이터 갱신 완료 / 현시간까지 소계 : {p} 원')

 

  ○ 구글 스프레드시트 API

      → 구글스프레드시트 연동관련 세팅

    # 구글스프레드시트 연동을 위한 사용자 세팅
    my_gs_json = 'json 파일 위치'
    gs_account_detail = gspread.service_account(my_gs_json) #사용자 계정 json 파일 사용 및 활성화
    main_gs_sheet = '사용시트 url' #구글 사용시트 주소
    useSheet = gs_account_detail.open_by_url(main_gs_sheet) #사용자 계정이 사용하고자하는 시트 url 설정
    print('구글 스프레드시트 연동 성공')

     * API 연동관련 아래 참조

 

      → 구글스프레드시트 업데이트

    # 구글 엑셀시트 업데이트 
    my_sheet = useSheet.worksheet('일일 매출현황') #시트명과 동일하게 기재
    my_sheet.update('a1','날 짜')   #a열 1행 필드명 지정
    my_sheet.update('b1','현재 매출') #b열 1행 필드명 지정
    my_sheet.update(f'a{code_execution_cnt+1}', now)         #회차수 = 행 순번 / 코드시행마다 값 추가
    my_sheet.update(f'b{code_execution_cnt+1}', total_sale + '원')

 

  ○ 엑셀저장

      → 엑셀 세팅

    # 엑셀파일 세팅
    excel_data = openpyxl.Workbook() #엑셀파일 생성
    excel_sheet = excel_data.active #데이터 적재 시트 지정 및 활성화
    excel_sheet.column_dimensions['A'].width = 10   #엑셀 A열 너비 조정
    excel_sheet.column_dimensions['B'].width = 10   #엑셀 B열 너비 조정
    excel_sheet.column_dimensions['C'].width = 10   #엑셀 C열 너비 조정
    excel_sheet.column_dimensions['D'].width = 10   #엑셀 D열 너비 조정
    excel_sheet.column_dimensions['E'].width = 10   #엑셀 E열 너비 조정
    excel_sheet.append(['오늘날짜', '시간대','판매건수','매출액','중간소계'])  #열별 1 행 필드명 지정
    print('엑셀파일 세팅 완료')

 

      → 엑셀 저장 및 종료 : excel_data.save('경로.xlsx'), excel_data.close()

    # 엑셀저장
    if code_execution_cnt == code_execution_max:  #시행차수가 24회(execution_max)가되면 엑셀저장 및 기능 종료
        excel_data.save('cureent_saleprice.xlsx')
        excel_data.close()
        print(f'{code_execution_cnt} 회차 시행완료 및 코드실행 종료')  
        exit()

 

  ○ 카카오톡 API

      → 토큰 callback

import requests
import json

url = 'https://kauth.kakao.com/oauth/token'
per_id = 'rest api 키'
redirect_url = '개인이 설정한 경로'
code = '리다이렉트된 키 입력'

data = {
    'grant_type' : 'authorization_code',
    'client_id' : per_id,
    'redirect_url' : redirect_url,
    'code' : code
}

#토큰 수신 및 덮어쓰기
response = requests.post(url, data=data)
tokens = response.json()

with open('token, json','w') as kakao:  #받은 토큰 덮어쓰기 저장을 위해 코드작성
    json.dump(tokens, kakao)

     * API 연동관련 아래 참조

 

      → 토큰 use : 저장한 토큰을 읽어 다시 url 헤더 데이터로 담아 발신

import requests
import json

with open('token, json','r') as kakao:
    tokens = json.load(kakao)

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

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

data={
    "template_object": json.dumps({
        "object_type":"text",
        "text":"전송할 내용",
        "link":{
            "web_url":"www.google.com"
        }
    })
}

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

 

 코드전체

# 필요 라이브러리 호출
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options        #자동꺼짐방지옵션 라이브러리
from datetime import datetime
import openpyxl  #엑셀활용위해 사용
import schedule #주기적실행을 위해 설정
import time #타임설정
import gspread  #구글스프레드시트 연동을 위한 라이브러리
import requests #카카오톡 파싱을 위한 라이브러리
import json #카카오톡 json 파일을 위한 라이브러리

# □■□■□■□■ 주기적으로 코드실행을 위한 변수
code_execution_cnt = 0
code_execution_max = 24  #24시간 기준으로 24지정

# □■□■□■□■ 함수정의
def action_start():
    # 전역변수 선언 및 회수출력
    global code_execution_cnt
    code_execution_cnt += 1
    print(f'{code_execution_cnt}회차 시작')  

    # 구글스프레드시트 연동을 위한 사용자 세팅
    my_gs_json = 'json 파일 경로'
    gs_account_detail = gspread.service_account(my_gs_json) #사용자 계정 json 파일 사용 및 활성화
    main_gs_sheet = '사용시트 url' #구글 사용시트 주소
    useSheet = gs_account_detail.open_by_url(main_gs_sheet) #사용자 계정이 사용하고자하는 시트 url 설정
    print('구글 스프레드시트 연동 성공')

    # 엑셀파일 세팅
    excel_data = openpyxl.Workbook() #엑셀파일 생성
    excel_sheet = excel_data.active #데이터 적재 시트 지정 및 활성화
    excel_sheet.column_dimensions['A'].width = 10   #엑셀 A열 너비 조정
    excel_sheet.column_dimensions['B'].width = 10   #엑셀 B열 너비 조정
    excel_sheet.column_dimensions['C'].width = 10   #엑셀 C열 너비 조정
    excel_sheet.column_dimensions['D'].width = 10   #엑셀 D열 너비 조정
    excel_sheet.column_dimensions['E'].width = 10   #엑셀 E열 너비 조정
    excel_sheet.append(['오늘날짜', '시간대','판매건수','매출액','중간소계'])  #열별 1 행 필드명 지정
    print('엑셀파일 세팅 완료')

    # 기본값 변수지정
    per_id = '로그인 ID'
    per_pw = '로그인 PW'
    now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    now_YMD = datetime.now().strftime('%Y-%m-%d')
    
    # 브라우저 자동 꺼짐옵션지정
    chrome_options = Options()
    chrome_options.add_experimental_option("detach", True)

    # 셀레니움옵션기능 활성화
    options = webdriver.ChromeOptions()
    options.add_argument("headless") # 창 숨기는 옵션 추가
    print('드라이버 실행 / 창옵션 숨김 완료')

    # 드라이버 변수 지정
    core_driver = webdriver.Chrome(options=options)

    # 접속 페이지 지정
    core_driver.get("https://www.orderqueen.kr/backoffice_admin/login.itp")

    # 입력 : 아이디(.find_element, .send_keys) / find_element 중 id의 값이 id인 부분을 찾고 값을 입력
    core_driver.find_element(by='id', value = 'userId').send_keys(per_id)
    # 입력: 비밀번호(.find_element, .send_keys) / find_element 중 id의 값이 pw인 부분을 찾고 값을 입력
    core_driver.find_element(by='id', value = 'pw').send_keys(per_pw)
    time.sleep(1)
    core_driver.find_element(by = 'id', value = 'btnLoginNew').click()
    print('계정/비번 입력완료')
    print('로그인 성공')
    print(f'현재 url 주소\t:\t{core_driver.current_url}')
    time.sleep(2)

    # 추출 : 데이터
    total_sale = core_driver.find_element(By.XPATH, value = '//*[@id="tbl-kiosk"]/tbody[2]/tr/td[2]').text
    print(f'{now} 누적매출액(당일기준)\t:\t{total_sale} 원')
    p = 0
    for v in range(1,25):
        time_zone = core_driver.find_element(By.XPATH, value = '//*[@id="tbl-time"]/tbody[1]/tr['+ str(v) + ']/td[1]').text
        sale_cnt =  core_driver.find_element(By.XPATH, value = '//*[@id="tbl-time"]/tbody[1]/tr['+ str(v) + ']/td[3]').text
        time_sale = core_driver.find_element(By.XPATH, value = '//*[@id="tbl-time"]/tbody[1]/tr[' + str(v) + ']/td[2]').text
        time_sale_int = int(time_sale.replace(',',''))
        p += time_sale_int
        excel_sheet.append([now, time_zone, sale_cnt, time_sale, p])
        print(f'시간대 : {time_zone}\t 판매건수 : {sale_cnt}\t 매출액 : {time_sale} 원\t 소계 : {p} 원')
    print(f'{now} 데이터 갱신 완료 / 현시간까지 소계 : {p} 원')

    # 구글 엑셀시트 업데이트 
    my_sheet = useSheet.worksheet('일일 매출현황') #시트명과 동일하게 기재
    my_sheet.update('a1','날 짜')
    my_sheet.update('b1','현재 매출')
    my_sheet.update(f'a{code_execution_cnt+1}', now)         #회차수 = 행 순번 / 코드시행마다 값 추가
    my_sheet.update(f'b{code_execution_cnt+1}', total_sale + '원')

    #카카오톡
    with open('token, json','r') as kakao:
        tokens = json.load(kakao)
    
    url="https://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"{now}  / 현재 매출액 : {total_sale} 원",
            "link":{
                "web_url":"연결 url"
            }
        })
    }
    response = requests.post(url, headers=headers, data=data)
    response.status_code
    print(f'상태 : {response.status_code} ')
    if response.json().get('result_code') == 0:
        print('메시지를 성공적으로 보냈습니다.')
    else:
        print('메시지를 성공적으로 보내지 못했습니다. 오류메시지 : ' + str(response.json()))

    # 엑셀저장
    if code_execution_cnt == code_execution_max:  #시행차수가 24회(execution_max)가되면 엑셀저장 및 기능 종료
        excel_data.save('cureent_saleprice.xlsx')
        excel_data.close()
        print(f'{code_execution_cnt} 회차 시행완료 및 코드실행 종료')  
        exit()
    #--------------------------------------------------------함수정의 끝--------------------------------------------------------

# □■□■□■□■ 함수실행
# 1초에 한번씩 함수 실행 schedule.every(1).seconds.do(함수)
# 1분에 한번씩 함수 실행 schedule.every(1).minutes.do(함수)
# 2시간에 한번씩 함수 실행 schedule.every(1).hours.do(함수)

schedule.every(1).hours.do(action_start)  # 1시간 마다 action_start 함수 실행

while True:
    schedule.run_pending()  # 함수 실행 메서드 .run_pending()
    if code_execution_cnt == code_execution_max:  # 코드 시행 회수가 24이상되면 실행 멈춤
        break