이전글보기
[정보/Discord Bot] - [discord.py 2.0] 13. Modal 기능으로 사용자입력창 띄우기
[정보/Discord Bot] - [discord.py 2.0] 14. 오류 발생 시 예외 처리하기
[정보/Discord Bot] - [discord.py 2.0] 15. 로또복권 정보 출력하기 (beautifulsoup4 library) - #1 사전 library 준비
[정보/Discord Bot] - [discord.py 2.0] 15. 로또복권 정보 출력하기 (beautifulsoup4 library) - #2 최신 로또 번호 파싱하기
[정보/Discord Bot] - [discord.py 2.0] 15. 로또복권 정보 출력하기 - #3 모든 당첨내역 다운로드하기
저번 포스팅에서 모든 당첨번호의 리스트를 다운받았었죠 !
이번엔 다운받았던 리스트를 파싱하여 사용하기 편하도록 가공하도록 해보겠습니다.
다운받았던 lottery****.xls 을 열어보시면 아래처럼 엑셀로 열리지만 실상은
회차별 추첨결과 |
년도 | 회차 | 추첨일 | 1등 | 2등 | 3등 | 4등 | 5등 | 당첨번호 | |||||||||||
당첨자수 | 당첨금액 | 당첨자수 | 당첨금액 | 당첨자수 | 당첨금액 | 당첨자수 | 당첨금액 | 당첨자수 | 당첨금액 | 1 | 2 | 3 | 4 | 5 | 6 | 보너스 | |||
2022 | 1033 | 2022.09.17 | 13 | 1,913,414,943원 | 79 | 52,477,625원 | 3,083 | 1,344,708원 | 145,505 | 50,000원 | 2,376,004 | 5,000원 | 3 | 11 | 15 | 20 | 35 | 44 | 10 |
1032 | 2022.09.10 | 10 | 2,675,257,538원 | 90 | 49,541,807원 | 3,078 | 1,448,591원 | 149,807 | 50,000원 | 2,458,611 | 5,000원 | 1 | 6 | 12 | 19 | 36 | 42 | 28 | |
1031 | 2022.09.03 | 8 | 3,213,957,563원 | 64 | 66,957,450원 | 2,789 | 1,536,493원 | 132,815 | 50,000원 | 2,247,015 | 5,000원 | 6 | 7 | 22 | 32 | 35 | 36 | 19 | |
1030 | 2022.08.27 | 19 | 1,276,406,507원 | 104 | 38,864,942원 | 3,278 | 1,233,055원 | 154,929 | 50,000원 | 2,473,576 | 5,000원 | 2 | 5 | 11 | 17 | 24 | 29 | 9 | |
1029 | 2022.08.20 | 10 | 2,527,848,450원 | 62 | 67,952,916원 | 2,614 | 1,611,738원 | 125,573 | 50,000원 | 2,136,972 | 5,000원 | 12 | 30 | 32 | 37 | 39 | 41 | 24 |
이렇게 html로 구성되어있는 파일입니다.
물론 윈도우에서 엑셀로 열리긴 해도 python에서는 엑셀을 파싱하는 라이브러리를 통한 파싱을 지원하지는 않더라구요..
이번에도 추가되는 코드는 비슷합니다 Lottery(commands.Cog) 에 동작호출을 위한 명령어 추가 -> class LotteryFunction 에 동작기능 추가 순이죠.
LotteryFunction 에 들어갈 함수부터 보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# 다운받은 리스트를 통해 계산
def calculate_list(self):
if os.path.isfile(self.listFilePath):
for idx in range(1, 46):
self.mCounterList[str(idx)] = 0 # 리스트 초기화
list_xml = open(self.listFilePath, encoding='cp949') # 저장된 list 불러오기
soup = BeautifulSoup(list_xml, 'html.parser') # 데이터 파싱
total_info = soup.findAll('tr')
default_row = 3 # 로또 list 에서 추첨 번호가 시작 하는 행
for row in range(default_row, len(total_info)):
row_data = total_info[row].findAll('td')
max_col = len(row_data)
for col in range(max_col-7, max_col):
# 각 숫자가 뽑힌 횟수 계산
self.mCounterList[row_data[col].text] += 1
else:
self.download_total()
self.calculate_list()
|
cs |
def calculate_list(self):
2 : 계산기능이 포함된 함수를 정의합니다.
if os.path.isfile(self.listFilePath):
3 : 이전 포스팅에서 작성한 모든 당첨내역 다운로드 기능을 통해 다운로드받은 파일이 있는 경우에 대한 조건문입니다.
만약 존재하지 않을경우, 16~18 line 에서 다시 다운로드 받고, 함수를 재호출합니다
for idx in range(1, 46):
self.mCounterList[str(idx)] = 0 # 리스트 초기화
4~5 : 멤버변수인 mCounterList 를 초기화합니다.
여기서 mCounterList의 자료형은 Dictinary 로, "로또번호":당첨횟수 쌍으로 구성하려고 합니다.
list_xml = open(self.listFilePath, encoding='cp949') # 저장된 list 불러오기
6 : 저장된 list 파일을 list_xml 변수에 open 합니다. 파일 내부에 한글이 포함되어있기 때문에 open시에 encoding='cp949'를 추가해줘야합니다.
soup = BeautifulSoup(list_xml, 'html.parser') # 데이터 파싱
total_info = soup.findAll('tr')
default_row = 3 # 로또 list 에서 추첨 번호가 시작 하는 행
7 : 6line 에서 open 한 파일을 BeatifulSoup 라이브러리의 html.parser 를 통해 soup 객체에 저장합니다.
8 : 저장된 soup 객체에서 태그가 "tr" 즉, 행 단위로 나누어 total_info 변수에 저장합니다.
9 : 맨 위에 첨부된 자료형태를 보자면 저희가 파싱해야 하는 정보(로또번호)는 4번째행(0-1-2-3) 부터 시작하는것을 알 수 있으므로 미리 보기 편하게 변수로 저장해놓았습니다.
for row in range(default_row, len(total_info)):
row_data = total_info[row].findAll('td')
max_col = len(row_data)
for col in range(max_col-7, max_col):
# 각 숫자가 뽑힌 횟수 계산
self.mCounterList[row_data[col].text] += 1
10 : 파싱해야 하는 첫행(default_row) 부터 자료의 맨 마지막 행(len(total_info)) 까지 행번호(row)를 반복하는 출력문입니다.
11 : 전체행(total_info)에서 반복하는 행(row)에 대한 정보(total_info[row]) 에서 모든 열 정보('td')를 찾아 row_data로 저장합니다.
12 : 저장된 열의 갯수(len(row_data)) 를 확인하여 max_col 변수에 저장합니다.
13 : 파싱해야하는 열의 열번호를 반복하는 출력문입니다
로또의 번호가 해당 행의 마지막부터 7번째까지에 저장되어 있으므로 range(max_col-7, max_col) 로 세팅합니다.
15 : 각 행,열 에 당첨번호를 key 로 하여 해당하는 mCounterList에 +1 을 해줍니다.
전체 동작 소스코드는 다음과 같습니다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | import os import glob import discord from discord.ext import commands from bs4 import BeautifulSoup import urllib.request class LotteryFunction: def __init__(self): self.lastGameCount = None # 1033 self.lastGameDate = None # (2022년 09월 17일 추첨) self.lastGameNumbers = [] self.parse_newest() self.mCounterList = {} # 로또 숫자 별 추첨 횟수 self.listFilePath = f'./lottery{self.lastGameCount}.xls' # 현재 회차 정보 파싱 def parse_newest(self): self.lastGameNumbers.clear() url = 'https://dhlottery.co.kr/gameResult.do?method=byWin' webpage = urllib.request.urlopen(url) soup = BeautifulSoup(webpage, 'html.parser') self.lastGameCount = soup.select_one('div.win_result > h4 > strong').get_text().split("회")[0] self.lastGameDate = soup.select_one('div.win_result > p').get_text() numberList = soup.select('div.win_result > div > .num > p .ball_645') for number in numberList: self.lastGameNumbers.append(number.get_text()) def delete_list(self, filename: str): for name in glob.glob(filename): print(name + "deleted") os.remove(name) # 모든 추첨 번호 다운 로드 def download_total(self): if os.path.isfile(self.listFilePath): print("lottery list exist") else: self.delete_list('*[0-9].xls') start_count = 1 url = f'https://dhlottery.co.kr/gameResult.do?method=allWinExel&gubun=byWin&nowPage=1&' \ f'drwNoStart={start_count}&drwNoEnd={self.lastGameCount}' urllib.request.urlretrieve(url, self.listFilePath) # 다운받은 리스트를 통해 계산 def calculate_list(self): if os.path.isfile(self.listFilePath): for idx in range(1, 46): self.mCounterList[str(idx)] = 0 # 리스트 초기화 default_row = 3 # 로또 list 에서 추첨 번호가 시작 하는 행 list_xml = open(self.listFilePath, encoding='cp949') # 저장된 list 불러오기 soup = BeautifulSoup(list_xml, 'html.parser') # 데이터 파싱 total_info = soup.findAll('tr') for row in range(default_row, len(total_info)): row_data = total_info[row].findAll('td') max_col = len(row_data) for col in range(max_col-7, max_col): # 각 숫자가 뽑힌 횟수 계산 self.mCounterList[row_data[col].text] += 1 else: self.download_total() self.calculate_list() class Lottery(commands.Cog): def __init__(self, app): self.app = app self.lottery = LotteryFunction() @commands.command(name="로또") async def lottery(self, ctx): self.lottery.parse_newest() embed = discord.Embed(title="로또 추첨 번호", description="최근 로또 번호를 출력합니다", colour=0xffffff) embed.set_thumbnail(url="https://dhlottery.co.kr/images/layout/logo-header.png") # 데이터로부터 추첨날짜 확인 embed.add_field(name="추첨날짜", value=self.lottery.lastGameDate, inline=True) # 데이터로부터 회차 확인 embed.add_field(name="회차", value=self.lottery.lastGameCount+"회", inline=True) embed.add_field(name="추첨번호", value=self.lottery.lastGameNumbers, inline=False) await ctx.send(embed=embed) @commands.command(name="다운") async def download_list(self, ctx): msg = await ctx.send("다운로드 시작") self.lottery.download_total() await ctx.message.delete() await msg.delete() await ctx.send("다운로드 완료", delete_after=5) @commands.command(name="계산") async def calc_list(self, ctx): msg = await ctx.send("계산시작") self.lottery.calculate_list() await msg.delete() embed = discord.Embed(title="로또 당첨번호 내역", description="번호별 당첨 횟수를 출력합니다") embed.add_field(name="내역", value=self.lottery.mCounterList, inline=True) await ctx.send("계산완료", embed=embed) async def setup(app): await app.add_cog(Lottery(app)) | cs |
Cogs 에 추가된 "!계산" 명령어는 임시로 확인하기 위한 명령어 이기도 하고..
그저 이전에 사용해오던 코드의 복붙이나 다름없으니 설명은 생략하도록 할게요
명령어 사용시 결과는 다음과 같습니다
동행복권 사이트를 통해 얻어온 정보 중 출력할만한것은 다 출력하였으니 `15.로또복권 정보 출력하기` 챕터는 여기까지만 이어가도록 할게요 !
포스팅에 사용된 모든 소스코드는 아래 Github에서 확인하실 수 있습니다.
https://github.com/aochfl/ChoRi_TestBot
참고자료
https://discord.com/developers/docs/reference - ( Discord Developer API )
https://discordpy.readthedocs.io/en/latest/index.html - ( discord.py library 문서 )
'정보 > Discord Bot' 카테고리의 다른 글
[discord.py 2.0] lottery.py 소스코드 정리 (0) | 2022.09.27 |
---|---|
[discord.py 2.0] 15. 로또복권 정보 출력하기 - #3 모든 당첨내역 다운로드하기 (1) | 2022.09.21 |
[discord.py 2.0] 15. 로또복권 정보 출력하기 (beautifulsoup4 library) - #2 최신 로또 번호 파싱하기 (0) | 2022.09.19 |
[discord.py 2.0] 15. 로또복권 정보 출력하기 (beautifulsoup4 library) - #1 사전 library 준비 (0) | 2022.09.19 |
[discord.py 2.0] 14. 오류 발생 시 예외 처리하기 (0) | 2022.09.16 |