1. 程式人生 > >python寫一個雙色球計算器

python寫一個雙色球計算器

腳本 while ins 參數 ace 接下來 連接數 取數 ndb

首先聲明,賭博一定不是什麽好事,也完全沒有意義,不要指望用彩票發財。之所以寫這個,其實是用來練手的,可以參考這個來預測一些其他的東西,意在拋磚引玉。

啰嗦完了,馬上開始,先上偽代碼

打開網址

讀取內容
內容解析

根據源碼得到需爬取內容

1、開獎日期:2018年8月26日

2、紅球

<li class="ball_red">03</li>

<li class="ball_red">07</li>

<li class="ball_red">08</li>

<li class="ball_red">14</li>

<li class="ball_red">25</li>

<li class="ball_red">32</li>

3、籃球

<li class="ball_blue">06</li>

打開數據庫連接

爬取內容寫入數據庫

共3個字段

1、開獎日期

2、紅球,紅球使用分號“;”分隔,方便調用和導出

3、籃球

在寫腳本前,建議先寫偽代碼,偽代碼格式不是固定的,隨自己喜好,主要就是在思維及算法落地前,把整個輪廓理清,可以有效降低都快寫完了,發現前面有錯誤,結果導致整個腳本全部更新一遍這種事

的發生概率

偽代碼解讀:

共分為兩個功能塊

一就是抓取彩票數據,這個使用爬蟲實現,分別抓取開獎日期、紅球區、籃球區,因為考慮雙色球的數據量比較龐大,所以這次使用數據庫進行存儲,選用的是免費又好用的mysql數據庫,數據庫接口文件使用MySQLdb,這個我以後會單獨寫一個說明,當然你也可以用文檔存儲,或者選擇別的數據庫比如oracle或者nosql的mangodb

二是用來分析彩票的,即使用彩票數據進行下一期的彩票預測,本次選用的是二項分布,這個在之前的算法裏面有,就不重復說明了

下面先上腳本,再對腳本進行說明

#!/usr/bin/python
# coding: UTF-8

‘‘‘
打開網址
  讀取內容
內容解析
  根據源碼得到需爬取內容
  1、開獎日期:2018年8月26日
  2、紅球
                                <li class="ball_red">03</li>
                                <li class="ball_red">07</li>
                                <li class="ball_red">08</li>
                                <li class="ball_red">14</li>
                                <li class="ball_red">25</li>
                                <li class="ball_red">32</li>
  3、籃球
                                <li class="ball_blue">06</li>
打開數據庫連接
  爬取內容寫入數據庫
    共3個字段
    1、開獎日期
    2、紅球,紅球使用分號“;”分隔,方便調用和導出
    3、籃球
create table tow_color_ball(open_date varchar(10),red_n varchar(20),blue_n varchar(2))
‘‘‘

import urllib
import urllib2
import re
import numpy as np
import operator
import MySQLdb

# 連接mysql
def conn_db():
  db = pythondb
  host = localhost
  iuser = xxx
  passwd = xxxxxx
  conn = MySQLdb.connect(db = db, host = host, user = iuser, passwd = passwd)
  cursor = conn.cursor()
  return cursor

# 處理網頁獲取頁面源碼
def get_html_values(url):
  url_open = urllib.urlopen(url)
  url_read = url_open.read()
  return url_read

# 處理源碼,獲取日期、紅球、籃球
def manage_html(html_values):
  red_no_re = re.compile((?<=\<li class\=\"ball_red\"\>)[0-9]+(?=\<\/li\>))
  blue_no_re = re.compile((?<=\<li class\=\"ball_blue\"\>)[0-9]+(?=\<\/li\>))
  date_re = re.compile((?<=開獎日期:)[0-9]+年[0-9]+月[0-9]+日)
  red_no_list = re.findall(red_no_re,html_values)
  red_numbers = ;.join(red_no_list)
  blue_number = re.search(blue_no_re,html_values)
  blue_number = blue_number.group()
  date_value = re.search(date_re,html_values)
  date_value = date_value.group()
  return date_value, red_numbers, blue_number

# 可惡的日期,竟然是YYYY年MM月DD日,需要改成YYYY-MM-DD
def manage_date(date_value):
  date_value = date_value.replace(,-).replace(,-).replace(,‘‘)
  return date_value

# 處理頁面編號,每次編號-1,也就是說end_page要小於url中的頁碼
def get_page(url,end_page):
  url_num = re.search((?<=\/)[0-9]+(?=\.),url)
  url_num = url_num.group()
  if int(end_page) > int(url_num):
    return end
  url_num_1 = int(url_num) - 1
  url = url.replace(url_num,str(url_num_1))
  return url

# 查看庫中是否已存在開獎日期,防止重復寫入
def check_open_date(open_date):
  conn = conn_db()
  check_sql = select 1 from tow_color_ball where open_date = %r %open_date
  conn.execute(check_sql)
  excur = conn.fetchall()
  conn.close()
  #如過未查到excur == ()
  return excur

# 寫入數據庫
def write_db(date_value, red_numbers, blue_number):
  conn = conn_db()
  in_sql = "insert into tow_color_ball(open_date,red_n,blue_n) values(%r,%r,%r)" %(date_value, red_numbers, blue_number)
  conn.execute(in_sql)
  conn.execute(commit)
  conn.close()

# 彩票主程序,用來爬取彩票號碼
def ball_main(url,end_page):
  while True:
    html_values = get_html_values(url)
    date_value, red_numbers, blue_number = manage_html(html_values)
    date_value = manage_date(date_value)
    data_check = check_open_date(date_value)
    if data_check == ():
      write_db(date_value, red_numbers, blue_number)
    url = get_page(url,end_page)
    if url == end:
      print url_page已到達end_page,獲取完成
      return 0

# 二項分布算法
class binomial_class(object):
  def __init__(self,case_count,real_count,p):
    self.case_count = case_count
    self.real_count = real_count
    self.p = p

  def multiply_fun(self,xlist):
    n = 1
    for x in xlist:
      n *= x
    return n
 
  def fact_fun(self,n):
    if n == 0:
      return 1
    n += 1
    fact_list = [i for i in range(1,n)]
    fact_num = self.multiply_fun(fact_list)
    return fact_num

  def c_n_x(self):
    fact_n = self.fact_fun(self.case_count)
    fact_x = self.fact_fun(self.real_count)
    fact_n_x = self.fact_fun(self.case_count - self.real_count)
    c_n_x_num = float(fact_n) / (fact_x * fact_n_x)
    return c_n_x_num

  def binomial_fun(self):
    c_n_k_num = self.c_n_x()
    pi = (self.p ** self.real_count) * ((1 - self.p) ** (self.case_count - self.real_count))
    binomial_num = c_n_k_num * pi
    return binomial_num

# 從庫裏獲取彩票信息
def get_ball_infomation(start_dt,end_dt):
  conn = conn_db()
  sql = "select red_n,blue_n from tow_color_ball where date_format(open_date,‘%%Y-%%m-%%d‘) >= %r and date_format(open_date,‘%%Y-%%m-%%d‘) <= %r" %(start_dt,end_dt)
  conn.execute(sql)
  excur = conn.fetchall()
  conn.close()
  case_array = np.array(excur)
  row_count = case_array.shape[0]
  col_count = case_array.shape[1]
  red_ball_array = case_array[:,0]
  blue_ball_array = case_array[:,1]
  return red_ball_array,blue_ball_array,row_count,col_count

# 統計每個號碼球的出現次數,這個應該在數據庫裏做,先放這,以後改
def every_ball_count(ball_array):
  ball_list = []
  for ball_char in ball_array:
    ball_list += ball_char.split(;)
  ball_count = {}
  for ball_num in ball_list:
    if ball_num in ball_count:
      ball_count[ball_num] += 1
    else:
      ball_count[ball_num] = ball_count.get(ball_num,0) + 1
  return ball_count

# 數據分析主函數,樣本量必須大於等於7,否則不進行處理
def analysis_main(start_dt,end_dt):
  red_ball_array,blue_ball_array,row_count,col_count = get_ball_infomation(start_dt,end_dt)
  if row_count < 7:
    print 樣本量不足以支持分析
    return 1
  red_count_dict = every_ball_count(red_ball_array)
  blue_count_dict = every_ball_count(blue_ball_array)
  for red_case in red_count_dict:
    red_rate = binomial_class((red_count_dict[red_case] + 1),(row_count + 1),0.5)
    red_count_dict[red_case] = red_rate.binomial_fun()
  for blue_case in blue_count_dict:
    blue_rate = binomial_class((blue_count_dict[blue_case] + 1),(row_count + 1),0.5)
    blue_count_dict[blue_case] = blue_rate.binomial_fun()
  sorted_red_count = sorted(red_count_dict.iteritems(),key=operator.itemgetter(1),reverse=True)
  sorted_blue_count = sorted(blue_count_dict.iteritems(),key=operator.itemgetter(1),reverse=True)
  print sorted_blue_count[0]
  print 選擇紅球是:
  n = 1
  for key,value in sorted_red_count:
    if n == 7:
      break
    print %s,%s %(key,str(value))
    n += 1
  print 選擇藍球是
  print %s,%s %(sorted_blue_count[0][0],str(sorted_blue_count[0][1]))

if __name__ == __main__:
  n = ‘‘
  while n != 1 or n != 2:
    input_n = raw_input(‘‘‘
請選擇需要進行的功能
1、爬取頁面的球號
2、進行球號分析
輸入quit退出
請選擇: ‘‘‘)
    if input_n == 1:
      url = raw_input(‘‘‘
請輸入需要爬取的地址(此為開始地址,因此建議選擇頁碼較大的地址)
輸入: ‘‘‘)
      end_page = raw_input(‘‘‘
輸入結束頁碼
(註意:如果結束頁碼大於輸入地址的頁碼,則不會爬取任何頁面)
輸入: ‘‘‘)
      ball_main(url,end_page)
    elif input_n == 2:
      analysis_main(2018-08-15,2018-09-09)
    elif input_n == quit:
      exit(0)

腳本共分兩個功能塊,一個是爬蟲,用來爬取雙色球號碼,另一個是分析,使用二項分布對已抓取數據進行概率計算

先說說爬蟲,依然是先觀察頁面

技術分享圖片

看過之前初級爬蟲的同學應該對這個很熟悉,要爬的是1的地方,觀察位置2和位置3,不難看出,每期占用一個頁面,那麽只要利用翻頁,每次頁碼-1即可,下面看看1位置的源代碼

技術分享圖片

在源碼中搜索開獎號碼,找到紅圈位置,這個和偽代碼中寫的一樣,現在看爬取正則

red_no_re = re.compile((?<=\<li class\=\"ball_red\"\>)[0-9]+(?=\<\/li\>))

blue_no_re = re.compile((?<=\<li class\=\"ball_blue\"\>)[0-9]+(?=\<\/li\>))

date_re = re.compile((?<=開獎日期:)[0-9]+年[0-9]+月[0-9]+日)
分別爬取紅球,籃球,日期
下面的事就好辦了,將爬好的數據存入數據庫,連接mysql,包含4個參數

db = ‘pythondb‘
host = ‘localhost‘
iuser = ‘xxx‘
passwd = ‘xxxxxx‘

分別是連接數據庫、連接地址、用戶名、密碼

因為在每期開獎之後都需要爬一次新的號碼,所以我沒有把這個做成一次性的,用戶需要輸入開始爬取頁面,以及結束頁面編號,當爬取到結束編號頁面後則停止

為防止重復爬入數據,導致數據庫數據重復,因此在數據入庫前需要對庫數據進行驗證需要入庫數據是否已存在,詳見check_open_date函數

最後需要註意的是,在寫入完畢後應關閉數據庫連接,因為mysql默認自動commit,因此我這個沒有單獨commit的sql,如果是oracle不要忘記加這個

接下來是分析模塊,二項分布為方便管理,單獨寫了個類,以後也可以單獨調用,這個用法我之前的文裏面有說明,就不再說了。這裏有幾個功能說明下

1、與爬蟲一樣,分析也是需要寫入開始日期和結束日期的,且從庫中獲取case必須大於7個,否則考慮樣本不足,無法分析

2、將每個號碼在時間段的出現頻次進行統計並+1,即二項分布的成功k次數

3、獲取時間段內的期數並+1,即二項分布的實驗次數

4、因為每個號碼只有兩種可能,要麽出現,要麽不出現,因此事件的成功率是0.5

技術分享圖片

結果是這樣,看到概率最高的是2.34863516114e-08,這是一個科學技術法,大約是0.00000002349,也就是1/5000萬,因此這個概率沒有任何意義,當然你也可以嘗試買2塊錢的,買不中別賴我啊,哈哈

細心的同學可能註意到了,算出來的最後兩個紅球概率是一樣的,舉個例子C(5,2)其實和C(5,3)的組合數是一樣的,那麽二項分布的概率當然也一樣,這樣就需要用到泊松分布,加入歷史平均值的計算,因為這個需要在庫中單獨建表,還沒有時間做這個事,因此沒有加入這項計算,如果各位有興趣可以自己嘗試把這塊加上,等我有時間了,我也會把這個寫出來完善下的

python寫一個雙色球計算器