Membuka Kedok Bola Basket Menggunakan Python
Dalam seri blog ini, perpustakaan Python yang kuat dimanfaatkan untuk membantu mengungkap beberapa kebenaran statistik tersembunyi dalam bola basket. Langkah pertama dalam setiap pendekatan berbasis data adalah mengidentifikasi dan mengumpulkan data yang dibutuhkan.
Beruntung bagi kami, Basketball-Reference.com menghosting halaman data bola basket yang dapat dengan mudah dihapus. Proses panduan ini dapat dengan mudah diterapkan ke sejumlah halaman mereka, tetapi untuk kasus ini, kami berencana mengumpulkan statistik musiman dari beberapa kelas pemula.
Objektif
- Identifikasi Sumber Data
- Unduh Halaman
- Identifikasi Elemen Halaman Penting
- Pra-Bersihkan dan Ekstrak
- Arsip
- Permintaan paket
- Paket sup cantik
- Paket Panda
Mengidentifikasi Sumber Data
Basketball-Reference.com menyelenggarakan ratusan halaman yang dikurasi tentang statistik bola basket yang berkisar dari rata-rata musiman kategori skor kotak tipikal seperti poin, rebound, dan persentase tembakan, hingga aksi play-by-play dari setiap game yang dimainkan di pertandingan terakhir. 20 atau lebih tahun. Seseorang dapat dengan mudah tersesat dalam tsunami statistik ini jika tidak ada tujuan yang jelas tentang apa yang sebenarnya harus dicari.
Tujuan di sini di posting ini sederhana: dapatkan data rookie yang akan membantu menilai nilai dan potensi pemain muda yang sebenarnya.
Tautan berikut adalah salah satu halaman tersebut. Ini mencantumkan semua statistik pemula yang relevan di musim tertentu.
https://www.basketball-reference.com/leagues/NBA_1990_rookies-season-stats.html
Untuk mengumpulkan data yang cukup untuk membuat kesimpulan statistik yang solid tentang pemain, data satu tahun tidak akan cukup. Perlu ada data puluhan tahun yang dikumpulkan untuk membantu menyaring kebisingan dan sampai pada kesimpulan tentang potensi masa depan pemain.
Jika suatu tindakan dapat diulang secara manual, itu menjadikannya kandidat yang bagus untuk otomatisasi. Dalam hal ini, nomor di URL di atas sesuai dengan tahun masing-masing kelas pemula tersebut. Didukung dengan pengetahuan itu, mari kita mulai menyusun baris kode pertama kita.
import requests
from bs4 import BeautifulSoup
import pandas as pd
years = list(range(1990, 2017))
url_base = "https://www.basketball-reference.com/leagues/NBA_{}_rookies-season-stats.html"
- Paket yang sesuai diimpor
- Variabel daftar
yearsmenentukan rentang tahun yang diinginkan - 1990 hingga 2017 url_baseberfungsi untuk menyimpan variabel string pra-format dari URL target
Dalam menggores halaman web, sangat penting untuk menghapus sebanyak mungkin overhead. Melihat situs menyimpan semua informasi mereka di bagian depan HTML, halaman tersebut dapat dengan mudah diunduh dan disimpan secara lokal secara keseluruhan.
#loop iterates through years
for year in years:
url = url_base.format(year)
data = requests.get(url)
#each page year is locally stored as an HTML file
with open("notebooks/Rookies/{}.html".format(year), "w+") as f:
f.write(data. Text)
- Kurung kurawal yang ditemukan di dalam
urlstring akan berfungsi untuk memungkinkan untukformatmenggantinya dengan tahun yang sedang diiterasi
— Misalnya, di iterasi pertama, nilainyaurlakan menjadihttps://www.basketball-reference.com/leagues/NBA_1990_rookies-season-stats.html
— Pada iterasi keduanya, tahun berikutnya akan direferensikan sebagai gantinya:https://www.basketball-reference.com/leagues/NBA_1991_rookies-season-stats.html - Variabel data bertindak sebagai placeholder untuk
requests.get()fungsi dan referensi dariurlnilai string yang saat ini diiterasi - Metode tersebut
requestskemudian menggunakan string URL yang baru diformat untuk mengambil halaman yang dimaksud - Berikutnya
with open()membaca dan menulis (w+) data halaman darirequests.get(data.text) kami, dan secara lokal menyimpan file HTML yang baru dibuat
Untuk menghindari kesulitan umum dalam pengikisan situs, kami menyimpan laman ini sebagai file HTML lokal. Lihat, saat melakukan kunjungan ke halaman situs, server hosting halaman tersebut menghormati permintaan Anda dan mengirimkan kembali data yang sesuai ke browser Anda. Tetapi memiliki satu klien khusus yang meminta informasi yang sama berulang kali membuat server menjadi tegang. Admin server berhak untuk memblokir permintaan terus-menerus ini demi dapat memberikan layanan ini secara optimal kepada orang lain secara online.
Dengan mengunduh file HTML ini di mesin lokal Anda, Anda menghindari dua hal:
- Harus menunggu lebih lama dari biasanya untuk mengumpulkan data yang sama
- Diblokir dari mengunjungi halaman, menghentikan pengumpulan data sama sekali
Ada beberapa keuntungan dalam mengorek data dari format HTML. Salah satu yang terpenting adalah bagaimana sifat-sifat unsur dapat diidentifikasi secara unik. Jika mereka dapat diidentifikasi secara unik, mereka dapat dikikis menggunakan Beautiful Soup. Tetapi untuk melakukan itu, seseorang harus tahu bagaimana memeriksa sendiri elemen-elemen HTML ini.
Cara Pemeriksaan
Kita harus menyelami lebih dalam cara kerja bagian dalam dokumen ini, tetapi saya berjanji tidak akan menjadikan ini sebagai latihan untuk mempelajari HTML.
Jika Anda tahu cara memeriksa objek HTML, silakan lanjutkan. Jika tidak, silakan ikuti cara memeriksa elemen halaman.
- Klik pada tiga titik vertikal di bilah menu atas Chrome
- Pilih “Alat lainnya”
- Pilih alat Pengembang.
- Klik kanan pada halaman web
- Pilih "Periksa" untuk mengakses panel alat Pengembang
Memeriksa Halaman
Melihat bahwa semua halaman ini disimpan secara lokal, kita dapat memilih untuk melihatnya dengan masuk ke sistem file untuk membukanya di browser yang kita inginkan, atau kita dapat terus membuat kode dengan mengimplementasikan potongan kode berikut.
with open("notebooks/Rookies/2000.html") as f:
page = f.read()
Semua data yang diinginkan dari halaman ini ditempatkan di elemen tabel itu. Sebelum buru-buru menyedot semua data ini apa adanya, sekarang adalah waktu terbaik untuk mempertimbangkan apakah semua yang ada di tabel ini layak untuk dikumpulkan.
Pra-Bersihkan
Pra-pembersihan mungkin bukan kata yang sering ada dalam kosa kata Anda, tetapi bagi Anda yang melihat diri Anda mengorek data secara teratur, seharusnya begitu. Jika Anda ingin menghindari frustrasi karena membuang waktu berjam-jam untuk kemajuan proyek pengumpulan data, yang terbaik adalah memisahkan sekam dari gandum terlebih dahulu.
Misalnya, perhatikan tiga elemen yang dikotak merah.
Satu baris berfungsi sebagai tajuk tabel "utama". Dua baris lainnya adalah contoh duplikat dari artefak yang sama yang ditemukan di bagian atas. Pola ini berulang setiap baris ke-20.
Pemeriksaan lebih lanjut mengungkapkan bahwa semua baris ini memiliki trtag HTML (baris tabel) yang sama. Yang membedakan masing-masing elemen ini dari elemen lainnya adalah nama kelasnya.
- Baris Tajuk Utama
— Kelas =over_header - Ulangi Baris Header
— Kelas =over_header thead - Baris Kategori Statistik
— Kelas =thead - Objek
classesarray akan menampung semua nama kelas elemen baris tabel yang tidak diinginkan.
#array to house list of dataframes
dfs = []
#unnecessary table rows to be removed
classes = ["over_header", "over_header thead", "thead"]
Metode tersebut decomposeberfungsi untuk menghapus elemen yang tidak diinginkan tersebut di halaman. Sesuai dokumentasi resmi Beautiful Soup ...
decompose()
Tag.decompose()menghapus tag dari pohon, lalu menghancurkannya sepenuhnya dan isinya.
Di bawah ini adalah cuplikan kode tempat kami dapat mengoptimalkan decomposemetode dengan bantuan forloop.
#for loop to iterate through the years
for year in years:
with open("notebooks/Rookies/{}.html".format(year)) as f:
page = f.read()
soup = BeautifulSoup(page, "html.parser")
#for loop cleans up unnecessary table headers from reappearing in rows
for i in classes:
for tr in soup.find_all("tr", {"class":i}):
tr.decompose()
- Metode ini
withmemberikan kode kita struktur untukpagevariabel untuk membaca file HTML yang disimpan secara lokal saat dipanggil - Kelas parser HTML diinisialisasi dengan membuat instance kelas Beautiful Soup dan mengirimkan
pageobjek string, danhtml.parser. - Loop kedua
formengulang melalui nilai-nilai dalamclassesarray - Loop ketiga
formenggunakan metode Beautiful Soupfind_alluntuk mengidentifikasi elemen yang memiliki tagtrdan nama kelas yang cocokclasses tr.decomposeberfungsi untuk menghilangkan setiap elemen baris tabel yang teridentifikasi dari halaman seluruhnya
Mengekstrak Data
Kami akhirnya dapat mulai mengerjakan bagian kode yang benar-benar mengekstrak data dari tabel. Ingatlah bahwa tabel dengan semua data yang relevan memiliki ID unik HTML rookies. Penambahan berikut pada kode kita akan berfungsi untuk mem-parsing data tabel ini.
#the years we wish to parse for
years = list(range(1990, 2017))
#array to house list of dataframes
dfs = []
#unnecessary table headers to be removed
classes = ["over_header","over_header thead", "thead"]
for year in years:
#url = url_base.format(year)
#data = requests.get(url)
##page is saved as an html and placed in Rookies folder
#with open("notebooks/Rookies/{}.html".format(year), "w+") as f:
#f.write(data.text)
#with open("notebooks/Rookies/2000.html") as f:
with open("notebooks/Rookies/{}.html".format(year)) as f:
page = f.read()
soup = BeautifulSoup(page, "html.parser") #for loop cleans up unnecessary table headers from reappearing in rows
for i in classes:
for tr in soup.find_all("tr", {"class":i}):
tr.decompose()
### Scraping Block ###
#identifies, scrapes, and loads rookie tables into one dataframe
rookie_table = soup.find(id="rookies")
rookies = pd.read_html(str(rookie_table))[0]
rookies["Year"] = year
dfs.append(rookies)
#new variable turns list of dataframes into single dataframe
all_rookies = pd.concat(dfs)
rookie_tableinstantiate metode Beautiful Soupfinduntuk mengidentifikasi elemen HTML dengan IDrookies- Melihat bahwa Pandas dapat membaca tabel HTML, tabel rookie dimuat ke dalam Pandas menggunakan
read_htmlmetode tersebut, meneruskannyarookie_tablesebagai string - Tacking on to end
[0]berubahrookiesdari daftar frame data menjadi satu frame data - Kolom "Tahun" adalah akhir dari
rookieskerangka data dfs.append(rookies)berfungsi untuk menampung semua tabel dari setiap tahun pemula dalam urutan mereka mengulanginya ke dalam daftar bingkai data- Metode Pandas
concatdigunakan untuk menggabungkan daftar frame data menjadi satu frame data tunggal:all_rookies
Langkah terakhir kami melibatkan mengambil semua informasi yang berguna dan bersih ini dan mengarsipkannya dalam format CSV yang mudah dibaca manusia dan mesin. Menempelkan baris ini ke akhir kode kita akan berguna saat memutuskan untuk kembali dan mereferensikan data yang dikumpulkan.
#a single dataframe archived as a local CSV using Pandas
all_rookies.to_csv("archive/NBA_Rookies_1990-2016.csv")
import requests
import pandas as pd
from bs4 import BeautifulSoup
years = list(range(1990, 2017))
dfs = []
classes = ["over_header","over_header thead", "thead"] #unnecessary table headers to be removed
for year in years:
with open("C:/Users/cisco/OneDrive/python/Projects/Basketball/Rookies/{}.html".format(year), encoding = "utf-8") as f:
page = f.read()
soup = BeautifulSoup(page, "html.parser")
#second for loop cleans up unnecessary table headers from reappearing in rows
for i in classes:
for tr in soup.find_all("tr", {"class":i}):
tr.decompose()
#identifies, scrapes, and loads rookie tables into one dataframe
table_rookies = soup.find(id="rookies")
rookies = pd.read_html(str(table_rookies))[0]
rookies["Year"] = year
dfs.append(rookies)
#new variable turns list of dataframes into single dataframe
all_rookies = pd.concat(dfs)
#dataframe archived as local CSV
all_rookies.to_csv("archive/NBA_Rookies_1990-2016.csv")
Sekali lagi, proses yang diikuti dalam panduan ini tidak diragukan lagi akan berlaku untuk hampir semua halaman lainnya di Basketball-Reference.com . Ada lima langkah sederhana yang layak dilakukan di setiap contoh.
- Identifikasi URL Halaman
- Unduh Halaman
- Identifikasi Elemennya
- Pra-Bersihkan dan Ekstrak
- Arsip
Selanjutnya dalam seri ini akan benar-benar menggunakan data ini untuk mendapatkan wawasan tentang potensi pemain di masa depan. Jadi waspadalah untuk cicilan di masa depan!

![Apa itu Linked List? [Bagian 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































