在大數據時代,一切都要用數據來講話,大數據處理的過程通常須要通過如下的幾個步驟css
數據的採集和獲取html
數據的清洗,抽取,變形和裝載python
數據的分析,探索和預測web
數據的展示shell
其中首先要作的就是獲取數據,並提煉出有效地數據,爲下一步的分析作好準備。api
數據的來源多種多樣,覺得我自己是足球愛好者,而世界盃就要來了,因此我就想提取歐洲聯賽的數據來作一個分析。許多的網站都提供了詳細的足球數據,例如:服務器
網易 http://goal.sports.163.com/ app
騰訊體育 http://soccerdata.sports.qq.com/ scrapy
虎撲體育 http://soccer.hupu.com/ ide
這些網站都提供了詳細的足球數據,然而爲了進一步的分析,咱們但願數據以格式化的形式存儲,那麼如何把這些網站提供的網頁數據轉換成格式化的數據呢?這就要用到Web scraping的技術了。簡單地說,Web Scraping就是從網站抽取信息, 一般利用程序來模擬人瀏覽網頁的過程,發送http請求,從http響應中得到結果。
在抓取數據以前,要注意如下幾點:
閱讀網站有關數據的條款和約束條件,搞清楚數據的擁有權和使用限制
友好而禮貌,使用計算機發送請求的速度飛人類閱讀可比,不要發送很是密集的大量請求以避免形成服務器壓力過大
由於網站常常會調整網頁的結構,因此你以前寫的Scraping代碼,並不老是可以工做,可能須要常常調整
由於從網站抓取的數據可能存在不一致的狀況,因此頗有可能須要手工調整
Python提供了很便利的Web Scraping基礎,有不少支持的庫。這裏列出一小部分
BeautifulSoup http://www.crummy.com/software/BeautifulSoup/
Scrapy http://scrapy.org/
webscraping https://code.google.com/p/webscraping/
固然也不必定要用Python或者不必定要本身寫代碼,推薦關注import.io
下面,咱們就一步步地用Python,從騰訊體育來抓取歐洲聯賽13/14賽季的數據。
首先要安裝Beautifulsoup
pip install beautifulsoup4
咱們先從球員的數據開始抓取。
球員數據的Web請求是http://soccerdata.sports.qq.com/playerSearch.aspx?lega=epl&pn=2 ,返回的內容以下圖所示:
該web服務有兩個參數,lega表示是哪個聯賽,pn表示的是分頁的頁數。
首先咱們先作一些初始化的準備工做
from urllib2 import urlopen import urlparse import bs4 BASE_URL = "http://soccerdata.sports.qq.com" PLAYER_LIST_QUERY = "/playerSearch.aspx?lega=%s&pn=%d" league = ['epl','seri','bund','liga','fran','scot','holl','belg'] page_number_limit = 100 player_fields = ['league_cn','img','name_cn','name','team','age','position_cn','nation','birth','query','id','teamid','league']
urlopen,urlparse,bs4是咱們將要使用的Python庫。
BASE_URL,PLAYER_LIST_QUERY,league,page_number_limit和player_fields是咱們會用到的一些常量。
下面是抓取球員數據的具體代碼:
def get_players(baseurl): html = urlopen(baseurl).read() soup = bs4.BeautifulSoup(html, "lxml") players = [ dd for dd in soup.select('.searchResult tr') if dd.contents[1].name != 'th'] result = [] for player in players: record = [] link = '' query = [] for item in player.contents: if type(item) is bs4.element.Tag: if not item.string and item.img: record.append(item.img['src']) else : record.append(item.string and item.string.strip() or 'na') try: o = urlparse.urlparse(item.a['href']).query if len(link) == 0: link = o query = dict([(k,v[0]) for k,v in urlparse.parse_qs(o).items()]) except: pass if len(record) != 10: for i in range(0, 10 - len(record)): record.append('na') record.append(unicode(link,'utf-8')) record.append(unicode(query["id"],'utf-8')) record.append(unicode(query["teamid"],'utf-8')) record.append(unicode(query["lega"],'utf-8')) result.append(record) return result result = [] for url in [ BASE_URL + PLAYER_LIST_QUERY % (l,n) for l in league for n in range(page_number_limit) ]: result = result + get_players(url)
咱們來看看抓取球員數據的詳細過程:
首先咱們定義了一個get_players方法,該方法會返回某一請求頁面上全部球員的數據。爲了獲得全部的數據,咱們經過一個for循環,由於要循環各個聯賽,每一個聯賽又有多個分頁,通常狀況下是須要一個雙重循環的:
for i in league: for j in range(0, 100): url = BASE_URL + PLAYER_LIST_QUERY % (l,n) ## send request to url and do scraping
Python的list comprehension能夠很方便的經過構造一個列表的方式來減小循環的層次。
另外Python還有一個很方便的語法來合併連個列表: list = list1 + list2
好咱們再看看如何使用BeautifulSoup來抓取網頁中咱們須要的內容。
首先調用urlopen讀取對應url的內容,一般是一個html,用該html構造一個beautifulsoup對象。
beautifulsoup對象支持不少查找功能,也支持相似css的selector。一般若是有一個DOM對象是<xx class='cc'>,咱們使用如下方式來查找:
obj = soup.find("xx","cc")
另一種常見的方式就是經過CSS的selector方式,在上述代碼中,咱們選擇class=searchResult元素裏面,全部的tr元素,過濾掉th也就是表頭元素。
for dd in soup.select('.searchResult tr') if dd.contents[1].name != 'th'
對於每一行記錄tr,生成一條球員記錄,並存放在一個列表中。因此咱們就循環tr的內容tr.contents,得到對應的field內容。
對於每個tr的content,咱們先檢查其類型是否是一個Tag,對於Tag類型有幾種狀況,一種是包含img的狀況,咱們須要取出球員的頭像圖片的網址。
另外一種是包含了一個連接,指向其餘數據內容
因此在代碼中要分別處理這些不一樣的狀況。
對於一個Tag對象,Tag.x能夠得到他的子對象,Tag['x']能夠得到Tag的attribute的值。
因此用item.img['src']能夠得到item的子元素img的src屬性。
對已包含連接的狀況,咱們經過urlparse來獲取查詢url中的參數。這裏咱們利用了dict comprehension的把查詢參數放入一個dict中,而後添加到列表中。
dict([(k,v[0]) for k,v in urlparse.parse_qs(o).items()])
對於其它狀況,咱們使用Python 的and or表達式以確保當Tag的內容爲空時,咱們寫入‘na’,該表達式相似C/C++或Java中的三元操做符 X ? A : B
而後有一段代碼判斷當前記錄的長度是否大於10,不大於10則用空值填充,目的是避免一些不一致的地方。
if len(record) != 10: for i in range(0, 10 - len(record)): record.append('na')
最後,咱們把query中的一些相關的參數如球員的id,球隊的id,所在的聯賽代碼等加入到列表。
record.append(unicode(link,'utf-8')) record.append(unicode(query["id"],'utf-8')) record.append(unicode(query["teamid"],'utf-8')) record.append(unicode(query["lega"],'utf-8'))
最後咱們把本頁面全部球員的列表放入一個列表返回。
好了,如今咱們擁有了一個包含全部球員的信息的列表,咱們須要把它存下來,以進一步的處理,分析。一般,csv格式是一個常見的選擇。
import csv def write_csv(filename, content, header = None): file = open(filename, "wb") file.write('\xEF\xBB\xBF') writer = csv.writer(file, delimiter=',') if header: writer.writerow(header) for row in content: encoderow = [dd.encode('utf8') for dd in row] writer.writerow(encoderow) write_csv('players.csv',result,player_fields)
這裏須要注意的就是關於encode的問題。由於咱們使用的時utf-8的編碼方式,在csv的文件頭,須要寫入\xEF\xBB\xBF,詳見這篇文章
好了如今大功告成,抓取的csv以下圖:
由於以前咱們還抓取了球員本賽季的比賽詳情,因此咱們能夠進一步的抓取全部球員每一場比賽的記錄
抓取的代碼以下
def get_player_match(url): html = urlopen(url).read() soup = bs4.BeautifulSoup(html, "lxml") matches = [ dd for dd in soup.select('.shtdm tr') if dd.contents[1].name != 'th'] records = [] for item in [ dd for dd in matches if len(dd.contents) > 11]: ## filter out the personal part record = [] for match in [ dd for dd in item.contents if type(dd) is bs4.element.Tag]: if match.string: record.append(match.string) else: for d in [ dd for dd in match.contents if type(dd) is bs4.element.Tag]: query = dict([(k,v[0]) for k,v in urlparse.parse_qs(d['href']).items()]) record.append('teamid' in query and query['teamid'] or query['id']) record.append(d.string and d.string or 'na') records.append(record) return records[1:] ##remove the first record as the header def get_players_match(playerlist, baseurl = BASE_URL + '/player.aspx?'): result = [] for item in playerlist: url = baseurl + item[10] print url result = result + get_player_match(url) return result match_fields = ['date_cn','homeid','homename_cn','matchid','score','awayid','awayname_cn','league_cn','firstteam','playtime','goal','assist','shoot','run','corner','offside','foul','violation','yellowcard','redcard','save'] write_csv('m.csv',get_players_match(result),match_fields)
抓取的過程和以前相似。
如今咱們擁有了詳細的歐洲聯賽的數據,那麼下一步要怎麼作呢,我推薦你們把數據導入BI工具來作進一步的分析。有兩個比較好的選擇:
Tableau在數據可視化領域可謂無出其右,Tableau Public徹底免費,用數據可視化來驅動數據的探索和分析,擁有很是好的用戶體驗
Splunk提供一個大數據的平臺,主要面向機器數據。支持天天免費導入500M的數據,若是是我的學習,應該足夠了。
固然你也能夠用Excel。 另外你們若是有什麼好的免費的數據分析的平臺,歡迎交流。