ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [데이터수집] 로또번호 전송봇 만들기
    Python/웹스크래핑.데이터수집 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
    '''

     

    댓글

Designed by Tistory.