코딩/Python

[Python, Selenium] 파이썬, 셀레늄을 이용한 로또 자동 구매 프로그램

후둘기 2022. 7. 1. 14:37
반응형

매주 사야지 사야지 하다가도 까먹고 안 사는 경우가 더 많아서

셀레늄으로 한번 만들어보았다.

 

구동을 위한 준비물로는

당연히 python (3.8 이상 버전을 권장)

셀레늄 버전 4 이상 (pip로 그냥 설치하면 되는듯)

크롬드라이버 자동 업데이트를 위해서 webdriver_manager 패키지도 필요하다.

 

크롬드라이버는 자동설치 기능을 이용하기 때문에 따로 설치안해주어도 된다.

 

주의점으로는 윈도우 환경에서만 작동한다. (테스트는 안해봤지만 맥에서도 될듯)

 

기능은 크게 세가지

 

1. 예치금 잔고 체크 기능 (check_deposit 함수)

현재 예치금을 확인해서 텔레그램 메시지로 보내준다. 

 

2. 예치금 충전 (charge_deposit 함수)

예치금 충전 버튼을 눌러서 입금계좌를 텔레그램으로 보내준다. 

충전 금액은 기본값인 2만 원으로 충전되게 설정 

 

3. 로또 구매 (buy_lotto 함수)

모드 지정에 따라 자동, 수동, 일부 수동 방식으로 구매 

 

 

나는 텔레그램 토큰 정보 같은걸 config파일로 만들어서 사용하고 있다.

재활용이 편하게 전에 만들어둔걸 이렇게 쓰는데 꼭 이렇게 할 필요는 없을 것 같다. 

 

read_config 함수의 config_data 변수를 참조해서 해당 데이터를 코드에 바로 입력해서 사용해도 무방.

사용하지 않는 기능 정보는(셀레늄 리모트, 텔레그램 불필요할 경우 토큰 정보 등) 적당히 아무 값이나 넣으면 상관없음. 

봇 초기화를(bot_init함수) 안 하면 텔레그램 사용 없이 화면 출력 모드로 구동된다.

 

config.ini파일의 형태는 다음과 같다.

[server]
host = 셀레늄 리모트 서버 주소 

[user]
id = 동행복권사이트 아이디
pwd = 비밀번호

[telegram]
token = 텔레그램봇 토큰
chat_id = 수신받을 내 챗 아이디

 

아래 첨부된 코드는 그 자체로 직접 구동 시 예치금 잔고 체크 및 일정 금액 이하일 경우 충전하도록 되어 있다.

그대로 사용해도 되고, 필요에 따라 수정하면 된다. 

 

나는 아래처럼 별도 구매 파일을 작성해서 사용 중이다. 

import pylotto

conf = pylotto.read_config('config.ini')

driver_type = 'local'
lotto = pylotto.DhLottery()
lotto.driver_init(driver_type, conf['host'])
lotto.bot_init(conf['token'], conf['chat_id'])

lotto.login(conf['uid'], conf['passwd'])
lotto.buy_lotto('manual', 3, [1, 2, 3, 4, 5, 6])
lotto.buy_lotto('auto', 2)

lotto.driver.quit()

자동으로 구매할 경우

buy_lotto('auto', 수량)

 

수동은

buy_lotto('manual', 수량, 내가 원하는 번호 리스트)

 

혼합방식은

buy_lotto('mixed', 수량, 일부 번호 리스트)

 

 

메인코드는 아래와 같다.


from selenium import webdriver
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import configparser
import time
import telegram


class DhLottery:
    def __init__(self):
        self.driver = None
        self.deposit = None
        self.bot = None
        self.chat_id = None

    def driver_init(self, _mode='local', _host=None):
        _driver = None
        if _mode == 'local':
            # 크롬드라이버 자동 설치
            _driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
        elif _mode == 'remote':
            _driver = webdriver.Remote(_host, DesiredCapabilities.CHROME)
        _driver.implicitly_wait(5)
        self.driver = _driver

    def bot_init(self, _token, _chat_id):
        self.bot = telegram.Bot(token=_token)
        self.chat_id = _chat_id

    def login(self, _uid, _passwd):
        # 로그인 페이지 이동
        _url = 'https://dhlottery.co.kr/user.do?method=login&returnUrl='
        _driver = self.driver
        _driver.get(url=_url)

        _driver.find_element(By.XPATH, '//input[@name="userId"]').send_keys(_uid)  # 아이디 입력
        _driver.find_element(By.XPATH, '//input[@name="password"]').send_keys(_passwd)  # 비밀번호 입력
        _driver.execute_script("javascript:check_if_Valid3();")  # 로그인 실행

        time.sleep(3)
        self.remove_popup()  # 팝업창 제거함수 호출

    def check_deposit(self):
        # 마이페이지로 이동
        _driver = self.driver
        _driver.get(url='https://dhlottery.co.kr/userSsl.do?method=myPage')

        # 예치금 금액 읽음
        _deposit = _driver.find_element(By.XPATH, '//p[@class="total_new"]/strong').text

        if self.bot is not None:
            self.send_telegram(f'잔고 : {_deposit}원')
        _deposit = _deposit.replace(',', '')  # 천단위 쉼표 제거

        print(f'잔액: {_deposit}')

        self.deposit = int(_deposit)

    def remove_popup(self):
        _driver = self.driver

        # 생성된 팝업창을 모두 닫음
        _tabs = _driver.window_handles
        while len(_tabs) != 1:
            _driver.switch_to.window(_tabs[1])
            _driver.close()
            _tabs = _driver.window_handles

        # 첫 창으로 돌아간다
        _driver.switch_to.window(_tabs[0])

    def send_telegram(self, _msg):
        _msg = '<로또>\n' + _msg
        self.bot.sendMessage(chat_id=self.chat_id, text=_msg)

    def send_result(self, _data):
        _msg = '구매성공!!\n' + '=' * 15
        for _d in _data:
            _msg = _msg + '\n' + ','.join(_d)
        print(_msg)
        self.send_telegram(_msg)

    def charge_deposit(self):
        # 예치금 충전 페이지로 이동
        _url = 'https://dhlottery.co.kr/payment.do?method=payment'
        _driver = self.driver
        _driver.get(url=_url)

        time.sleep(1)
        _driver.execute_script("nicepayStart();")  # 충전버튼 클릭

        time.sleep(1)
        # 충전금액
        _amount = _driver.find_element(By.XPATH, '//div[@class="contents_wrap contents_result_payment"]'
                                                 '/div/table/tbody/tr[2]/td').text
        # 입금계좌
        _account = _driver.find_element(By.XPATH, '//span[@class="pay_lt"]').text

        # 충전 금액, 계좌정보 출력하거나 텔레그램 전송
        _msg = f'예치금 충전\n{_account}\n{_amount}'
        if self.bot is not None:
            self.send_telegram(_msg)
        else:
            print(_msg)

    def buy_lotto(self, _mode, _amount, _nums=None):
        # 메인 페이지로 이동
        _url = 'https://dhlottery.co.kr/common.do?method=main'
        _driver = self.driver
        _driver.get(url=_url)

        # 팝업창 닫음
        time.sleep(3)
        self.remove_popup()

        # 로또 구매 페이지로 이동
        _driver.execute_script('javascript:goLottoBuy(2);')

        # 생성된 구매 페이지로 전환
        time.sleep(3)
        _tabs = _driver.window_handles
        _driver.switch_to.window(_tabs[1])

        # 내부 iframe으로 전환
        _content = _driver.find_element(By.TAG_NAME, "iframe")
        _driver.switch_to.frame(_content)

        if _mode == 'manual':  # 수동모드
            for _n in _nums:
                _driver.find_element(By.XPATH, f'//label[@for="check645num{str(_n)}"]').click()

        elif _mode == 'auto':  # 자동모드
            _driver.find_element(By.XPATH, '//label[@for="checkAutoSelect"]').click()

        elif _mode == 'mixed':  # 혼합모드 (숫자 일부 지정, 나머지 자동)
            for _n in _nums:
                _driver.find_element(By.XPATH, f'//label[@for="check645num{str(_n)}"]').click()
            _driver.find_element(By.XPATH, '//label[@for="checkAutoSelect"]').click()

        # 수량 변경
        _select = Select(_driver.find_element(By.XPATH, '//select[@id="amoundApply"]'))
        _select.select_by_value(str(_amount))

        # 수량 입력 확인
        _driver.find_element(By.XPATH, '//input[@id="btnSelectNum"]').click()

        # 구매하기 버튼
        _driver.find_element(By.XPATH, '//input[@id="btnBuy"]').click()

        # 최종 구매 확인
        _driver.execute_script("javascript:closepopupLayerConfirm(true);")

        # 구매 번호 불러옴
        time.sleep(3)
        _res1 = _driver.find_elements(By.XPATH, '//ul[@id="reportRow"]/li')

        # 구매된 번호들을 인식
        _result = list()
        for _r1 in _res1:
            _selected = list()
            _res2 = _r1.find_elements(By.XPATH, 'div[@class="nums"]/span')
            for _r2 in _res2:
                _selected.append(_r2.text)
            _result.append(_selected)

        # 인식된 번호 텔레그램 전송
        if self.bot is not None:
            self.send_result(_result)
        else:
            print(_result)

        # iframe에서 기본 창으로 다시 변경
        _driver.switch_to.default_content()


def read_config(_conf_file):
    _config = configparser.ConfigParser()
    _config.read(_conf_file)

    _config_data = {
        'host': _config['server']['host'],  # Selenium Remote 주소
        'uid': _config['user']['id'],  # 동행복권 아이디
        'passwd': _config['user']['pwd'],  # 동행복권 비밀번호
        'token': _config['telegram']['token'],  # 텔레그램봇 토큰
        'chat_id': _config['telegram']['chat_id']  # 텔레그램 전송받을 챗아이디
    }

    return _config_data


if __name__ == '__main__':
    conf = read_config('config.ini')

    driver_type = 'local'
    lotto = DhLottery()
    lotto.driver_init(driver_type, conf['host'])
    lotto.bot_init(conf['token'], conf['chat_id'])  # 텔레그램 불필요시 비활성화

    lotto.login(conf['uid'], conf['passwd'])

    time.sleep(1)
    lotto.check_deposit()
    if lotto.deposit <= 10000:
        lotto.charge_deposit()

    lotto.driver.quit()
반응형