Python 爬蟲實戰範例
使用 Selenium 抓取
鉅亨網 高年化配息債券型基金 Part2
提供給想學習 Python 爬蟲的朋友們,分享 Python 爬蟲的步驟與方法,並提供完整的程式碼,只要常透過不同主題的實戰練習,就可以駕輕就熟爬蟲技術,往後要抓取網頁資料,就能夠輕易上手
在上一篇文章【使用 Selenium 抓取鉅亨網 高年化配息債券型基金 Part1】提到如何使用 Selenium 和 BeautifulSoup 套件打造 Python 基金爬蟲程式,來抓取鉅亨網高年畫配息債券型基金,並將搜尋的結果抓取下來處存至檔案當中。
而在這一篇文章將續上一篇文章的內容,將篩選出來的基金更進一步取得各基金的細節資料,包含了管理費、成立日期、基金規模、風險評等、申購手續費、夏普值和表準差等資訊,未來只需要定期執行一次,就能夠透過爬蟲程式將所有基金資訊完整的整理在一份檔案當中,一目了然。
如果你還你還不知道網路爬蟲是什麼,可以先閱讀這一篇:認識網路爬蟲
我們將打造 Python 基金爬蟲程式 Part2,讀取上一篇文章產生的基金清單,在使用 Selenium 套件自動操作瀏覽器,抓取清單中各基金的細節資料,並將抓取下來的結果儲存至檔案當中
那我們開始吧!
本文中 Python 基金爬蟲實戰範例程式碼可以直接在 Google Drive 下載
第一步:讀取檔案
匯入所需的套件之後,首先要讀取上一篇文章產生出來的檔案,從中取得基金資料的連結
import time import pandas as pd from selenium import webdriver from bs4 import BeautifulSoup from datetime import datetime df = pd.read_csv('20210615_全球高收益債基金.csv') df
讀取之後可以看到 DataFrame 內容如下
再來就可以透過 for 迴圈,逐一讀取基金清單中各別連結,之後就可以連到網站中取得基金細節的資料
for index, row in df.iterrows(): print(row['連結'])
https://fund.cnyes.com/detail/NN%20(L)%20環球高收益基金X股對沖級別美元(月配息)/B33,173/report https://fund.cnyes.com/detail/NN%20(L)%20環球高收益基金X股美元(月配息)/B33,081/report https://fund.cnyes.com/detail/法巴全球高收益債券基金/月配(美元)避險/B06,298/report
第二部:檢視要抓取的資料
在抓取我們所需的內容前,要先了解要抓取資料的位置,包含了基金名稱、管理費、成立日期和基金規模
基金名稱:在class為 _1MTL 元素中的h1中
管理費:在第5個class為_3Zdyl的元素中
成立日期:在第6個class為_3Zdyl的元素中
基金規模:在第7個class為_3Zdyl的元素中
補充:通常要找到資料的位置,會先取得特定元素的清單,在從中找出特定的位置,就以_3Zdyl為例子,會使用程式使用 css selector 找出所有 class 為 _3Zdyl 的元素,再從中找出順位第幾的位置
了解要抓取資料的位置後,就可以到 Jupter Notebook 來實作
第三步:抓取管理費、成立日期與基金規模
先建立 Chrome driver 物件,executable_path 要丟入 chromedriver 位置,而【./】代表當前路徑,在這是將 chromedriver 放到與 Jupyter Notebook 相同的路徑,透過 for 迴圈來抓取各基金的資料
Step 1. 透過 driver.get(url=row[‘連結’]) 開啟連結
Step 2. 使用 BeautifulSoup 解析網頁
Step 3. 抓取基金的名稱,並判斷如果有資料的話才抓取其它資訊,不然就直接為 ‘ – ‘ 代表無資料
Step 4. print 出抓取的資料
Step 5. for 迴圈跑完之後,關閉瀏覽器
driver = webdriver.Chrome(executable_path='./chromedriver') for index, row in df.iterrows(): driver.get(url=row['連結']) fund_html_source = driver.page_source fund_soup = BeautifulSoup(fund_html_source, 'lxml') fund_name = fund_soup.select_one('._1MXTL h1').text # 基金名稱 if fund_name != '': management_fee = fund_soup.select('._3Zdyl')[4].text # 管理費 establish_date = fund_soup.select('._3Zdyl')[5].text # 成立日期 total_asset = fund_soup.select('._3Zdyl')[6].text # 基金規模 else: management_fee = '-' establish_date = '-' total_asset = '-' print(fund_name) print(management_fee) print(establish_date) print(total_asset) time.sleep(3) driver.close()
執行之後,就可以看到前兩個基金的管理費、成立日期和基金規模,但由於第三個基金資料的內容無法抓取成功 (網頁資料本身就沒有資料可以抓),所以就會直接顯示 ‘ – ‘。
NN (L) 環球高收益基金X股對沖級別美元(月配息) 1.50% 2014/11/19 19.3億 NN (L) 環球高收益基金X股美元(月配息) 1.50% 2011/05/02 19.3億 - - -
第四步:抓取更多基金資訊
接著要抓取其它頁面更多的基金資訊,需要先取得【基金檔案】的連結,再透過 driver.get(url) 前往頁面,並在新的頁面中找到所需資訊的元素位置,包含了ISIN、風險評等和申購手續費
ISIN:在第一個 table 中第八個 tr 的最後一個 td 中(HTML太長,所以沒有將標籤 tr 打開)
風險評等:在第一個 table 中第10個 tr 的第一個 td 中
申購手續費:在第二個 table 中第1個 tr 的最後一個 td 中
補充:tr 為 table row,td 則為 table data
為了簡化,將抓取管理費、成立日期、基金規模資料的程式碼先給省略掉,主要的步驟如下
Step 1. 透過 driver.get(url=row[‘連結’]) 開啟連結
Step 2. 使用 BeautifulSoup 解析網頁
Step 3. 抓取基金的名稱,並判斷如果有資料的話才繼續執行,不然就直接為 ‘ – ‘ 代表無資料
Step 4. 前往【基金檔案】頁面
Step 5. 抓取ISIN、風險評等和申購手續費
Step 6. print 出抓取的資料
Step 7. for 迴圈跑完之後,關閉瀏覽器
driver = webdriver.Chrome(executable_path='./chromedriver') for index, row in df.iterrows(): driver.get(url=row['連結']) fund_html_source = driver.page_source fund_soup = BeautifulSoup(fund_html_source, 'lxml') fund_name = fund_soup.select_one('._1MXTL h1').text # 基金名稱 if fund_name != '': # 抓取管理費、成立日期、基金規模 (程式碼省略) # ... # 前往基金基本資料 driver.get(url='https://fund.cnyes.com' + fund_soup.select('._1DBp3 a')[1]['href']) fund_document_source = driver.page_source fund_document_soup = BeautifulSoup(fund_document_source, 'lxml') isin = fund_document_soup.select('table')[0].select('tr')[7].select('td')[-1].text # ISIN risk_return = fund_document_soup.select('table')[0].select('tr')[9].select('td')[0].text # 風險評等 purchase_fee = fund_document_soup.select('table')[1].select('tr')[0].select('td')[-1].text # 申購手續費 else: # 設定管理費、成立日期、基金規模 (程式碼省略) # ... isin = '-' risk_return = '-' purchase_fee = '-' print(fund_name) print(isin) print(risk_return) print(purchase_fee) time.sleep(3) driver.close()
執行之後,就可以看到前兩個基金的ISIN、風險評等和申購手續費,但由於第三個基金資料的內容無法抓取成功 (網頁資料本身就沒有資料可以抓),所以就會直接顯示 ‘ – ‘。
NN (L) 環球高收益基金X股對沖級別美元(月配息) LU1121988494 RR3 5% NN (L) 環球高收益基金X股美元(月配息) LU0555026847 RR3 5% - - -
第五步:抓取風險評等資料
接著要抓取風險指標的數據,需要先取得【風險評等】頁面的連結,再透過 driver.get(url) 前往頁面,並在新的頁面中找到所需資訊的元素位置,包含了夏普值、Beta值和標準差,而要抓取的指標以3年為主。
夏普值:在擁有class為_MY0Rz的 table 中第二個 tr 的第二個 td 中
Beta值 :在擁有class為_MY0Rz的 table 中第三個 tr 的第二個 td 中
標準差:在擁有class為_MY0Rz的 table 中第五個 tr 的第二個 td 中
為了簡化,將抓取管理費、成立日期、基金規模、ISIN、風險評等、申購手續費資料的程式碼先給省略掉,主要的步驟如下
Step 1. 透過 driver.get(url=row[‘連結’]) 開啟連結
Step 2. 使用 BeautifulSoup 解析網頁
Step 3. 抓取基金的名稱,並判斷如果有資料的話才繼續執行,不然就直接為 ‘ – ‘ 代表無資料
Step 4. 前往【風險評等】頁面
Step 5. 抓取夏普值、Beta值和標準差
Step 6. print 出抓取的資料
Step 7. for 迴圈跑完之後,關閉瀏覽器
driver = webdriver.Chrome(executable_path='./chromedriver') for index, row in df.iterrows(): driver.get(url=row['連結']) fund_html_source = driver.page_source fund_soup = BeautifulSoup(fund_html_source, 'lxml') fund_name = fund_soup.select_one('._1MXTL h1').text # 基金名稱 if fund_name != '': # 抓取管理費、成立日期、基金規模、ISIN、風險評等、申購手續費 (程式碼省略) # ... # 前往風險評等 driver.get(url='https://fund.cnyes.com' + fund_soup.select('._1DBp3 a')[3]['href']) fund_risk_source = driver.page_source fund_risk_soup = BeautifulSoup(fund_risk_source, 'lxml') sharpe = fund_risk_soup.select('table._MY0Rz')[0].select('tr')[1].select('td')[1].text # 夏普值 beta = fund_risk_soup.select('table._MY0Rz')[0].select('tr')[2].select('td')[1].text # Beta值 sd = fund_risk_soup.select('table._MY0Rz')[0].select('tr')[4].select('td')[1].text # 標準差 else: # 設定管理費、成立日期、基金規模、ISIN、風險評等、申購手續費 (程式碼省略) # ... sharpe = '-' beta = '-' sd = '-' print(fund_name) print(sharpe) print(beta) print(sd) time.sleep(3) driver.close()
執行之後,就可以看到前兩個基金的夏普值 、Beta值和標準差 ,但由於第三個基金資料的內容無法抓取成功 (網頁資料本身就沒有資料可以抓),所以就會直接顯示 ‘ – ‘。
NN (L) 環球高收益基金X股對沖級別美元(月配息) 0.45 0.97 10.01% NN (L) 環球高收益基金X股美元(月配息) 0.42 1.06 10.79% - - -
第六步:整理基金資料至Dataframe中
在最前面替各個基金資料建立 List 清單,用來暫存資料,在 for 迴圈中,將抓取的資料,使用 append 加入至各個清單中,最後當跑完 for 迴圈後,再全部加入至 DataFrame 當中,並設定【基金名稱】為索引 index,其中 inplace=True 代表不建立新的 DataFrame 物件,直接對本身 DataFrame 物件進行修改
management_fee_list = [] establish_date_list = [] total_asset_list = [] isin_list = [] risk_return_list = [] purchase_fee_list = [] sharpe_list = [] beta_list = [] sd_list = [] driver = webdriver.Chrome(executable_path='./chromedriver') for index, row in df.iterrows(): # 抓取管理費、成立日期、基金規模、ISIN、風險評等、申購手續費、夏普值、Beta值、標準差(程式碼省略) # ... management_fee_list.append(management_fee) # 管理費 establish_date_list.append(establish_date) # 成立日期 total_asset_list.append(total_asset) # 基金規模 isin_list.append(isin) # ISIN risk_return_list.append(risk_return) # 風險評等 purchase_fee_list.append(purchase_fee) # 申購手續費 sharpe_list.append(sharpe) # 夏普值 beta_list.append(beta) # Beta值 sd_list.append(sd) # 標準差 time.sleep(3) driver.close() df['管理費'] = management_fee_list df['成立日期'] = establish_date_list df['基金規模'] = total_asset_list df['ISIN'] = isin_list df['風險評等'] = risk_return_list df['申購手續費'] = purchase_fee_list df['夏普值'] = sharpe_list df['Beta值'] = beta_list df['標準差'] = sd_list df.set_index('基金名稱', inplace=True) df
跑完 for 迴圈後,最後 DataFrame中的資料將會如下
第七步:儲存資料
最後在使用 DataFrame 的 to_csv 方法,並丟入要建立的檔案名稱,就可以直接將整理好的 DataFrame 表格寫入 csv 檔案中 (新建立的檔案會在 Jupyter Notebook 相同的路經中找到),而為了避免儲存之後中文出現亂碼需加上帶入 encoding=’utf_8_sig’
date = datetime.today().strftime("%Y%m%d") file_name = '{}_全球高收益債基金v2.csv'.format(date) df.to_csv(file_name, encoding='utf_8_sig')
執行上方程式碼之後,就可以在 Jupyter Notebook 相同路徑中看到 csv 檔案,內容就是在鉅亨網中前幾名的高年化配息債券型基金資料包含了各基金的基本概況與風險評等資訊
以上就是使用 Selenium 抓取鉅亨網高年化配息債券型基金的 Python 基金爬蟲實作範例 Part 2;以下可以看到完整的程式碼,也可以直接下載 Jupyter Notebook 基金爬蟲程式碼檔案。
結語
現今已經有很多的工具與套件(像是本文中提到的 Selenium、BeautifulSoup 與 Pandas)能夠快速的開發適合自己需求的網路爬蟲工具,而 Python 非常最適合寫爬蟲,程式看起來很清楚、優雅、可以快速入門,而且只需要有些 Python 程式語言的基礎,透過實作範例練習,就能夠開發出網路爬蟲工具
之後我們會再陸續出其它 Python 網路爬蟲主題實作,可以訂閱我們,當推出新的文章時,我們將會把第一首消息通知給你喔,如果你有其他問題,或是想要我們推出什麼樣的爬蟲實作,可以直接寄信至 webscrapingpro.tw@gmail.com 聯絡我們喔
正在尋找網路爬蟲線上課程?
如果你在找一個有系統教學的網路爬蟲課程,我們有開一門完整的 Python 網路爬蟲課程,從 Python 程式語言入門開始到網路爬蟲套件教學,最後以股票數據、 金融資訊和財經新聞為主題做實務範例練習,教你如何在這資訊爆炸的時代中,有效率的抓取、整理和分析所需要的資料