小編也是最近在學習數據挖掘,看到了第三章用決策樹預測獲勝的球隊。然而,NBA官網早就改版了,Export不能全部下載一年的數據記錄,只能按月,而且我也下載不了。想了想,就只能爬取了。話不多說。
小編最開始用的Xpath,感覺路徑有點麻煩,而且速度好像也沒有BeautifulSoup快,所以小編就選用了pyquery和BeautifulSoup兩個方法實現爬取數據。
首先,先查看網站,看到每月的數據,對應的url與月份有關,因此定義函數用於獲取每月的數據,輸入變量為月份。
下面的函數為pyquery的方法。
import requests from pyquery import PyQuery as pq from bs4 import BeautifulSoup import csv headers = { 'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36' } def get_data_pyquery(month): # 構造請求url url = 'https://www.basketball-reference.com/leagues/NBA_2014_games-{}.html'.format(month) result = requests.get(url, headers=headers).text doc = pq(result) # 用於存儲表頭 header = [] # 解析html for thead in doc.find('thead tr th').items(): text = thead.text() # 忽略空白符 # print(text) if(len(text)>2): header.append(text) # 存儲數據 # print(header) data_all = [] for tr in doc('tbody tr').items(): data = [] try: data.append(tr.find('th').text()) for i in ([t.text() for t in tr('td').items()]):
# 用於清除‘OT’不想關的數據 if i and not('OT' in i): data.append(i) # print(data) data_all.append(data) # print(data_all) except: print('有點錯誤,已忽略') return header,data_all
下面的為BeautifulSoup:
def get_data_bs4(month): url = 'https://www.basketball-reference.com/leagues/NBA_2014_games-{}.html'.format(month) result = requests.get(url).text soup = BeautifulSoup(result,"lxml") data_all = [] for i in range(len(soup.tbody.find_all("tr"))): data = [] # 添加時間 data.append(soup.tbody.find_all("tr")[i].find_all("th")[0].getText()) for j in range(len(soup.find_all("tr")[i].find_all("td"))): data.append(soup.find_all("tr")[i].find_all("td")[j].getText()) # 添加沒次的數據 data_all.append(data) # print(data_all) return data_all
這種方法有待完善,爬取的數據不是很全,有紕漏。(小編懶,不改了)
小編着重 用pyquery的方法。
接下來上主函數:
def get_csv(): i = 0 a = 0 months = ['october','november','december','january','february','march','april','may','june'] with open('NBA13_14.csv', 'w')as f: writer = csv.writer(f) for month in months: header,data = get_data_pyquery(month) if i == 0: writer.writerow(header) i += 1 writer.writerows(data) a += 1 print("第{}個月份 寫入完畢".format(a)) print("NBA 2012-2014 共{}月份的數據寫入完畢!!".format(str(i)))
輸出結果:
上述代碼得到csv格式,注意:
在4月份的數據中,有一行不符合規則:
小編用的try,except,直接忽略錯誤,但同時Playoffs也寫入到了文件中。
Playoffs,在得到的csv表格中,刪除即可。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面獲取上一個賽季的比賽記錄,這里的代碼需要重新寫:
一開始,小編還是按照網址:view-source:https://www.basketball-reference.com/leagues/NBA_2013_standings.html
右擊檢查,查找對應的源代碼,如果直接查看網頁源代碼的化,確實可以看到對應的代碼。於是小編就按照看到的寫,最后發現數據對不上。
小編查看對應的源代碼,發現:
小編發現,想爬取的數據都在 注釋里面。那想必是網頁在加載的過程中有JS的動態渲染。這是小編想用selenium或這splash訪問,結果都是TimeOuts,出現延遲。
這是,Embed this Table。彈出來了JS代碼的一個鏈接。發現里面的網址對應代碼有想要的數據。與原來的對比了一下,HTML結構一致,那么就可以進行爬取了。
下面直接上代碼,小編用的Beautifulsoup,當然pyquery也可以,感興趣的可以自己試一下。
from bs4 import BeautifulSoup import requests import csv headers = { 'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36' } def get_data_bs4(url): html = requests.get(url).text soup = BeautifulSoup(html, 'lxml') # 要插入的數據 data_all = [] header = [] tr = soup.find_all(name='tr')[1] for th in tr.find_all(name='th'): header.append(th.string) # print(header) data_all.append(header) # 下面來獲取數據 tbody = soup.find(name='tbody') for tr in tbody.find_all(name='tr'): data = [] data.append(tr.th.string) for td in tr.find_all(name='td'): data.append(td.string) data_all.append(data) return data_all def get_csv(data_all): with open('NBA12-13.csv', 'w') as f: writer = csv.writer(f) for i, data in enumerate(data_all): writer.writerow(data) print("第 {} 名數據下載完畢".format(i + 1)) print("文件下載完畢") if __name__ == '__main__': url = 'https://widgets.sports-reference.com/wg.fcgi?css=1&site=bbr&url=%2Fleagues%2FNBA_2013_standings.html&div=div_expanded_standings' data = get_data_bs4(url) get_csv(data)
完畢!!!!!