TC_DHL 发表于 2021-4-21 19:14:19

交作业了(机选彩票号码程序+爬取最新开奖号码) | [课后作业] 第038讲

本帖最后由 TC_DHL 于 2021-4-21 22:58 编辑

@小甲鱼
作业正好做了七天
这个程序作用是<机选三种彩票类型的号码>
里面包含有:

[*]自动获取最新的三种彩票的开奖号码
[*]随机生成三种彩票类型的号码
[*]注册
[*]登录
[*]密码加密
[*]数据写入文件
[*]文件中提取数据
[*]时间模块判断早中晚


因为是自学状态,没有人手把手教, 迫切想知道写的这些代码哪里需要改进的地方, 哪里不规范,或者说是不应该这么写等
坐等甲鱼老师和各位大佬批评!
-----------------
先上个演示 | 再附上打包后的程序exe | 再贴上完整源代码
https://dhlgits.gitee.io/blog_res/HelloFlesk-images/appdemo.gif

点击下载文件>>>密码:**** Hidden Message *****


截至2021-04-20的最新彩票开奖信息和程序获取的一致,如图:
https://dhlgits.gitee.io/blog_res/HelloFlesk-images/get-cpxinxi.png
https://dhlgits.gitee.io/blog_res/HelloFlesk-images/new_AppDemo_img1.png
https://dhlgits.gitee.io/blog_res/HelloFlesk-images/new_AppDemo.gif

重新打包了一下,新的exe执行程序会启动更快, 点击下载>>>密码:**** Hidden Message *****

更新一下对时间的判断

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 == url:
            # 福彩3D: 开奖日期, 开奖期号, 开奖号码, 写入字典
            self.lottery_date = m_re.findall(self.html_lable, html.text, m_re.S)
            lottery_date_nums = m_re.findall(self.html_lable, html.text, m_re.S)
            lottery_nums = m_re.findall(self.html_lable, html.text, m_re.S)
            # 数据进字典
            self.ddd_nums = lottery_nums
            # print(self.ddd_nums)

      if self.urls == url:
            # 双色球: 号码列表-合并期号, 开奖日期, 开奖期号, 开奖号码 红六个 / 蓝一个, 红蓝号码合并列表
            lottery_nums = []
            lottery_date = m_re.findall(self.html_lable, html.text, m_re.S)
            lottery_date_nums = m_re.findall(self.html_lable, html.text, m_re.S)
            lottery_nums_red = m_re.findall(self.html_lable, html.text, m_re.S)[:6]
            lottery_nums_blue = m_re.findall(self.html_lable, html.text, m_re.S)[:1]
            # 下面用extend 插了两次是因为我想把红蓝球变成一个列表, 如果弄成只插一次就会造成列表套列表,很是疑惑
            lottery_nums.extend(lottery_nums_red)
            lottery_nums.extend(lottery_nums_blue)
            # 数据进字典
            self.ssq_nums = lottery_nums
            # print(self.ssq_nums)

      if self.urls == url:
            # 七乐彩: 号码列表-合并期号, 开奖日期, 开奖期号, 开奖号码 红七个 / 蓝一个, 红蓝号码合并列表
            lottery_nums = []
            lottery_date = m_re.findall(self.html_lable, html.text, m_re.S)
            lottery_date_nums = m_re.findall(self.html_lable, html.text, m_re.S)
            lottery_nums_red = m_re.findall(self.html_lable, html.text, m_re.S)[:7]
            lottery_nums_blue = m_re.findall(self.html_lable, html.text, m_re.S)[:1]

            lottery_nums.extend(lottery_nums_red)
            lottery_nums.extend(lottery_nums_blue)
            # 数据进字典
            self.qlc_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[: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[: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, 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,
                self.box_title,
                choices=(self.indexbox_choices,self.indexbox_choices)
            )

            # 判断用户是选择的[确定]按钮, 开始调用diropenbox() 函数选择目录
            if choices_msg == int(self.indexbox_choices):
                choices_path = m_easygui.diropenbox(self.box_msg)
                # 这里会先生成文件 MainConfig.ini, 避免与下方的m_os.chdir() 函数冲突
                with open(self.app_config, 'w', encoding='utf-8') as user_f1:
                  user_f1.write(
                        self.app_config + m_os.getcwd() + ';' + '\n' +
                        self.app_config + m_os.getcwd() + '\\' + self.app_config + ';'
                  )
                # 选择目录窗口如果直接关闭在这里做个TypeError处理
                try:
                  m_os.chdir(choices_path)
                except TypeError:
                  return
                # 合并一下选择的目录跟文件名AppConfig.ini,得到一个完整路径
                merge_path = m_os.path.join(m_os.getcwd(), self.app_config)
                # 根据用户选择的目录直接覆写文件AppConfig.ini
                with open(merge_path, 'w', encoding='utf-8') as user_f2:
                  user_f2.write(
                        self.app_config + choices_path + ';' + '\n' +
                        self.app_config + merge_path + ';'
                  )
                EasyGuiUI().reg_EasyGuiUI()
            # 判断用户是选择的[默认]按钮, 直接在程序目录下进行覆写两个文件MainConfig.ini AppConfig.ini
            elif choices_msg == int(self.indexbox_choices):
                # 选择[默认] 直接在程序所在目录生成文件
                with open(self.app_config, 'w', encoding='utf-8') as app_f1,\
                        open(self.app_config, 'w', encoding='utf-8') as app_f2:
                            app_f1.write(
                              self.app_config + m_os.getcwd() + ';' + '\n' +
                              self.app_config + m_os.getcwd() + '\\' + self.app_config + ';'
                            )
                            app_f2.write(
                              self.app_config + m_os.getcwd() + ';' + '\n' +
                              self.app_config + m_os.getcwd() + '\\' + self.app_config + ';'
                            )
                EasyGuiUI().reg_EasyGuiUI()

    # 注册
    def reg_EasyGuiUI(self):
      # 在启用注册UI之前 判断下是否已经进行了注册, 判断文件MainConfig.ini中有无self.app_config/这两个字符串
      # 这种判断应该还有更好的写法, 截至学到目前的知识 确实想不出了
      with open(self.app_config, 'r', encoding='utf-8') as read_f1:
            #在这个变量出来前, 原地转圈琢磨了好久. read()这个好像并不能用在if语句的多重判断中,期望的结果会False
            read_f1_temp = read_f1.read()
            if self.app_config in read_f1_temp and self.app_config in read_f1_temp:
                return EasyGuiUI().login_EasyGuiUI()
      # 这下面是原地转圈时琢磨的
      # if (self.app_config and self.app_config) in read_f1:
      #   return EasyGuiUI().login_EasyGuiUI()            
                # aa = m_re.search('username=*|userkey=*', i)
                # if aa:
                #   print(aa.group())
                #   print(i)
      # if :
      #   print('11')

      # with open(self.app_config, 'r+', encoding='utf-8') as read_f2:
      #   if ) for read_f2_temp1 in read_f2.readlines()]:
      #         return EasyGuiUI().login_EasyGuiUI()

      reg_values = []
      reg_values = m_easygui.multpasswordbox(
            self.box_msg,
            self.box_title,
            fields=(self.multpasswordbox_fields,self.multpasswordbox_fields)
      )

      while True:
            # 循环后 重置self.indexbox_errmsg的消息为空字符串
            self.indexbox_errmsg = self.indexbox_errmsg
            # 返回值为None,结束
            if reg_values == None:
                return
            # 这块还想写一个昵称只能输入纯英文, 程序密码只能输入纯数字
            for i in range(len(self.multpasswordbox_fields)):
                if reg_values == '' and self.multpasswordbox_fields == '*' and self.multpasswordbox_fields == '*':
                  self.indexbox_errmsg += ('【%s】为必填项,请重新填写!\n' % self.multpasswordbox_fields)
            if self.indexbox_errmsg == '':
                break
            
            reg_values = m_easygui.multpasswordbox(
                self.indexbox_errmsg,
                self.box_title,
                fields=(self.multpasswordbox_fields,self.multpasswordbox_fields),
                values=reg_values# 这里是留存填写过的内容,并显示在程序,避免用户二次输入
            )
      # 联动enctry_AppCryptos() 加密函数, 对用户输入的<程序密码>进行加密
      link_AppCryptos = AppCryptos()
      link_AppCryptos.enctry_AppCryptos(reg_values)
      self.temp_enctry_str = link_AppCryptos.enctry_str
      # 将昵称和加密的程序密码存入文件MainConfig.ini
      # 这块应该还要做个文件中是否存在username和userkey的字符串做对应的写入判断(如果字符串存在多个,或者没有,或者文件不在,或者权限不够等)
      # 不过这次就简单写一下数据存入文件, 其他的心里写了就行
      try:
            with open(self.app_config, 'a', encoding='utf-8') as enctry_f1:
                enctry_f1.write(
                  '\n' + self.app_config + reg_values + ';' +
                  '\n' + self.app_config + self.temp_enctry_str + ';'
                )
            m_easygui.msgbox(self.box_msg)
            EasyGuiUI().login_EasyGuiUI()
      except OSError:
            m_easygui.msgbox(self.indexbox_errmsg)
      # print(self.enctry_str)

    # 登录
    def login_EasyGuiUI(self):
      # 登录这块应该也要写一个取文件中密文的时候来个文件是否存在或文件中需要的字符串是否存在, 心里写了!
      # 想了下 验证文件这些步骤其实可以单独弄个函数放在那边来调用, 这样代码应该可以精简一些
      # 在open的时候用'x'模式 检查文件是否存在?
      login_return_cont = m_easygui.passwordbox(self.box_msg, self.box_title)

      # 读取文件中userkey存放的密文
      with open(self.app_config, 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)
      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)
      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()))
      dict_ssq_value = ','.join(list(dict_ssq.values()))
      dict_qlc_value = ','.join(list(dict_qlc.values()))

      self.marge_msgs_get_nums_ForPanel = (
            # ext_username + self.box_msg + '\n' +
            '第[' + list(dict_ddd) + ']期福彩3D开奖号码: ' + dict_ddd_value + '\n' +
            '第[ ' + list(dict_ssq) + ' ]期双色球开奖号码: ' + dict_ssq_value + '\n' +
            '第[ ' + list(dict_qlc) + ' ]期七乐彩开奖号码: ' + dict_qlc_value
      )

    # 机选号码, 机选的规则都为:彩票投注中的单式投注!
    # 此方法被panel_EasyGuiUI(self) 方法来调用
    def get_loopnums_ForPanel(self, keyloopnums):
      if keyloopnums == 'start':
            # 机选福彩3D
            # 使用列表推导式 把需要的每一个元素转换成字符串,这样做的方式是方便呈现的时候 数字后面自带逗号
            # loopnums_1_ddd = ''
            loopnums_1_ddd = ,self.loop_ddd)) for loop in range(3)]
            loopnums_1_ddd = ','.join(loopnums_1_ddd)# # 三个数字转换成字符串且用逗号来分割进行展示
            # print(loopnums_1_ddd)# 输出一下 机选出来的三个数字

            # 机选双色球
            # loopnums_2_ssq = []
            loopnums_2_red = ,self.loop_ssq_red)) for loop in range(6)]
            loopnums_2_blue = ,self.loop_ssq_blue)) for loop in range(1)]
            loopnums_2_red.append(loopnums_2_blue)# 蓝球合并到红球的列表
            loopnums_2_ssq = ','.join(loopnums_2_red)# 定一个新的变量名称 | 七个数字转换成字符串且用逗号来分割进行展示
            # print(loopnums_2_ssq)# 输出一下 机选出来且合并后的 红+蓝七个数字
            
            # 机选七乐彩
            loopnums_3_red = ,self.loop_qlc)) for loop in range(7)]
            loopnums_3_blue = ,self.loop_qlc)) for loop in range(1)]
            loopnums_3_red.append(loopnums_3_blue)
            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, 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 + self.box_msg),
            title=self.box_title,
            choices=(self.indexbox_choices,self.indexbox_choices,self.indexbox_choices)
      )

      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,
                  choices=(self.indexbox_choices,self.indexbox_choices,self.indexbox_choices)
                )
            elif choices_msg == 1:
                # 按钮返回1 则去获取最新号码展示给用户
                choices_msg = m_easygui.indexbox(
                  msg=self.marge_msgs_get_nums_ForPanel,
                  title=self.box_title,
                  choices=(self.indexbox_choices,self.indexbox_choices,self.indexbox_choices)
                )
            elif choices_msg == 2:
                # 直接结束
                break
            else:
                # 这里比如直接关闭 返回了None
                break


app_run = EasyGuiUI()
app_run.init_EasyGuiUI()
# app_run.get_loopnums_ForPanel()

hornwong 发表于 2021-4-21 20:38:29

{:5_95:}

hornwong 发表于 2021-4-21 20:39:00

感谢分享!

xiaosi4081 发表于 2021-4-21 21:06:28

占楼领育碧{:10_256:}

jw1379 发表于 2021-4-24 10:35:57

感谢分享!

noah-py 发表于 2021-4-24 12:41:51

{:10_299:}

盛世呀 发表于 2021-4-24 18:50:50

{:10_277:}

小白菜mx 发表于 2021-4-27 19:02:51

无条件支持楼主!

小伤口 发表于 2021-4-27 20:46:09

厉害,学习了,不愧是会员
能发这么久的gif{:10_254:}

kangbao 发表于 2021-4-27 23:11:50

谢谢分享

最冒险的梦 发表于 2021-4-28 10:32:10

看看看看看

kerln888 发表于 2021-4-28 13:52:53

感谢分享!

crisfo 发表于 2021-4-28 21:53:57

厉害厉害{:5_106:}

松冈有沙 发表于 2021-4-29 20:13:30

{:10_258:}

神官只在景仁宫 发表于 2021-4-30 11:29:28

阿里嘎多

noah-py 发表于 2021-5-2 09:16:26

{:10_256:}

青出于蓝 发表于 2021-5-2 21:30:10

鱼b

咸鱼吃栗子 发表于 2021-5-3 09:07:22

支持支持,是我羡慕的大神

Py与C。。。 发表于 2021-5-3 15:19:16

看隐藏内容

kenangan 发表于 2021-5-4 23:39:54

厉害
页: [1] 2 3 4
查看完整版本: 交作业了(机选彩票号码程序+爬取最新开奖号码) | [课后作业] 第038讲