用爬蟲抓取崑崙決所有選手信息並保存為PDF檔案!(淺談搏擊運動數據分析)
GitHub地址:QuantumLiu/KLFSpider
背景
本人是個偽拳迷,520之夜我跑到「寶馬雕車香滿路」的某豪車交易中心,現場觀看了崑崙決「」讓子彈飛」MMA比賽,不但看夠了豪車美女(受夠了刺激)
欣賞了精彩刺激的比賽更是見證了姜老闆和龍武探討摔跤哲學
正文
在本文中,我們從崑崙決爬取了全部350位的公開信息,包括姓名、年齡、戰績、身高體重等。並保存為 `.md` 的markdown文件,並進一步使用Python-markdown 庫將markdown文本轉換為HTML文件並列印為pdf文件。
一.分析網頁結構並確定處理流程
進入崑崙決首頁,點擊選手選項卡下的「運動員」。
不出所料,對應的網頁是一個索引性質的各個選手的簡介頁面。但是我們注意到,這個網頁並不是一次載入完成的,在底部有一個「載入更多」的按鈕通過開發工具,我們知道這是一個xxxx/n.html形式的鏈接,而且n是從2開始的。
所以我們可以推測這個簡介頁面原理如下:n=1n載入xxxx/1.htmlnwhile n<n_max:n 點擊「載入更多」n n+=1n load(xxx/n.html)n
我們稱xxxx/n.html為簡介內容鏈接。如果我們枚舉所有的簡介內容鏈接,就可以得到所有選手的簡介和詳情頁面的入口。
我們先嘗試一下當n=1是頁面是否存在並試出最大頁數。
我們看到當n=1時,簡介內容鏈接的內容和簡介頁面的核心內容是一樣的(亂碼應該是因為ISO編碼問題),同時我們試出來最大有效頁數是26。接下來我們進入每個選手的詳情頁面,所有我們需要的信息都在這個頁面
現在我們明確了網頁的結構,抓取的流程也就隨之確定下來了抓取流程:
獲取所有簡介內容鏈接n抓取所有選手詳情鏈接nfor 詳情鏈接 in 所有選手詳情鏈接:n 抓取信息並處理n return 信息n
二.具體實現
1.正則表達式
首先我們要抓取的所有的詳情鏈接。
通過開發工具,我們看到在簡介頁面中每個選手的詳情鏈接:
於是可以確定詳情頁面的正則:
r_player_info_page=r</a></li><li><a href="(.*?)" title="#詳情頁的正則n
接下來我們查看選手詳情頁的代碼來獲得每項屬性的正則。
我們驚喜的發現包裹每項信息的字元非常的規律與簡潔!
我們不妨先得到所有屬性名稱的list再得到所有屬性的內容r_att=r <li><span>(.*?)</span>#屬性名稱正則natt_list=re.findall(r_att,page_text)[0:8]nfor att in att_list:n r=r<li><span>+att+</span>([sS]*?)</li>#屬性內容正則n
其中使用([sS]*?)匹配符是因為簡介信息會有換行符n,所以要匹配所有的包括換行符在內地符號。
我們看到的對於外國選手,姓名屬性只有中文譯名,所以我們還需要英文名。
全名、戰績以及排名的正則:
r_name=r<div class="uk-width-2-3 info"> <h1><img src=".*?">(.*?)</h1> nr_gain=r<h3 class="chengji">(.*?)</h3>nr_rank=r<!-- <h3 class="paiming">(.*?)</h3>n
最後,我們得到選手圖片鏈接的正則
r_pic=r<div class="uk-width-1-3 avatar"> <img src="(.*?)" alt=n
以上,我們完成了對所要抓取信息的正則的分析,接下來我們編寫一個完整的爬蟲程序。
2.完整程序
程序邏輯:
定義一個player類,每個運動員看做一個player對象。
按照我的習慣,我選擇使用requests庫和multiprocessing來實現這個爬蟲。
通過並行遍歷每個運動員的詳情頁處理數據,將信息保存為Markdown格式
最後,我們使用 markdown庫將markdown文本轉換為html文件,再使用印表機列印為pdf文檔。
# -*- coding: utf-8 -*-n"""nCreated on Sun May 21 20:29:40 2017nn@author: Quantum Liun"""nnimport requestsnimport renimport picklenimport markdownnimport codecsnfrom multiprocessing import Pool,cpu_count,freeze_supportnimport osnclass player():#每個運動員都是一個player對象n def __init__(self,info_dic,info,pic_url):n self.info_dic=info_dicn self.info=infon self.pic_url=pic_urln self.name=self.info_dic.get(姓名)n self.dir_name=./+self.info_dic.get(姓名)n self.info_file=self.dir_name+/+info.mdn def mkdir(self):#創建運動員目錄n if not os.path.exists(self.dir_name):n os.mkdir(self.dir_name)n def saveimg(self):#保存頭像圖片n self.pic_path=self.dir_name+/+head.pngn data=requests.get(self.pic_url).contentn with open(self.pic_path,wb) as f:n f.write(data)n def saveasmd(self):#生成個人.md文檔n with open(self.info_file,w,encoding=utf-8) as f:n head=# +self.info_dic.get(姓名)n pic_link= r![pic](./head.png) rn upic_link= r![pic](+self.pic_path+) rn self.mdtext=head+pic_link+self.info#個人markdown文本內容n self.umdtext=head+upic_link+self.info#合集的markdown內容n f.write(self.mdtext)ndef player_info(page_text=):n info=n r_att=r <li><span>(.*?)</span>#屬性名稱正則n r_name=r<div class="uk-width-2-3 info"> <h1><img src=".*?">(.*?)</h1> n r_gain=r<h3 class="chengji">(.*?)</h3>n r_rank=r<!-- <h3 class="paiming">(.*?)</h3>n r_pic=r<div class="uk-width-1-3 avatar"> <img src="(.*?)" alt=n att_list=re.findall(r_att,page_text)[0:8]n att_list.remove(社交)#社交這一項信息無用n dic={}.fromkeys(att_list)n pic_url=http://www.kunlunjue.com+re.findall(r_pic,page_text)[0]n name=re.findall(r_name,page_text)[0]n gain=re.findall(r_gain,page_text)[0]n rank=re.findall(r_rank,page_text)[0]n dic[全名]=namen dic[戰績]=gainn dic[排名]=rankn info+=全名:+name+ r+戰績:+gain+ r+排名:+rank+ rn for att in att_list:n r=r<li><span>+att+</span>([sS]*?)</li>#屬性內容正則n value=re.findall(r,page_text)[0].replace(n, r)#將換行改為markdown格式n info+=att+:+value+ rn dic[att]=valuen return (dic,info,pic_url)ndef processing(page_url=):#想不出函數名的時候就叫它processing吧n page_text=requests.get(page_url).textn info_dic,info,pic_url=player_info(page_text=page_text)n p=player(info_dic,info,pic_url)n p.mkdir()n p.saveimg()n p.saveasmd()n return p#返回一個player對象nif __name__ == __main__:n freeze_support()n #全體自由搏擊選手或者全部項目運動員的索引頁的HTML內容n free_sparring_only=Truen index_root=(http://www.kunlunjue.com/portal/player/player_fall/level/all/national/all/height/all/order/any/desc/des/type/%E8%87%AA%E7%94%B1%E6%90%8F%E5%87%BB/p/ if free_sparring_only else http://www.kunlunjue.com/portal/player/player_fall/level/all/national/all/height/all/order/any/desc/des/type/all/p/)n ran=(26 if free_sparring_only else 37)n all_page_text=.join([requests.get(page).text.encode(ISO-8859-1).decode(utf-8) for page in [index_root+str(int(i+1))+.html for i in range(ran)]])n r_player_info_page=r</a></li><li><a href="(.*?)" title="#詳情頁的正則n info_page_list=[http://www.kunlunjue.com/+url for url in re.findall(r_player_info_page,all_page_text)]#所有詳情頁n pool=Pool(cpu_count())#根據cpu最大線程數創建並行池n player_list=[]n for page_url in info_page_list:n player_list.append(pool.apply_async(processing,(page_url,)))n pool.close()n pool.join()n player_list=[result.get() for result in player_list]n uni_mdetext=.join([p.umdtext for p in player_list])#全集的md文本n with codecs.open(./uni_data.md,w,encoding=utf-8) as f:n f.write(uni_mdetext)n htmltext=<meta http-equiv="content-type" content="text/html; charset=UTF-8"> r+markdown.markdown(uni_mdetext)n with codecs.open(./uni_data.html,mode=w,encoding=utf-8) as f:n f.write(htmltext)n with open(./players.pkl,wb) as f:#保存運動員player對象的列表n pickle.dump(player_list,f)n
運行結果如圖:
我們用瀏覽器打開HTML文件右鍵列印Done!至此我們完成了對崑崙決所有自由搏擊選手公開信息的抓取,並生成了一個專屬的「機密檔案」pdf文件!我們把每個player都dump起來,留待以後進一步的統計分析。
成品:
鏈接:http://pan.baidu.com/s/1gfHwMht 密碼:btk6
淺談搏擊運動中的體育數據分析(吐槽)
恕我直言,搏擊運動簡直是數據分析的荒漠,幾乎停留在「老中醫看病」的經驗主義階段。
- 信息不公開。
- 崑崙決號稱引入數據統計,但是數據從未公布崑崙決引入技術統計 保證賽事公平公正公開數據說話我的本意是抓一些技術統計數據的,結果只能抓一些簡介。同樣,在國內外我都沒有中的搏擊方面的數據集。
- 沒信息、沒數據,怎麼研究?
我相信很多人都看過《點球成金》這部電影,能夠理解基於數據統計的方法能給一項運動帶來多大的改變。沒看過的希望去看一看,特別是從業者。
與搏擊不同,足球和籃球的技術體育數據分析非常發達,數據也很開放、容易獲得。甚至可以基於統計數據做量化博彩交易策略。
這是我前幾天看過的一篇散打運動的paper,它通過數據分析的方法研究了散打運動員鞭腿運用情況。李大龍, 李小龍. 我國高水平散打運動員鞭腿技術運用特點分析[J]. 遼寧體育科技, 2015(4):105-107.
它統計了十二屆全運會上高水平散打運動員鞭腿的運用情況
老說誰誰誰鞭腿厲害,誰誰誰拳很重.....
應該拿出數據來,誰誰誰的鞭腿運用率是多少成功率是多少,再研究科學、準確的對策。
誠然,客觀上搏擊運動動作更迅速,情況更複雜,技術統計有一定難度,但是這些困難不是很難克服的,主要還是看有沒有心去做。
希望中國的搏擊運動發展的越來越好!
ps:請各位自覺維護知乎的網路環境。上次寫個技術分享博客被噴子撕了半天,這次說好了,批評可以,請指出具體的技術上的不足。再有瞎噴的我也不和你用鍵盤撕了,直接在北京切磋一下搏擊吧,散打規則,時間地點你定:-D
推薦閱讀:
※Python數據分析模塊 | pandas做數據分析(一):基本數據對象
※使用Python進行語音識別---將音頻轉為文字
※Python-Excel 模塊哪家強?
※從零開始掌握Python機器學習:十四步教程