Python/웹스크래핑.데이터수집

[데이터수집] 로또번호 전송봇 만들기

hayjo 2021. 1. 4. 15:37

매주 토요일 저녁 8시 47분마다

동행복권 사이트(dhlottery.co.kr/common.do?method=main)에서 해당 주차 당첨번호를 확인 후 전송하는 텔레그램봇 작성

당첨번호 확인이 지연될 경우, 완료될 때까지 5분 단위로 재실행하고, 재시도하겠다는 메시지를 보낸다.


로또사이트는 참으로 친절해서 아래 url 정보만 있으면 번호를 바로 조회할 수 있다.

url = 'https://dhlottery.co.kr/gameResult.do?method=byWin&drwNo=' + 회차정보

 

이제 매주의 회차 정보를 구하면 된다.

로또 추첨은 매주 1회 진행하고, 그때마다 1회차씩 증가하므로

처음 시작한 1회(2002. 12. 07.) 기준으로 몇주가 지나갔는가를 계산하면 된다.

조회 대상 날짜에서 시작일을 뺀 다음, 주 단위로 환산하기 위해 7로 나누고, 거기에 첫 시작회차 숫자인 1을 더한다.

from datetime import datetime, timedelta

def getWeeks(year, month, day, baseDay = datetime(2002, 12, 7)):
    howManyDays = datetime(year, month, day) - baseDay
    return int(howManyDays.days/7) + 1

 

예를 들어 최신 회차인 2021. 01. 02.인 경우, 시작일로부터 6601일이 경과했으므로

7로 나누면 943이 되고, 회차는 944회차가 된다.

 

회차를 구했으니 requests를 보내본다.

import requests

baseURL = 'https://dhlottery.co.kr/gameResult.do?method=byWin&drwNo='
data = requests.get(baseURL + getWeeks(2021, 1, 2))

print(data.text)
'''
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="EUC-KR">
<meta id="utitle" name="title" content="동행복권">
<meta id="desc" name="description" content="동행복권 944회 당첨번호 2,13,16,19,32,33+42. 1등 총 13명, 1인당 당첨금액 1,961,836,356원.">
<title>로또6/45 - 회차별 당첨번호</title>
<title>동행복권</title>
'''

필요한 데이터는 head 최상단에 들어있다. meta 태그에서 id desc로 검색하고, content를 얻으면 된다.

from bs4 import BeautifulSoup
soup = BeautifulSoup(data.text, 'html.parser')

numberData = soup.find('meta', id='desc')['content']
print(numberData)
'''
동행복권 944회 당첨번호 2,13,16,19,32,33+42. 1등 총 13명, 1인당 당첨금액 1,961,836,356원.
'''

 

데이터를 모바일로 보낼 것이라서 줄바꿈이 들어갔으면 좋겠다.

def parse(numberData):
    result = numberData.replace(" 당첨번호 ", "\n")
    result = result.replace("+", "\n2등 보너스: ")
    result = result.replace(". ", ".\n")
    result = result.replace(", 1인당 당첨금액 ", ", 각 ")
    return result

parsed = parse(numberData)
print(parsed)
'''
동행복권 944회
2,13,16,19,32,33
2등 보너스: 42.
1등 총 13명, 각 1,961,836,356원.
'''

 

이제 혹시 확인이 지연될 경우를 위한 에러처리를 추가한다.

아직 업데이트되지 않은 945회차 열람을 시도하면

url945 = 'https://dhlottery.co.kr/gameResult.do?method=byWin&drwNo=' + str(945)
testData = requests.get(url945).text
print(testData)

'''
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="EUC-KR">
<meta id="utitle" name="title" content="동행복권">
<meta id="desc" name="description" content="동행복권 회 당첨번호 ,,,,,+. 1등 총 명, 1인당 당첨금액 원.">
<title>로또6/45 - 회차별 당첨번호</title>
<title>동행복권</title>
'''

해당 구간 데이터만 생략되어 리턴된다. 이 데이터를 위의 parse 함수에 넣으면 아래와 같이 된다.

print(parsed(testData))
'''
,,,,,
2등 보너스: .
1등 총 명, 각 원.
'''

이 경우는 '아직 확인되지 않았습니다'라는 결과를 리턴하는 편이 나을 것 같다.

확인에 실패한 경우 재실행을 해야하기 때문에, 완료여부를 1번째 인자에 넣어서 리턴하기로 한다.

def parse(numberData, weeks):
    result = numberData.replace(" 당첨번호 ", "\n")
    result = result.replace("+", "\n2등 보너스: ")
    result = result.replace(". ", ".\n")
    result = result.replace(", 1인당 당첨금액 ", ", 각 ")
    if ',,,,,' in result:
        result = str(weeks) + '회차는 아직 확인되지 않았습니다.'
        return False, result
    return True, result

 

이제 정리해서, 봇에 연결([TelegramBot] 봇 생성과 메시지전송)하고, 성공할 때까지 반복실행하도록 한다.

def getData(current=None):
    baseURL = 'https://dhlottery.co.kr/gameResult.do?method=byWin&drwNo='
    if current is None:
        current = datetime.datetime.now()
    weeks = str(getWeeks(current.year, current.month, current.day))
    url = baseURL + weeks
    data = requests.get(url, headers=headers)
    soup = BeautifulSoup(data.text, 'html.parser')
    numberData = soup.find('meta', id='desc')['content']
    boolean, result = parse(numberData, weeks)
    return boolean, result


def replay(something, current, sleep, bot, chatid):
    while True:
        boolean, result = something(current)
        if boolean:
            bot.sendMessage(chatid, text=result)
            break
        waitingMsg = result + '\n' + str(int(sleep/60)) + '분 후에 다시 확인합니다.'
        bot.sendMessage(chatid, text=waitingMsg)
        time.sleep(sleep)

 

한 사이클이 완료되었으니, 매주 실행하도록 지정한다. [스케쥴링] 특정 시간에 실행하기 - 휴장일 커버에서 썼던 방법을 수정했다.

실행 기준 일자를 확인하고,

토요일 추첨전인 경우 추첨시간(20시 47분)까지 sleep,

추첨후인 경우 해당 일자 작업을 실행 후 sleep,

토요일 외의 일자인 경우 다음 토요일 20시 47분까지 sleep

def runEvery(days, times, replay, something, sleep, bot, chatid, current=None):
    if current is None:
        current = datetime.datetime.now()
    gameTime = datetime.datetime(current.year, current.month, current.day,
                                 times[0], times[1])
    if current.weekday() in days:  # 토요일인 경우
        if current < gameTime:  # 추첨전인 경우
            sleepTime = (gameTime - current).total_seconds()
            print("다음 실행시각:", gameTime, sleepTime)
            time.sleep(sleepTime)
        else:  # 추첨이 끝난 경우
            print("전송합니다.")
            replay(something, current, sleep, bot, chatid)  # 실행
            pass  # 나머지 시간에 실행하도록 리턴
    # 날짜 넘기기
    plusDay = 5 - current.weekday()
    if plusDay <= 0:  # 토/일요일인 경우
        plusDay += 7  # 다음주로 넘기기
    nextTime = gameTime + datetime.timedelta(days=plusDay)
    sleepTime = (nextTime - current).total_seconds()
    print("다음 실행시각:", nextTime, sleepTime)
    time.sleep(sleepTime)


while True:
    print(runEvery([5], [20, 47], replay, getData, 300, BOTobject, chatID))

 

이제 백그라운드에서 돌리고 로그를 저장한다. (봇 항상 켜두기)

# nohup python -u scripts.py > logfile.log 2>&1 &

로그를 확인해보니 정상적으로 작동하고 있다.

'''
nohup: ignoring input
다음 실행시각: 2021-01-09 20:47:00 451427.048589
'''