用python编写一个时时彩的开奖号码采集器


前期准备

Python

 


功能需求

1.采集数据,支持断线后重新登录时的数据自动补全

2.按日期存放到数据库中

3.GUI界面显示选定日期的数据以及最新开奖的数据刷新


功能实现

标注:为避免冲突,在描述时,类属性名和类方法名会修改成红色,普通变量名为正常颜色

1.界面布置

以下是GUI.py用到的所有模块,其中有两个是另外的自建.py文件

from tkinter import *
from threading import Timer
from tkinter import ttk
import time
import calendar
import pickle
import os
import getAwardData
import loadHistory

创建一个GUI的类,初始化时创建窗口win,设定窗口大小均为500*500

data_term用来存放左上角实时开奖的期号信息,起始值为""开奖查询中...""

data_number用来存放左上角实时开奖号码信息,起始值为""X   X   X   X   X""

创建两个实例,gadlh

getAwardData文件中的GetAwardData类是用来爬取实时开奖信息的

loadHistory文件中的LoadHistory类是用来检测断期并补全数据用的

class GUI(object):
    def __init__(self):
        self.win = Tk()
        self.win.maxsize(500, 500)
        self.win.minsize(500, 500)
        self.win.protocol("WM_DELETE_WINDOW", self.closeloop)
        self.data_term = "开奖查询中..."
        self.data_number = "X  X  X  X  X"
        self.gad = getAwardData.GetAwardData()
        self.lh = loadHistory.LoadHistory()

中间还有一行,设置窗口的系统协议,点击右上角的"X"按钮时,默认是销毁窗口,现在更改成触发类方法closeloop

closeloop方法代码如下:

    def closeloop(self):
        self.timmer1.cancel()
        self.timmer2.cancel()
        self.win.destroy()

timmer1 , timmer2 后面会讲到,是两个定时器,所以在关闭窗口之前,首先要做的是把定时器关掉


窗口初始化完毕之后开始布局:

==========↓↓↓以下区域内所有代码若开头无"def",则均为layout方法内的代码↓↓↓==========

    def layout(self):

aaa.首先是左上角开奖数据区域,代码如下:

       # 左上角当期开奖数据
        # # 载入图像文件
        self.img_frame1 = PhotoImage(file="image/frame1.png")
        # # 当前开奖数据外框架
        self.frame_now = Frame(self.win, width=200, height=100)
        self.frame_now.place(x=5, y=5)
        # #当前开将数据画布
        self.canvas_now = Canvas(self.frame_now)
        self.canvas_now.create_image(100, 50, image=self.img_frame1)
        self.canvas_now.place(x=0, y=0)
        # # 当前开奖信息标签
        Label(self.frame_now, text="开奖号码").place(x=55, y=0)
        self.label_term = Label(self.frame_now, font=(15,), text=self.data_term)
        self.label_term.place(x=20, y=20)
        self.label_number = Label(self.frame_now, font=("Times", 20, "bold"), text=self.data_number)
        self.label_number.place(x=20, y=40)

分析:

第一步,使用tkinter中的PhotoImage类创建了一个图片实例img_frame1,该图片用途后面描述

第二步,创建一个200*100的Frame框架frame_now,放置于主窗口win内的左上角(5,5)处

第三步,创建一个Canvas画布canvas_now,放置于frame_now的左上角(0,0)处,画布内的图像为第一步时创建的img_frame1对象

第四步,放置三个标签:第一个是标题"开奖号码",该标签不存在需要改变值的情况,所以不需要赋给任何变量,放置在frame_now中的(55,0)处;;第二个是开奖期号标签label_term,放置在frame_now中的(20,20)处,内容为data_term的值;;第三个是开奖号码标签label_number,放置在frame_now中的(20,40)处,内容为data_number的值.

运行一下可以看到窗口左上角界面大致如此

 

bbb.接下来做窗口右下方开奖号码收集栏,代码如下:

        # 左下角显示已收集的开奖数据的列表框
        # # 列表框外框架
        self.frame_collect = Frame(self.win, borderwidth=2, relief=RAISED)
        self.frame_collect.place(x=7, y=107)
        # # 滚动条
        self.collect_scy = Scrollbar(self.frame_collect)
        self.collect_scy.pack(side=RIGHT, fill=Y)
        # # 列表框
        self.listbox_collect = Listbox(self.frame_collect, width=21, height=19, font=("Times", 12),
                                       yscrollcommand=self.collect_scy.set)
        self.listbox_collect.pack(side=LEFT, fill=BOTH)
        # 滚动条设置可视范围
        self.collect_scy.config(command=self.listbox_collect.yview)

代码分析:

第一步,创建一个Frame框架frame_collect,放置在win内的(7,107)位置

第二步,创建纵向滚动条collect_scy,在frame_collect内用pack方法打包在右侧,填充为Y方向

第三步,创建列表框listbox_collect,宽度为21个字符宽度,高度为19个字符高度,字体设置如代码中所示,在frame_collect内用pack方法打包在左侧,填充为BOTH,  y方向的滚动条指令为collect_scy.set

第四步,设置滚动条对应列表框的可视范围

注意项::存在滚动条的组件群,需要使用pack方法布局

运行一下可以看到左下角列表框已经出来了

ccc.右上方的日期选择区域

包含三个下拉列表框,三个固定标签,一个提示信息标签,以及一个按钮,代码如下:

        # 右侧历史数据查询
        # # 年份选择框
        self.combo_year = ttk.Combobox(self.win, textvariable="年份", width=4)
        now_year = time.strftime("%Y")
        self.combo_year["value"] = tuple([int(now_year) - i for i in range(10)])
        self.combo_year["state"] = "readonly"
        self.combo_year.current(0)
        self.combo_year.place(x=210, y=10)
        self.combo_year.bind("<<ComboboxSelected>>", self.selected)
        self.combo_year.bind("<<ComboboxSelected>>", self.resetDay)
        Label(self.win, text="年", font=("Times", 12)).place(x=265, y=10)
        # # 月份选择框
        self.combo_month = ttk.Combobox(self.win, textvariable="月份", width=2)
        now_month = time.strftime("%m")
        self.combo_month["value"] = tuple([i + 1 for i in range(12)])
        self.combo_month["state"] = "readonly"
        self.combo_month.current(int(now_month) - 1)
        self.combo_month.place(x=290, y=10)
        self.combo_month.bind("<<ComboboxSelected>>", self.selected)
        self.combo_month.bind("<<ComboboxSelected>>", self.resetDay)
        Label(self.win, text="月", font=("Times", 12)).place(x=330, y=10)
        # # 日期选择框
        self.combo_day = ttk.Combobox(self.win, textvariable="日期", width=2)
        now_day = time.strftime("%d")
        self.combo_day["value"] = tuple([i + 1 for i in range(calendar.monthrange(int(now_year), int(now_month))[1])])
        self.combo_day["state"] = "readonly"
        self.combo_day.current(int(now_day) - 1)
        self.combo_day.place(x=355, y=10)
        self.combo_day.bind("<<ComboboxSelected>>", self.selected)
        Label(self.win, text="日", font=("Times", 12)).place(x=395, y=10)
        # # 查询按钮
        self.button_query = Button(self.win, text="查询", width=8)
        self.button_query.place(x=428, y=5)
        self.button_query.bind("<1>", self.query)
        # # 提示信息
        self.label_tips = Label(self.win, text="", foreground="#FF0000")
        self.label_tips.place(x=210, y=35)

三个下拉列表框代码形式基本一致,只是放置位置以及内置的值不同,下面以日期选择框来说明:

代码分析:

第一步,创建年份,月份,日期选择框combo_year, combo_month, combo_day,三个选择框与其后的标签都放置在win中,具体位置参照代码

        创建选择框combo_day,value值为从日历查询到的当月天数列表,初始时使用的是当前的年份和月份求得天数

        该注意的是,年份选择框和日期选择框都应该绑定一个时间,当选择时,重新计算日期选择框的值

        calendar.monthrange(year,month)返回一个元组,元组中第二个值就是我们需要的当月天数

        每个选择框都绑定了一个事件,就是清空提示标签中的提示内容,并且让其获得焦点,代码如下:

    def selected(self, *args):
        self.label_tips["text"] = ""
        self.label_tips.focus()

        年份和月份选择框还有另外一个事件,就是刚刚提到的修改日期选择框的值的事件,代码如下:

    def resetDay(self, *args):
        year = int(self.combo_year.get())
        month = int(self.combo_month.get())
        day_num = calendar.monthrange(year, month)[1]
        self.combo_day["value"] = [i + 1 for i in range(day_num)]

第二步,创建按钮button_query,宽度为8,放置在win中,绑定事件为query方法

第三步,创建标签label_tips,放置在win中,该标签用于显示提示信息

运行一下可以看到界面如图

下面是第二步中提到的query方法

    def query(self, event):
        # 清空提示标签的提示
        self.label_tips["text"] = ""
        # 年份
        year = self.combo_year.get()
        # 月份
        month = self.combo_month.get()
        if len(month) < 2:
            month = "0" + month
        # 日期
        day = self.combo_day.get()
        if len(day) < 2:
            day = "0" + day
        file_path = "data/%s/" % year + year + month + day + ".txt"
        if not os.path.exists(file_path):
            self.label_tips["text"] = "没有该日期的数据 !"
            self.listbox_show.delete(0, 1500)
            return None
        with open(file_path, "rb") as f:
            file = pickle.load(f)
        lenght = len(file)
        for i in range(lenght):
            string = "  ".join(list(map(str, file[i])))
            self.listbox_show.insert(END, string)

query方法是查询数据的方法,点击"查询"按钮触发此事件

代码分析:

第一步,将提示标签label_tips的内容清空

第二步,获取combo_year选择框中的年份,combo_month选择框中的月份,combo_day中的日期,如果月份和日期位数为一位,则在其前加"0"

第三步,组合成文件路径字符串

第四步,判断是否存在该文件,

        如果没有,提示标签label_tips内容修改为"没有该日期的数据 !",列表框listbox_show(下面的代码中创建)内容清空,因为最多只可能存在1440行数据,所以只需要删除0-1500行的数据已经能够保证全部删除,然后return None

        如果有,则继续往下执行

第五步,打开文件,读取文件数据并存放在变量file中

第六步,遍历file,将每一条数据转换成以"   "分隔的字符串后插入listbox_show

ddd.右下方数据展示列表,代码如下:

        # # 列表框外框架
        self.frame_show = Frame(self.win, borderwidth=2, relief=RAISED)
        self.frame_show.place(x=210, y=55)
        # # 滚动条
        self.show_scy = Scrollbar(self.frame_show)
        self.show_scy.pack(side=RIGHT, fill=Y)
        # # 列表框
        self.listbox_show = Listbox(self.frame_show, width=37, height=24, yscrollcommand=self.show_scy.set)
        self.listbox_show.pack(side=LEFT, fill=BOTH)
        # # 滚动条设置列表框可视范围
        self.show_scy.config(command=self.listbox_show.yview)

代码分析:

第一步,创建Frame框架frame_show,放置于win中的(210,55)处

第二步,创建Y方向滚动条show_scy,用pack方法在frame_show中打包,填充为Y方向

第三步,创建列表框listbox_show,宽度为37个字符宽度,高度为24个字符高度,用pack方法在frame_show中打包,填充为BOTH,y方向的滚动条命令为show_scy.set

第四步,设置滚动条对应列表框的视图

最后出来的界面大致是这样的

==========↑↑↑以上,layout方法已经完成↑↑↑==========


下面是剩余一些方法的罗列:

主循环方法mainloop:

    def mainloop(self):
        self.timmer1 = Timer(1, self.timing1)
        self.timmer2 = Timer(1, self.timing2)
        self.timmer1.start()
        self.timmer2.start()
        self.win.mainloop()

代码分析:  在窗口的mainloop开始前,要先设定两个定时器timmer1timmer2,下面即将介绍两个定时器的作用

定时器1方法timing1:

    def timing1(self):
        try:
            data = self.gad.get()
            print(data)
            data_term = data["curDate"] + data["curPeriod"]
            data_number = data["awardNumber"].replace(",", "   ")
            if data_term == self.data_term or data["awardNumber"] == "null":
                print("again")
                self.timmer1 = Timer(1, self.timing1)
                self.timmer1.start()
            else:
                self.data_term = data_term
                self.data_number = data_number
                self.label_term["text"] = self.data_term + " :"
                self.label_number["text"] = self.data_number
                self.listbox_collect.insert(0, "  " + data["curPeriod"] + "   -   " + data_number)
                self.timmer1 = Timer(30, self.timing1)
                self.timmer1.start()
        except:
            print("again")
            self.timmer1 = Timer(1, self.timing1)
            self.timmer1.start()
        

定时器1在程序开始1秒后触发定时器1事件timing1,代码分析如下:

第一步:

        尝试调用gad对象的get方法,这个方法是接下来第二个大步骤介绍的后台任务代码中的获取最新开奖号码信息的方法,可以先不用管,返回的数据是一个字典,将获得的字典打印一下

        如果失败报错,则打印"again",并重设定时器timmer1, 1秒钟之后再次触发事件

第二步:

        第一步成功的情况下,从返回的数据字典中获取键名为"curDate"的值与"curPeriod"的值,它们两个相加就是XXXXXXXX的日期格式,赋值给变量data_term,然后获取"awardNumber"的键值,并将其中的","替换成"   ",赋值给变量data_number

第三步:

        判断如果data_term等于data_term,或者返回的data数据字典中的"awardNumber"的键值为"null",则打印"again",并重设定时器timmer1,1秒钟后再次触发事件(即此判断为判断是否为最新一期的数据或者抓取回来的数据为空)

 

        如果不满足条件,证明此次获取的data为新一期的数据,并且不为空,则将data_term的值赋给data_term,将data_number的值赋给data_number,修改label_termlabel_number的内容,然后往listbox_collect中插入最新获得的数据,最后重设定时器timmer1,30秒之后再次触发事件

定时器2方法timing2:

    def timing2(self):
        # 获取历史日期
        with open("history.txt", "r") as f:
            history_date = f.read()
        award_data = self.lh.load(history_date)
        if award_data:
            # 保存数据
            year = history_date[0:4]
            if not os.path.exists("data/" + year):
                os.mkdir("data/" + year)
            filename = "data/%s/" % year + "".join(history_date.split("-")) + ".txt"
            with open(filename, "w") as f:
                pickle.dump(award_data, f)
            print("%s数据写入成功" % history_date)
            # 判断日期是否为今日
            now = time.strftime("%Y-%m-%d", time.localtime(time.time()))
            if now == history_date:
                return None
        else:
            print("%s无数据" % history_date)
        # 保存新时间
        add_part = "-12-00-00"
        t_time = history_date + add_part
        ts = time.mktime(time.strptime(t_time, "%Y-%m-%d-%H-%M-%S"))
        ts += 86400.0
        tts = time.localtime(ts)
        sft = time.strftime("%Y-%m-%d", tts)
        with open("history.txt", "w") as f:
            f.write(sft)
        # 开启新的定时器
        self.timmer2 = Timer(1, self.timing2)
        self.timmer2.start()

定时器2在程序开始1秒后触发该事件

代码分析:

第一步:

        打开存放采集历史的时间记录文件history.txt,里面只会存放每次采集完后更新的时间XXXX-XX-XX这样的时间数据

        读取到时间数据后赋值给变量history_date

        调用lh对象的load方法,传参history_date,返回值是获取的传入日期的历史开奖数据numpy数组,赋值给变量award_data

第二步:

        判断,如果award_data不为空,则获取history_date中的前四位为年数据,赋值给变量year

        {再判断是否存在目录,不存在则新建一个文件夹}

        给相应的文件中写入数据

        {判断如果history_date跟当前日期相等,则return None},(即结束定时器2)

 

        但如果award_data为空,则打印没有此日数据

第三步:

        给history_date加一天,具体方法看代码

        加完之后转换成对应的XXXX-XX-XX格式,存到history.txt中

第四步:

        重设定时器timmer2,1秒钟后再次触发事件



2.后台任务代码

第一部分,另建一个getAwardData.py  ,  实现功能为爬取最新的开奖数据

import json
import requests
import time
import urllib3


class GetAwardData(object):
    def __init__(self):
        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
        self.base_url = "https://www.qqff6.com/Home/GetAwardData?r="
        self.headers = {
            'Connection': 'keep - alive',
            'Cookie': 'UM_distinctid = 1647cf3d191143 - 0e25766130e05 - 6114147a - 1fa400 - 1647cf3d19220f;CNZZDATA1272976055 = 532055155 - 1531100909 - null % 7C1536476068;Hm_lvt_6138b14b6aeb117c46460e5587e24fd2 = 1535355469, 1535422652, 1536198411, 1536481231;Hm_lpvt_6138b14b6aeb117c46460e5587e24fd2 = 1536481254',
            'User - Agent': 'Mozilla / 5.0(Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, likeGecko) Chrome/68.0.3440.106 Safari/537.36',
        }

    def get(self):
        self.url = self.base_url + str(int(time.time() * 1000))
        self.response = requests.get(self.url, headers=self.headers, verify=False)
        return json.loads(self.response.content.decode("utf-8"))

代码分析:

创建一个GetAwardData的类,根据分析网页xhr请求,可以看到每过一小段时间就会出现一个get请求,请求url里带一个参数,是一个毫秒级的时间戳

经过初步伪装之后,直接请求即可获得返回的数据,返回的数据是json格式的数据,将这部分操作封装在类内的get方法中

这个getAwardData.py就是上面GUI中导入的那个,包括下面的loadHistory.py也是


第二部分,另建一个loadHistory.py文件,实现功能为爬取历史数据,下面是第一版本的代码

import requests
from lxml import etree
import time
import urllib3
import numpy


class LoadHistory(object):
    '''
    输入日期XXXX-XX-XX,返回当日开奖数据numpy数组(最后一行为0001期)
    '''

    def __init__(self):
        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
        self.url = r'https://www.qqff6.com/History/LoadHistory?count=1440&maxPeriod=1440&showType=0'
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
            'Cookie': 'UM_distinctid=1647cf3d191143-0e25766130e05-6114147a-1fa400-1647cf3d19220f; CNZZDATA1272976055=532055155-1531100909-null%7C1536501123; Hm_lvt_6138b14b6aeb117c46460e5587e24fd2=1535422652,1536198411,1536481231,1536504163; Hm_lpvt_6138b14b6aeb117c46460e5587e24fd2=1536504166',
        }

    def load(self, date):
        print("输入历史日期:", date)
        self.url += "&date=" + date
        r = str(int(time.time() * 1000))
        self.url += "&r=" + r
        print(self.url)
        response = requests.get(self.url, headers=self.headers, verify=False)
        tree = etree.HTML(response.content.decode("utf-8"))
        if tree:
            award_num = tree.xpath('//span[@class="nav_num" and @style=""]')
            award_term = tree.xpath('//tr/td[2]/span/text()')
            output = []
            for i in range(len(award_term)):
                term = award_term[i].strip()
                num = award_num[i].xpath('./i/text()')
                tmp = [term]
                tmp.extend(num)
                output.append(tmp)
            output = numpy.array(output)
            return output
        else:
            return None

通过分析url接口可以知道,这里有四个变参,分别是count,maxPeriod,date,r

count是返回的数据的条数

maxPeriod是从当天哪一期往前取数据

date是日期,XXXX-XX-XX格式

r是请求发出时的毫秒级时间戳

用上面的LoadHistory类经过测试能够实现爬取历史数据的功能,

但是,多次爬取之后会被服务器识别为"恶意握手"而出现异常

所以决定用selenium搭配PhantomJS无界面浏览器的组合去获取数据

以下是修改后的loadHistory.py的代码:

from lxml import etree
import time
import numpy
from selenium import webdriver


class LoadHistory(object):
    '''
    输入日期XXXX-XX-XX,返回当日开奖数据numpy数组(最后一行为0001期)
    '''

    def __init__(self):
        self.url = r'https://www.qqff6.com/History/LoadHistory?count=1440&maxPeriod=1440&showType=0'

    def load(self, date):
        self.driver = webdriver.PhantomJS(
            executable_path=r'D:\software\phantomjs-2.1.1-windows\phantomjs-2.1.1-windows\bin\phantomjs.exe')
        print("输入历史日期:", date)
        url = self.url + "&date=" + date
        r = str(int(time.time() * 1000))
        url += "&r=" + r
        print(url)
        self.driver.get(url)
        try:
            tree = etree.HTML(self.driver.page_source)
            span_list = tree.xpath('//span')
            output = []
            length = int(len(span_list) / 4)
            for i in range(length):
                term = span_list[i * 4].xpath("./text()")[0].strip()
                num = span_list[i * 4 + 1].xpath("./i/text()")
                tmp = [term]
                tmp.extend(num)
                output.append(tmp)
            output = numpy.array(output)
            self.driver.quit()
            return output
        except:
            self.driver.quit()
            return None

代码解析:

在类的初始化方法中定义了基础url

在load方法中,建立了一个phantomjs浏览器的driver实例,通过计算参数对url进行拼接,用driver.get()方法访问url,并获取网页文本driver.page_source,使用xpath进行解析,得到一个长度为5000多的列表,里面包含了所有的span标签的信息,这些span标签是4个为一组的,所以循环的时候,只需要对整个列表的长度的1/4范围进行循环,然后通过算式获取其中对应的元素,进行二次解析获取内容,最后是一些数据样式的处理以及return

 

 

相对而已,用此方法会比较慢,但哪怕是10秒钟获取一次,10年的数据也仅需10小时就可以全部收集完毕,也是比较可观的

以上,就是整个软件的开发过程,后面部分的代码如果看不懂,可以给我私信或者在文章下方评论,看到了就会马上解答的



最后附上三个脚本的代码:

GUI.py

from tkinter import *
from threading import Timer
from tkinter import ttk
import time
import calendar
import pickle
import os
import getAwardData
import loadHistory


class GUI(object):
    def __init__(self):
        self.win = Tk()
        self.win.maxsize(500, 500)
        self.win.minsize(500, 500)
        self.win.protocol("WM_DELETE_WINDOW", self.closeloop)
        self.data_term = "开奖查询中..."
        self.data_number = "X  X  X  X  X"
        self.gad = getAwardData.GetAwardData()
        self.lh = loadHistory.LoadHistory()

    def mainloop(self):
        self.timmer1 = Timer(1, self.timing1)
        self.timmer2 = Timer(1, self.timing2)
        self.timmer1.start()
        self.timmer2.start()
        self.win.mainloop()

    def closeloop(self):
        self.timmer1.cancel()
        self.timmer2.cancel()
        self.win.destroy()

    def timing1(self):
        try:
            data = self.gad.get()
            print(data)
            data_term = data["curDate"] + data["curPeriod"]
            data_number = data["awardNumber"].replace(",", "   ")
            if data_term == self.data_term or data["awardNumber"] == "null":
                print("again")
                self.timmer1 = Timer(1, self.timing1)
                self.timmer1.start()
            else:
                self.data_term = data_term
                self.data_number = data_number
                self.label_term["text"] = self.data_term + " :"
                self.label_number["text"] = self.data_number
                self.listbox_collect.insert(0, "  " + data["curPeriod"] + "   -   " + data_number)
                self.timmer1 = Timer(30, self.timing1)
                self.timmer1.start()
        except:
            print("again")
            self.timmer1 = Timer(1, self.timing1)
            self.timmer1.start()


    def timing2(self):
        # 获取历史日期
        with open("history.txt", "r") as f:
            history_date = f.read()
        award_data = self.lh.load(history_date)
        if award_data:
            # 保存数据
            year = history_date[0:4]
            if not os.path.exists("data/" + year):
                os.mkdir("data/" + year)
            filename = "data/%s/" % year + "".join(history_date.split("-")) + ".txt"
            with open(filename, "w") as f:
                pickle.dump(award_data, f)
            print("%s数据写入成功" % history_date)
            # 判断日期是否为今日
            now = time.strftime("%Y-%m-%d", time.localtime(time.time()))
            if now == history_date:
                return None
        else:
            print("%s无数据" % history_date)
        # 保存新时间
        add_part = "-12-00-00"
        t_time = history_date + add_part
        ts = time.mktime(time.strptime(t_time, "%Y-%m-%d-%H-%M-%S"))
        ts += 86400.0
        tts = time.localtime(ts)
        sft = time.strftime("%Y-%m-%d", tts)
        with open("history.txt", "w") as f:
            f.write(sft)
        # 开启新的定时器
        self.timmer2 = Timer(1, self.timing2)
        self.timmer2.start()

    def layout(self):
        # 左上角当期开奖数据
        # # 载入图像文件
        self.img_frame1 = PhotoImage(file="image/frame1.png")
        # # 当前开奖数据外框架
        self.frame_now = Frame(self.win, width=200, height=100)
        self.frame_now.place(x=5, y=5)
        # #当前开将数据画布
        self.canvas_now = Canvas(self.frame_now)
        self.canvas_now.create_image(100, 50, image=self.img_frame1)
        self.canvas_now.place(x=0, y=0)
        # # 当前开奖信息标签
        Label(self.frame_now, text="开奖号码").place(x=55, y=0)
        self.label_term = Label(self.frame_now, font=(15,), text=self.data_term)
        self.label_term.place(x=20, y=20)
        self.label_number = Label(self.frame_now, font=("Times", 20, "bold"), text=self.data_number)
        self.label_number.place(x=20, y=40)

        # 左下角显示已收集的开奖数据的列表框
        # # 列表框外框架
        self.frame_collect = Frame(self.win, borderwidth=2, relief=RAISED)
        self.frame_collect.place(x=7, y=107)
        # # 滚动条
        self.collect_scy = Scrollbar(self.frame_collect)
        self.collect_scy.pack(side=RIGHT, fill=Y)
        # # 列表框
        self.listbox_collect = Listbox(self.frame_collect, width=21, height=19, font=("Times", 12),
                                       yscrollcommand=self.collect_scy.set)
        self.listbox_collect.pack(side=LEFT, fill=BOTH)
        # 滚动条设置可视范围
        self.collect_scy.config(command=self.listbox_collect.yview)

        # 右侧历史数据查询
        # # 年份选择框
        self.combo_year = ttk.Combobox(self.win, textvariable="年份", width=4)
        now_year = time.strftime("%Y")
        self.combo_year["value"] = tuple([int(now_year) - i for i in range(10)])
        self.combo_year["state"] = "readonly"
        self.combo_year.current(0)
        self.combo_year.place(x=210, y=10)
        self.combo_year.bind("<<ComboboxSelected>>", self.selected)
        self.combo_year.bind("<<ComboboxSelected>>", self.resetDay)
        Label(self.win, text="年", font=("Times", 12)).place(x=265, y=10)
        # # 月份选择框
        self.combo_month = ttk.Combobox(self.win, textvariable="月份", width=2)
        now_month = time.strftime("%m")
        self.combo_month["value"] = tuple([i + 1 for i in range(12)])
        self.combo_month["state"] = "readonly"
        self.combo_month.current(int(now_month) - 1)
        self.combo_month.place(x=290, y=10)
        self.combo_month.bind("<<ComboboxSelected>>", self.selected)
        self.combo_month.bind("<<ComboboxSelected>>", self.resetDay)
        Label(self.win, text="月", font=("Times", 12)).place(x=330, y=10)
        # # 日期选择框
        self.combo_day = ttk.Combobox(self.win, textvariable="日期", width=2)
        now_day = time.strftime("%d")
        self.combo_day["value"] = tuple([i + 1 for i in range(calendar.monthrange(int(now_year), int(now_month))[1])])
        self.combo_day["state"] = "readonly"
        self.combo_day.current(int(now_day) - 1)
        self.combo_day.place(x=355, y=10)
        self.combo_day.bind("<<ComboboxSelected>>", self.selected)
        Label(self.win, text="日", font=("Times", 12)).place(x=395, y=10)
        # # 查询按钮
        self.button_query = Button(self.win, text="查询", width=8)
        self.button_query.place(x=428, y=5)
        self.button_query.bind("<1>", self.query)
        # # 提示信息
        self.label_tips = Label(self.win, text="", foreground="#FF0000")
        self.label_tips.place(x=210, y=35)
        # # 列表框外框架
        self.frame_show = Frame(self.win, borderwidth=2, relief=RAISED)
        self.frame_show.place(x=210, y=55)
        # # 滚动条
        self.show_scy = Scrollbar(self.frame_show)
        self.show_scy.pack(side=RIGHT, fill=Y)
        # # 列表框
        self.listbox_show = Listbox(self.frame_show, width=37, height=24, yscrollcommand=self.show_scy.set)
        self.listbox_show.pack(side=LEFT, fill=BOTH)
        # # 滚动条设置列表框可视范围
        self.show_scy.config(command=self.listbox_show.yview)

    def selected(self, *args):
        self.label_tips["text"] = ""
        self.label_tips.focus()

    def resetDay(self, *args):
        year = int(self.combo_year.get())
        month = int(self.combo_month.get())
        day_num = calendar.monthrange(year, month)[1]
        self.combo_day["value"] = [i + 1 for i in range(day_num)]

    def query(self, event):
        # 清空提示标签的提示
        self.label_tips["text"] = ""
        # 年份
        year = self.combo_year.get()
        # 月份
        month = self.combo_month.get()
        if len(month) < 2:
            month = "0" + month
        # 日期
        day = self.combo_day.get()
        if len(day) < 2:
            day = "0" + day
        file_path = "data/%s/" % year + year + month + day + ".txt"
        if not os.path.exists(file_path):
            self.label_tips["text"] = "没有该日期的数据 !"
            self.listbox_show.delete(0, 2000)
            return None
        with open(file_path, "rb") as f:
            file = pickle.load(f)
        lenght = len(file)
        for i in range(lenght, -1, -1):
            string = "  ".join(list(map(str, file[i])))
            self.listbox_show.insert(END, string)


if __name__ == "__main__":
    gui = GUI()
    gui.layout()
    gui.mainloop()
getAwardData.py
import json
import requests
import time
import urllib3


class GetAwardData(object):
    def __init__(self):
        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
        self.base_url = "https://www.qqff6.com/Home/GetAwardData?r="
        self.headers = {
            'Connection': 'keep - alive',
            'Cookie': 'UM_distinctid = 1647cf3d191143 - 0e25766130e05 - 6114147a - 1fa400 - 1647cf3d19220f;CNZZDATA1272976055 = 532055155 - 1531100909 - null % 7C1536476068;Hm_lvt_6138b14b6aeb117c46460e5587e24fd2 = 1535355469, 1535422652, 1536198411, 1536481231;Hm_lpvt_6138b14b6aeb117c46460e5587e24fd2 = 1536481254',
            'User - Agent': 'Mozilla / 5.0(Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, likeGecko) Chrome/68.0.3440.106 Safari/537.36',
        }

    def get(self):
        self.url = self.base_url + str(int(time.time() * 1000))
        self.response = requests.get(self.url, headers=self.headers, verify=False)
        return json.loads(self.response.content.decode("utf-8"))

loadHistory.py

from lxml import etree
import time
import numpy
from selenium import webdriver


class LoadHistory(object):
    '''
    输入日期XXXX-XX-XX,返回当日开奖数据numpy数组(最后一行为0001期)
    '''

    def __init__(self):
        self.url = r'https://www.qqff6.com/History/LoadHistory?count=1440&maxPeriod=1440&showType=0'
        self.page_number = 0

    def load(self, date):
        self.driver = webdriver.PhantomJS(
            executable_path=r'D:\software\phantomjs-2.1.1-windows\phantomjs-2.1.1-windows\bin\phantomjs.exe')
        print("输入历史日期:", date)
        url = self.url + "&date=" + date
        r = str(int(time.time() * 1000))
        url += "&r=" + r
        print(url)
        self.driver.get(url)
        self.page_number += 1
        try:
            tree = etree.HTML(self.driver.page_source)
            span_list = tree.xpath('//span')
            output = []
            length = int(len(span_list) / 4)
            for i in range(length):
                term = span_list[i * 4].xpath("./text()")[0].strip()
                num = span_list[i * 4 + 1].xpath("./i/text()")
                tmp = [term]
                tmp.extend(num)
                output.append(tmp)
            output = numpy.array(output)
            self.driver.quit()
            return output
        except:
            self.driver.quit()
            return None

 

展开阅读全文

没有更多推荐了,返回首页