首先聲明,賭博一定不是什麼好事,也完全沒有意義,不要指望用彩票發財。之所以寫這個,其實是用來練手的,可以參考這個來預測一些其他的東西,意在拋磚引玉。 啰嗦完了,馬上開始,先上偽代碼 打開網址 讀取內容內容解析 根據源碼得到需爬取內容 1、開獎日期:2018年8月26日 2、紅球 <li class= ...
首先聲明,賭博一定不是什麼好事,也完全沒有意義,不要指望用彩票發財。之所以寫這個,其實是用來練手的,可以參考這個來預測一些其他的東西,意在拋磚引玉。
啰嗦完了,馬上開始,先上偽代碼
打開網址
讀取內容
內容解析
根據源碼得到需爬取內容
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)的組合數是一樣的,那麼二項分佈的概率當然也一樣,這樣就需要用到泊松分佈,加入歷史平均值的計算,因為這個需要在庫中單獨建表,還沒有時間做這個事,因此沒有加入這項計算,如果各位有興趣可以自己嘗試把這塊加上,等我有時間了,我也會把這個寫出來完善下的