期末考 Projects 說明
整個期末考分數(佔學期總分50%)由兩個 project 組成
1. Project 1 - 股價下載器:佔期末考分數80%
2. Project 2 - 基礎數值分析與可視化:佔期末考分數20%
Project 1 - 股價下載器
目標
建立一個圖形介面應用。運行後,在輸入某港股編號後,點擊下載按鈕可以從 YahooFinance 網站下載該港股最近60個交易日的股價。
該程序由以下兩個檔案構成:
1. 模組檔案 yf.py:負責定義一個叫 YahooFinanceHistory 的 python 類,專門用
於處理爬蟲工作。
2. 主程序 app.py:負責使用 tkinter 建立圖形介面。
一點提示
模組 yf.py
在該文件中定義的 YahooFinanceHistory 類要具有以下屬性(attribute)和方法
(method):
1. _url 屬性:為目標網頁之URL之字符串模板:
https://finance.yahoo.com/quote/{code}.HK/history?p={code}.HK
其中 {code} 預定填入股票編號的地方。
2. get_data 方法:接受參數 code(為目標股票編號的字符串)。執行該方法後會
從 Yahoo Finance 下載最近60個交易日的股價。該方法函數應該包含以下四個步
驟:
i. 由 _url 建構完整 URL。
ii. 用 requests.get 函數訪問 Yahoo Finance 網站並取得 HTML 碼。
iii. 用 BeautifulSoup 類分析HTML的結構,並定位所需內容。
iv. 提取數據,建立 DataFrame,並將其返回(return)。
# File: yf.py
class YahooFinanceHistory:
_url = 'https://finance.yahoo.com/quote/{code}.HK/history?p={code}.HK'
def get_data(self, code):
# 以下請應用課堂上教的爬蟲知識:
# 1. 由 `_url` 建構完整 URL。
# 2. 用 `requests.get` 函數訪問 Yahoo Finance 網站並取得其中 HTML 碼。
# 3. 用 `BeautifulSoup` 物件分析HTML的結構,並定位所需內容。
# 4. 提取數據,建立 `DataFrame`,並將其返回(return)。
return df
第一步:由 _url 建構完整 URL 字符串 url
這一步要用到字符串格式化(string formatting)的知識。
def get_data(self, code):
...
url = self._url.format(...) # 請自行完成
...
第二步:用 requests.get 函數訪問 Yahoo Finance 網站並取得 HTML 碼。
這一步用到網絡爬蟲的內容。
requests.get(url) 讓 python 訪問 url 指向的網站,獲取 HTML 內容。可是,YahooFinance 設置了反爬蟲,自動拒絕來自 python 的請求。因此,我們使用一個簡單的方法來反反爬蟲,就是通過設置參數 User-Agent 來假裝自己是普通瀏覽器:
r = requests.get(url, headers={'User-Agent': ua})
其中 ua 為變數名,其值等於以下字符串(也可以從這裏選擇一個):
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15(KHTML, like Gecko) Version/14.1.2 Safari/605.1.15'
成功後 r.text 即為網頁的HTML。
另,建議在 get_data 中增加一行 r.raise_for_status() 來觸發請求失敗後的報錯。
第三步:用 BeautifulSoup 物件分析HTML的結構,並定位所需內容。
同樣是用到網絡爬蟲的內容。
BeautifulSoup 為 bs4 庫的一個類,可以解析HTML內的標簽元素(tag element)的結
構和關係。
soup = BeautifulSoup(r.text, 'lxml')
提示:股價數據所在標簽為一 table 標簽。該標簽具有屬性 data-test,屬性的值為
historical-prices。請利用這一點。
第四步:提取數據,建立 DataFrame,並將其返回(return)
在目標 table 標簽中,可以發現股價數據表每行 row 都處於一個 tr 標簽中。而每行 row
當中每個格(cell)上的數據又位於稱為 th 或 td 的標簽中。
因此,我們可以
table = soup.find?????? # 請自行完成
trs = table.find_all('tr')
data = list()
for tr in trs:
cells = tr.find_all(['th', 'td'])
row = list()
for cell in cells:
row.append(cell.text.strip())
data.append(row)
df = pandas.DataFrame(data[1:61], columns=data[0]) # 只要60個交易日數據
至此 get_data 這個方法函數應該大致上完成。請自行調試。
主程序 app.py
題目要求的圖形介面視窗應該包含四個控件(widget):
1. 標語文字(使用控件類 Label):用於顯示輸入股價的提示標語
2. 輸入欄位(使用控件類 Entry):用於輸入港股編號
3. 按鈕(使用控件類 Button):用於觸發爬蟲的行為
4. 結果狀態提示(使用控件類 Label):用於顯示爬蟲是否成功:
成功則顯示成功!
失敗則顯示失敗!
# File: app.py
import tkinter as tk
import yf # 請把 yf.py 放在同一目錄下
# 按鈕控件觸發以下函數:
def download():
# 1. 讀取 Entry 控件的內容
# 1. 調用 YahooFinanceHistory 類。使用其 get_data 下載股價
# 2. 把返回的數據(DataFrame物件)儲存成 csv 檔案
# 4. 利用 try-except 語法捕捉錯誤
# 建立介面視窗
window = tk.Tk()
window.geometry('200x200')
window.title('股價下載器')
# 下方寫入各控件。所有按件用 pack 進行放置
第一步:建立控件
這一步用到 section9 的內容。
# 用於顯示標語
tk.Label(window, text='請輸入股票編號').pack()
ent = tk.Entry(window)
ent.pack()
tk.Button(..., text='下載', ...).pack() # 請自行完成
lbl = tk.Label(...)
lbl.pack()
要記住每個控件都需要 master 這個參數來說明該控件是建立在什麼結構之上。
Label 和 Button 兩類控件都需要 text 參數來顯示一些文字。
Button 這類控件還需要 command 參數來說明點擊後觸發的動作。
第二步: download 函數
這是點擊按鈕後要觸發的函數。
它主要做四件事:
1. 讀取 ent 中的內容
2. 調用 yf.py 中的 YahooFinanceHistory 類的 get_data 方法來獲得數據
3. 把數據儲存為 csv
4. 在 lbl 中顯示成功或失敗(通過修改 lbl 的屬性 text)
def download():
try:
code = ent.get()
df = yf.YahooFinanceHistory().get_data(code)
except:
lbl['text'] = ??? # 請自行完成
else:
df.to_csv(...) # 請自行完成
lbl['text'] = ??? # 請自行完成
繳交詳情和配分
Project 1 完成後請繳交以下檔案:
1. (40%)代碼檔案(yf.py 和 app.py)
2. (30%)說明文件(PDF格式):
i. 精簡,清晰,完整
ii. 介紹你撰寫的程序的目的和功能,使用方式,設計原理(python 模組、類,和
函數等)。
iii. 可用 markdown、Word,或 PowerPoint 等軟件但最後要轉換成 PDF
3. (30%且必須)程序運行情況的螢幕錄影(.mp4)一個:
i. 長度不多於1分鐘
ii. 影片應包含以下過程:啟動程序;輸入股票編號;點擊按鈕爬蟲;顯示成功;
同框目睹數據檔案的產生,並將之打開。
上傳時,不用把以上檔案打包成zip
Project 2 - 數據分析與可視化
目標
把 Project 1 所下載下來的60個交易日之數據,用 pandas 作簡單加工,再畫圖顯示。
步驟
1. 用 pandas 讀取 project 1 中下載得來的股價數據 csv,得到一 DataFrame。
2. 檢查有否數據異常,把各 column 轉為相應類型(datatime, float, integer, object, ...)
3. 把 DataFrame 的 index 轉為 Date
4. 用 DataFrame 的 rolling 方法計算 Adj Close 的 5, 10, 15 天移動平均值,分別建立
新 column 叫 ma5, ma10, ma15 紀錄
5. 建立 column 叫 pos,使當 ma5 數值大於ma10 數值的日子中,pos的數值取 1,
其餘日子中 pos 的數值取 0.
6. 把 Adj Close, ma5, ma10, ma15 全部畫在同一個圖中,並加上 title 說明股票編
號,然後把圖片儲存為 png。如下頁所示:
沒有提示
和 project 1 不同,project 2 為全自學模式。請同學自行找尋資料依上頁步驟完成題目。
閱讀材料可以找:
pandas 等相關的工具庫(還有其他工具庫需要用到嗎?請自行研究)的官方網頁和
說明文件。
各式搜尋引擎尋找網上的文章
Youtube 等視頻網站
本課程講義。
繳交詳情和配分
Project 2 完成後請繳交以下檔案:
1. (70%)代碼檔案一個:可以寫在 .py 或 .ipynb 中
2. (10%)數據檔案(.csv)一個
3. (10%)圖片檔案(.png)一個
4. (10%且必須)程序運行情況的螢幕錄影(.mp4)一個(不多於1分鐘長度):影片
應包含以下過程:
i. 在你的電腦上啟動程序
ii. 運行結束後,目睹png檔的產生,並將之打開。
上傳時,不用把以上檔案打包成zip。
繳交方式
1. 兩個 project 各自經 tronclass 繳交所有要求的檔案
2. 現場 USB 繳交。
注意:需分別交給本課程(BIT001計算機程式設計語言)以及BIT002設計計算工作室1的老師。詳情請向相關老師查詢