(機選彩票號碼+爬取最新開獎號碼 | 2021-04-21)
學習記錄,好記不如爛筆頭
這個程序作用是<機選三種彩票類型的號碼>
程序內包含功能有如下:
- 自動獲取最新的三種彩票的開獎號碼
- 隨機生成三種彩票類型的號碼
- 注冊
- 登錄
- 密碼加密
- 數據寫入文件
- 文件中提取數據
- 時間模塊判斷早中晚
先上個演示 | 再附上打包后的程序exe | 再貼上完整源代碼
截至2021-04-20的最新彩票開獎信息和程序獲取的一致,如圖:
演示程序下載>>>
點擊下載提取密碼:cisj
import re as m_re
import os as m_os
import time as m_time
import random as m_random
import easygui as m_easygui
import requests as m_requests
# 取開獎號碼
class HtmlInfo():
def __init__(self):
self.browser_header = {
"User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36"
"(KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"}
#福利彩票
self.ddd_nums = {}# 福彩3D
self.ssq_nums = {}# 雙色球
self.qlc_nums = {}# 七樂彩
self.urls = [
r'http://kaijiang.500.com/sd.shtml',
r'http://kaijiang.500.com/ssq.shtml',
r'http://kaijiang.500.com/qlc.shtml'
]
self.html_lable = [
r'<span class="span_right">(.*?)</span>',# 開獎日期-0
r'<strong>(.*?)</strong>',# 開獎期號-1
r'<li class="ball_orange">(.*?)</li>',# 福彩3D-2
r'<li class="ball_red">(.*?)</li>',# 雙色球-紅-3
r'<li class="ball_blue">(.*?)</li>',# 雙色球-藍-4
r'<li class="ball_red">(.*?)</li>',# 七樂彩-紅-5
r'<li class="ball_blue">(.*?)</li>'# 七樂彩-藍-6
]
def get_HtmlInfo(self, url):
try:
html = m_requests.get(url, headers=self.browser_header)
html.encoding = 'gbk'# 一下午試圖想在正則中解決它...cnm,耽誤不少時間
except TypeError:
print('網絡中斷或其他原因!')
return# 直接中斷程序, 函數內用 return | 函數外用 exit()
# 取最新的日期
# lottery_date = m_re.findall('<td align="center">(.*?)</td>', html.text, m_re.S)
# 取最新的開獎號碼
# for loop_urls in range(len(self.urls)):
if self.urls[0] == url:
# 福彩3D: 開獎日期, 開獎期號, 開獎號碼, 寫入字典
self.lottery_date = m_re.findall(self.html_lable[0], html.text, m_re.S)[0]
lottery_date_nums = m_re.findall(self.html_lable[1], html.text, m_re.S)[1]
lottery_nums = m_re.findall(self.html_lable[2], html.text, m_re.S)
# 數據進字典
self.ddd_nums[lottery_date_nums] = lottery_nums
# print(self.ddd_nums)
if self.urls[1] == url:
# 雙色球: 號碼列表-合並期號, 開獎日期, 開獎期號, 開獎號碼 紅六個 / 藍一個, 紅藍號碼合並列表
lottery_nums = []
lottery_date = m_re.findall(self.html_lable[0], html.text, m_re.S)[0]
lottery_date_nums = m_re.findall(self.html_lable[1], html.text, m_re.S)[1]
lottery_nums_red = m_re.findall(self.html_lable[3], html.text, m_re.S)[:6]
lottery_nums_blue = m_re.findall(self.html_lable[4], html.text, m_re.S)[:1]
# 下面用extend 插了兩次是因為我想把紅藍球變成一個列表, 如果弄成只插一次就會造成列表套列表,很是疑惑
lottery_nums.extend(lottery_nums_red)
lottery_nums.extend(lottery_nums_blue)
# 數據進字典
self.ssq_nums[lottery_date_nums] = lottery_nums
# print(self.ssq_nums)
if self.urls[2] == url:
# 七樂彩: 號碼列表-合並期號, 開獎日期, 開獎期號, 開獎號碼 紅七個 / 藍一個, 紅藍號碼合並列表
lottery_nums = []
lottery_date = m_re.findall(self.html_lable[0], html.text, m_re.S)[0]
lottery_date_nums = m_re.findall(self.html_lable[1], html.text, m_re.S)[1]
lottery_nums_red = m_re.findall(self.html_lable[5], html.text, m_re.S)[:7]
lottery_nums_blue = m_re.findall(self.html_lable[6], html.text, m_re.S)[:1]
lottery_nums.extend(lottery_nums_red)
lottery_nums.extend(lottery_nums_blue)
# 數據進字典
self.qlc_nums[lottery_date_nums] = lottery_nums
# print(self.qlc_nums)
# 對密碼加密-解密, 上面代碼很長 總感覺可以再精簡優化下, 目前對於類的使用不是很熟練
class AppCryptos():
def __init__(self):
self.token_list = [
'0000000000_'
'bC0>aB3?aA0!aG1%hI1$'
'eK6)dA8&qB4@lC0$bA0&aI0eP1#cC0$'
'!@#$%^&*()_+aF0!bG2!cE4_eC1^bE0^aE4@bC0{nB'
]
self.enctry_str = ''# 加密數據
self.dectry_str = ''# 解密數據
# 加密
def enctry_AppCryptos(self, key):# key為傳入的密碼
for i,j in zip(key, str(self.token_list)):
temp_ij = str(ord(i) + ord(j)) + str(self.token_list[0][:15])
self.enctry_str += temp_ij
# print(self.enctry_str)
return self.enctry_str
# 解密
def dectry_AppCryptos(self, key):# key為傳入的密文
for i,j in zip(key.split(str(self.token_list[0][:15]))[:-1], str(self.token_list)):
temp_ij = chr(int(i) - ord(j))
self.dectry_str += temp_ij
# print(self.dectry_str)
return self.dectry_str
# EasyGui
class EasyGuiUI():
def __init__(self):
self.app_config = [
r'AppConfig.ini',# 文件可自定義目錄存放,也可以跟主程序走
r'MainConfig.ini',# 文件跟着主程序走
r'config_path=',# 用戶自己選擇的配置文件目錄路徑
r'configfile_path=',# 用戶自己選擇的配置文件目錄路徑 + AppConfig.ini路徑
r'username=',# 用戶昵稱
r'userkey='# 加密的程序密碼的密文
]
# 取三個數為一注
self.loop_ddd = (0, 9)
# 取六個紅球,一個藍球為一注
self.loop_ssq_red = (1, 33)
self.loop_ssq_blue = (1, 16)
# 七個基本號, 一個特別號為一注
self.loop_qlc = (1, 30)
self.box_msg = [
'歡迎進入彩票號碼生成器!\n是否進行程序初始化?\n自定義配置文件目錄或程序默認目錄',
'選擇一個文件夾!',
'歡迎使用機選彩票號碼程序, 祝您早日中大獎!',
'請輸入程序密碼',
'注冊成功!',
'\n\n\n點擊下方[查看最新開獎號碼]按鈕以獲取開獎號碼'
]
self.box_title = [
'程序初始化',
'激活程序',
'登錄驗證',
'機選號碼'
]
self.indexbox_choices = [
['0', '確定'],# 用來判斷choices_msg按鈕返回值
['1', '默認'],
['2', '機選號碼'],
['3', '查看最新開獎號碼'],
['4', '退出程序']
]
self.indexbox_errmsg = [
'未知錯誤!',
'文件不存在',
'',
'',
'主程序文件失效,請重新運行程序!'
]
self.multpasswordbox_fields = [
'*昵稱',
'*程序密碼'
]
# 如果函數中已經有相同變量,應該是優先讀函數中的, 有點忘記了...
# 想起來一個, 相同方法下的變量互相調用之前,得先調用被調用的那個方法
self.temp_enctry_str = ''# 臨時存放加密的密文,寫入到文件MainConfig.ini. 如果函數中已經有相同變量,應該是優先讀函數中的
self.temp_ext_userkey = []# 臨時存放提取出來的密文.
self.temp_ext_username = []# 臨時存放提取出來的昵稱
# 運行程序 初始化界面 | 用戶選擇目錄或者程序直接走默認目錄
def init_EasyGuiUI(self):
try:
with open(self.app_config[1], encoding='utf-8') as init_f1:
init_f1.close()# 走個過程就直接關掉, 不占用
EasyGuiUI().reg_EasyGuiUI()
except OSError:
# 初始界面, 因為檢查不到文件MainConfig.ini, 所以初始化一下 目的是生成AppConfig.ini和MainConfig.ini兩個文件
# 原本還想弄一個判斷有無文件AppConfig.ini, 因為這個文件是可以讓用戶自定義目錄去生成的,
# 如果作這個判斷就把文件AppConfig.ini的目錄路徑也寫到文件MainConfig.ini中, 想了下還是沒寫這個, 只驗證有無文件MainConfig.ini
choices_msg = m_easygui.indexbox(
self.box_msg[0],
self.box_title[0],
choices=(self.indexbox_choices[0][1],self.indexbox_choices[1][1])
)
# 判斷用戶是選擇的[確定]按鈕, 開始調用diropenbox() 函數選擇目錄
if choices_msg == int(self.indexbox_choices[0][0]):
choices_path = m_easygui.diropenbox(self.box_msg[1])
# 這里會先生成文件 MainConfig.ini, 避免與下方的m_os.chdir() 函數沖突
with open(self.app_config[1], 'w', encoding='utf-8') as user_f1:
user_f1.write(
self.app_config[2] + m_os.getcwd() + ';' + '\n' +
self.app_config[3] + m_os.getcwd() + '\\' + self.app_config[1] + ';'
)
# 選擇目錄窗口如果直接關閉在這里做個TypeError處理
try:
m_os.chdir(choices_path)
except TypeError:
return
# 合並一下選擇的目錄跟文件名AppConfig.ini,得到一個完整路徑
merge_path = m_os.path.join(m_os.getcwd(), self.app_config[0])
# 根據用戶選擇的目錄直接覆寫文件AppConfig.ini
with open(merge_path, 'w', encoding='utf-8') as user_f2:
user_f2.write(
self.app_config[2] + choices_path + ';' + '\n' +
self.app_config[3] + merge_path + ';'
)
EasyGuiUI().reg_EasyGuiUI()
# 判斷用戶是選擇的[默認]按鈕, 直接在程序目錄下進行覆寫兩個文件MainConfig.ini AppConfig.ini
elif choices_msg == int(self.indexbox_choices[1][0]):
# 選擇[默認] 直接在程序所在目錄生成文件
with open(self.app_config[0], 'w', encoding='utf-8') as app_f1,\
open(self.app_config[1], 'w', encoding='utf-8') as app_f2:
app_f1.write(
self.app_config[2] + m_os.getcwd() + ';' + '\n' +
self.app_config[3] + m_os.getcwd() + '\\' + self.app_config[0] + ';'
)
app_f2.write(
self.app_config[2] + m_os.getcwd() + ';' + '\n' +
self.app_config[3] + m_os.getcwd() + '\\' + self.app_config[1] + ';'
)
EasyGuiUI().reg_EasyGuiUI()
# 注冊
def reg_EasyGuiUI(self):
# 在啟用注冊UI之前 判斷下是否已經進行了注冊, 判斷文件MainConfig.ini中有無self.app_config[4]/[5]這兩個字符串
# 這種判斷應該還有更好的寫法, 截至學到目前的知識 確實想不出了
with open(self.app_config[1], 'r', encoding='utf-8') as read_f1:
#在這個變量出來前, 原地轉圈琢磨了好久. read()這個好像並不能用在if語句的多重判斷中,期望的結果會False
read_f1_temp = read_f1.read()
if self.app_config[4] in read_f1_temp and self.app_config[5] in read_f1_temp:
return EasyGuiUI().login_EasyGuiUI()
# 這下面是原地轉圈時琢磨的
# if (self.app_config[4] and self.app_config[5]) in read_f1:
# return EasyGuiUI().login_EasyGuiUI()
# aa = m_re.search('username=*|userkey=*', i)
# if aa:
# print(aa.group())
# print(i)
# if [read_f1_temp1.strip().find('username=') for read_f1_temp1 in read_f1]:
# print('11')
# with open(self.app_config[1], 'r+', encoding='utf-8') as read_f2:
# if [read_f2_temp1.strip().find(self.app_config[5]) for read_f2_temp1 in read_f2.readlines()]:
# return EasyGuiUI().login_EasyGuiUI()
reg_values = []
reg_values = m_easygui.multpasswordbox(
self.box_msg[2],
self.box_title[1],
fields=(self.multpasswordbox_fields[0],self.multpasswordbox_fields[1])
)
while True:
# 循環后 重置self.indexbox_errmsg[2]的消息為空字符串
self.indexbox_errmsg[2] = self.indexbox_errmsg[3]
# 返回值為None,結束
if reg_values == None:
return
# 這塊還想寫一個昵稱只能輸入純英文, 程序密碼只能輸入純數字
for i in range(len(self.multpasswordbox_fields)):
if reg_values[i] == '' and self.multpasswordbox_fields[i][0] == '*' and self.multpasswordbox_fields[i][0] == '*':
self.indexbox_errmsg[2] += ('【%s】為必填項,請重新填寫!\n' % self.multpasswordbox_fields[i])
if self.indexbox_errmsg[2] == '':
break
reg_values = m_easygui.multpasswordbox(
self.indexbox_errmsg[2],
self.box_title[1],
fields=(self.multpasswordbox_fields[0],self.multpasswordbox_fields[1]),
values=reg_values# 這里是留存填寫過的內容,並顯示在程序,避免用戶二次輸入
)
# 聯動enctry_AppCryptos() 加密函數, 對用戶輸入的<程序密碼>進行加密
link_AppCryptos = AppCryptos()
link_AppCryptos.enctry_AppCryptos(reg_values[1])
self.temp_enctry_str = link_AppCryptos.enctry_str
# 將昵稱和加密的程序密碼存入文件MainConfig.ini
# 這塊應該還要做個文件中是否存在username和userkey的字符串做對應的寫入判斷(如果字符串存在多個,或者沒有,或者文件不在,或者權限不夠等)
# 不過這次就簡單寫一下數據存入文件, 其他的心里寫了就行
try:
with open(self.app_config[1], 'a', encoding='utf-8') as enctry_f1:
enctry_f1.write(
'\n' + self.app_config[4] + reg_values[0] + ';' +
'\n' + self.app_config[5] + self.temp_enctry_str + ';'
)
m_easygui.msgbox(self.box_msg[4])
EasyGuiUI().login_EasyGuiUI()
except OSError:
m_easygui.msgbox(self.indexbox_errmsg[4])
# print(self.enctry_str)
# 登錄
def login_EasyGuiUI(self):
# 登錄這塊應該也要寫一個取文件中密文的時候來個文件是否存在或文件中需要的字符串是否存在, 心里寫了!
# 想了下 驗證文件這些步驟其實可以單獨弄個函數放在那邊來調用, 這樣代碼應該可以精簡一些
# 在open的時候用'x'模式 檢查文件是否存在?
login_return_cont = m_easygui.passwordbox(self.box_msg[3], self.box_title[2])
# 讀取文件中userkey存放的密文
with open(self.app_config[1], encoding='utf-8') as dectry_f1:
# for read_line in dectry_f1:
ext_userkey = m_re.findall(r'userkey=(.*?);', dectry_f1.read(), m_re.S)
# print(ext_userkey)
# 聯動enctry_AppCryptos(),進行一次密碼加密,然后驗證加密好的密文是否存在文件內
link_AppCryptos = AppCryptos()
link_AppCryptos.dectry_AppCryptos(ext_userkey[0])
if login_return_cont == link_AppCryptos.dectry_str:
EasyGuiUI().panel_EasyGuiUI()
elif login_return_cont == None:
return
else:
return EasyGuiUI().login_EasyGuiUI()
# 登錄成功后調用的, 獲取最新開獎號碼給面板顯示
# 此方法被panel_EasyGuiUI(self) 方法來調用
def get_nums_ForPanel(self):
# 獲取最新中獎號碼, 為了給面板顯示
link_HtmlInfo = HtmlInfo()
for loop_urls in range(len(link_HtmlInfo.urls)):
link_HtmlInfo.get_HtmlInfo(link_HtmlInfo.urls[loop_urls])
dict_ddd = link_HtmlInfo.ddd_nums
dict_ssq = link_HtmlInfo.ssq_nums
dict_qlc = link_HtmlInfo.qlc_nums
dict_ddd_value = ','.join(list(dict_ddd.values())[0])
dict_ssq_value = ','.join(list(dict_ssq.values())[0])
dict_qlc_value = ','.join(list(dict_qlc.values())[0])
self.marge_msgs_get_nums_ForPanel = (
# ext_username[0] + self.box_msg[2] + '\n' +
'第[' + list(dict_ddd)[0] + ']期福彩3D開獎號碼: ' + dict_ddd_value + '\n' +
'第[ ' + list(dict_ssq)[0] + ' ]期雙色球開獎號碼: ' + dict_ssq_value + '\n' +
'第[ ' + list(dict_qlc)[0] + ' ]期七樂彩開獎號碼: ' + dict_qlc_value
)
# 機選號碼, 機選的規則都為:彩票投注中的單式投注!
# 此方法被panel_EasyGuiUI(self) 方法來調用
def get_loopnums_ForPanel(self, keyloopnums):
if keyloopnums == 'start':
# 機選福彩3D
# 使用列表推導式 把需要的每一個元素轉換成字符串,這樣做的方式是方便呈現的時候 數字后面自帶逗號
# loopnums_1_ddd = ''
loopnums_1_ddd = [str(m_random.randint(self.loop_ddd[0],self.loop_ddd[1])) for loop in range(3)]
loopnums_1_ddd = ','.join(loopnums_1_ddd)# # 三個數字轉換成字符串且用逗號來分割進行展示
# print(loopnums_1_ddd)# 輸出一下 機選出來的三個數字
# 機選雙色球
# loopnums_2_ssq = []
loopnums_2_red = [str(m_random.randint(self.loop_ssq_red[0],self.loop_ssq_red[1])) for loop in range(6)]
loopnums_2_blue = [str(m_random.randint(self.loop_ssq_blue[0],self.loop_ssq_blue[1])) for loop in range(1)]
loopnums_2_red.append(loopnums_2_blue[0])# 藍球合並到紅球的列表
loopnums_2_ssq = ','.join(loopnums_2_red)# 定一個新的變量名稱 | 七個數字轉換成字符串且用逗號來分割進行展示
# print(loopnums_2_ssq)# 輸出一下 機選出來且合並后的 紅+藍七個數字
# 機選七樂彩
loopnums_3_red = [str(m_random.randint(self.loop_qlc[0],self.loop_qlc[1])) for loop in range(7)]
loopnums_3_blue = [str(m_random.randint(self.loop_qlc[0],self.loop_qlc[1])) for loop in range(1)]
loopnums_3_red.append(loopnums_3_blue[0])
loopnums_3_qlc = ','.join(loopnums_3_red)
# print(loopnums_3_qlc)
# 三個彩種機選的號碼合並掉,給panel_EasyGuiUI() 函數中的indexbox() 調用
self.marge_msgs_get_loopnums_ForPanel = (
'機選的福彩3D號碼: ' + loopnums_1_ddd + '\n' +
'機選的雙色球號碼: ' + loopnums_2_ssq + '\n' +
'機選的七樂彩號碼: ' + loopnums_3_qlc + '\n' +
'截屏或拍照后去彩票站購買, 祝你鴻運當頭!'
)
else:
pass
# 登錄成功后 顯示獲取的最新彩票號碼 | 按鈕形式機選號碼並以msgbox() 函數顯示給用戶 | over!
def panel_EasyGuiUI(self):
self.get_nums_ForPanel()
# self.get_loopnums_ForPanel()
# 讀取文件中username存放的昵稱
with open(self.app_config[1], encoding='utf-8') as read_f1:
ext_username = m_re.findall(r'username=(.*?);', read_f1.read(), m_re.S)
# 加一個時間判斷
# 06:00~10:00>早上 10:00~12:00>中午 12:00~18:00>下午 18:00~06:00>晚上
get_time = m_time.localtime()
# print(get_time.tm_hour)
if 0 <= get_time.tm_hour <= 4:
indexbox_msg_time = '凌晨時段,注意休息: '
elif 5 <= get_time.tm_hour <= 10:
indexbox_msg_time = '早上好: '
elif 11 <= get_time.tm_hour <= 12:
indexbox_msg_time = '中午好: '
elif 13 <= get_time.tm_hour <= 18:
indexbox_msg_time = '下午好: '
elif 19 <= get_time.tm_hour <= 23:
indexbox_msg_time = '晚上好: '
else:
indexbox_msg_time = '奈何橋見: '
choices_msg = m_easygui.indexbox(
msg=(indexbox_msg_time + ext_username[0] + self.box_msg[5]),
title=self.box_title[3],
choices=(self.indexbox_choices[2][1],self.indexbox_choices[3][1],self.indexbox_choices[4][1])
)
while True:
if choices_msg == 0:
self.get_loopnums_ForPanel('start')# 寫這里是因為要每次點擊都獲取新的隨機數
# 按鈕返回0 則去機選隨機號碼展示給用戶
choices_msg = m_easygui.indexbox(
msg=self.marge_msgs_get_loopnums_ForPanel,
title=self.box_title[3],
choices=(self.indexbox_choices[2][1],self.indexbox_choices[3][1],self.indexbox_choices[4][1])
)
elif choices_msg == 1:
# 按鈕返回1 則去獲取最新號碼展示給用戶
choices_msg = m_easygui.indexbox(
msg=self.marge_msgs_get_nums_ForPanel,
title=self.box_title[3],
choices=(self.indexbox_choices[2][1],self.indexbox_choices[3][1],self.indexbox_choices[4][1])
)
elif choices_msg == 2:
# 直接結束
break
else:
# 這里比如直接關閉 返回了None
break
app_run = EasyGuiUI()
app_run.init_EasyGuiUI()
# app_run.get_loopnums_ForPanel()