為了能夠自動化蒐集網頁上的資料,通常都會利用Python網頁爬蟲來幫忙完成,而蒐集到的資料如果想要進行排序、群組或篩選的動作,就需要花費不少的功夫來達成。
這時候,就能夠整合Pandas資料分析套件,將爬取的資料存入DataFrame資料結構,使用它所提供的方法,即可輕鬆操作其中的資料,除了提升處理資料的效率,也能夠讓程式碼更加簡潔。
所以,本文以Accupass活動通網站為例,來和大家分享如何將Python網頁爬蟲取得的資料,存入Pandas DataFrame,進而有效的操作資料。開發流程如下:
- 分析Accupass活動通網頁
- 安裝相關套件
- 開發Python網頁爬蟲
- 存入Pandas DataFrame
- 篩選Pandas DataFrame資料
- 排序Pandas DataFrame資料
- 匯出Pandas DataFrame資料到Excel
一、分析Accupass活動通網頁
Accupass活動通網站包含了各式各樣的活動資訊,能夠在上面舉辦、尋找及報名活動,首頁如下圖:
而本文想要來蒐集有關Python活動的名稱以及相應的觀看人數、喜歡人數及售票狀態。在右上角搜尋的地方輸入「Python」關鍵字後,可以查詢到如下圖的結果:
接下來,就可以在這四個部份點擊右鍵,選擇「檢查」來觀察HTML原始碼,如下圖:
二、安裝相關套件
網頁分析完成後,就可以利用下面的指令來安裝開發所需的套件:
$ pip install selenium $ pip install webdriver-manager #瀏覽器驅動管理套件 $ pip install beautifulsoup4 $ pip install lxml #HTML解析器 $ pip install pandas $ pip install openpyxl
Accupass活動通是一個動態載入資料的網站,畫面上的資料都是從後端來進行綁定,所以點擊右鍵,選擇「檢視網頁原始碼」時,是找不到畫面上所顯示的活動資訊的,這時候就需要Selenium套件來開發Python動態網頁爬蟲,而openpyxl則是在利用Pandas DataFrame匯出Excel檔時所需要的相依性套件。
三、開發Python網頁爬蟲
套件安裝完成後,本文以Visual Studio Code為例,建立scraper.py檔案,並且引用以下的模組:
from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup import pandas as pd
接著,就可以利用Selenium套件開啟Chrome瀏覽器,並且請求(Request)Accupass活動通的Python活動網址,如下範例:
from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup import pandas as pd browser = webdriver.Chrome(ChromeDriverManager().install()) #安裝Chrome驅動程式及建立Chrome物件 browser.get("https://old.accupass.com/search/r/0/0/0/0/4/0/00010101/99991231?q=python")
開啟Python活動的網頁後,就可以將Selenium模組所取得的網頁原始碼內容,傳入BeautifulSoup模組來進行解析,如下範例:
from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup import pandas as pd browser = webdriver.Chrome(ChromeDriverManager().install()) #安裝Chrome驅動程式及建立Chrome物件 browser.get("https://old.accupass.com/search/r/0/0/0/0/4/0/00010101/99991231?q=python") soup = BeautifulSoup(browser.page_source, "lxml")
解析後,就能夠利用BeautifulSoup模組的find_all()方法(Method),來取得網頁上所有的活動資訊卡片(Card),如下範例:
from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup import pandas as pd browser = webdriver.Chrome(ChromeDriverManager().install()) #安裝Chrome驅動程式及建立Chrome物件 browser.get("https://old.accupass.com/search/r/0/0/0/0/4/0/00010101/99991231?q=python") soup = BeautifulSoup(browser.page_source, "lxml") activities = soup.find_all("div", {"class": "apcss-activity-card ng-isolate-scope"})
接下來,透過迴圈讀取活動資訊卡片(Card)中的內容,爬取活動名稱、觀看人數、喜歡人數及售票狀態,如下範例:
from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup import pandas as pd browser = webdriver.Chrome(ChromeDriverManager().install()) #安裝Chrome驅動程式及建立Chrome物件 browser.get("https://old.accupass.com/search/r/0/0/0/0/4/0/00010101/99991231?q=python") soup = BeautifulSoup(browser.page_source, "lxml") activities = soup.find_all("div", {"class": "apcss-activity-card ng-isolate-scope"}) for activity in activities: #活動名稱 title = activity.find("h3", {"class": "apcss-activity-card-title ng-binding"}).getText().strip() #觀看人數 view = activity.find("span", {"class": "apcss-activity-pageview ng-binding"}).getText().strip() #喜歡人數(去除其中的中文字) like = activity.find("span", {"class": "apcss-activity-card-like ng-binding"}).getText().strip().replace(" 人喜歡", "") #售票狀態 status = activity.find("a", {"class": "apcss-btn apcss-btn-block ng-binding activity-card-status-ready"}) #如果售票狀態為已完售,則爬取另一個樣式類別(class) if status == None: status = activity.find("a", {"class": "apcss-btn apcss-btn-block ng-binding activity-card-status-end"})
由於售票狀態按鈕的「熱銷中」及「已完售」是套用不一樣的樣式類別(class),所以在第28行判斷如果爬取不到內容,也就代表為「已完售」,則爬取「已完售」的樣式類別(class)。
而要將Python網頁爬蟲所取得的資料存入Pandas DataFrame中,就需要將每筆資料打包為一個元組(Tuple),並且加入到串列(List)中,才有辦法用來建立Pandas DataFrame物件,如下範例第13、32行:
from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup import pandas as pd browser = webdriver.Chrome(ChromeDriverManager().install()) #安裝Chrome驅動程式及建立Chrome物件 browser.get("https://old.accupass.com/search/r/0/0/0/0/4/0/00010101/99991231?q=python") soup = BeautifulSoup(browser.page_source, "lxml") activities = soup.find_all("div", {"class": "apcss-activity-card ng-isolate-scope"}) result = [] for activity in activities: #活動名稱 title = activity.find("h3", {"class": "apcss-activity-card-title ng-binding"}).getText().strip() #觀看人數 view = activity.find("span", {"class": "apcss-activity-pageview ng-binding"}).getText().strip() #喜歡人數(去除其中的中文字) like = activity.find("span", {"class": "apcss-activity-card-like ng-binding"}).getText().strip().replace(" 人喜歡", "") #售票狀態 status = activity.find("a", {"class": "apcss-btn apcss-btn-block ng-binding activity-card-status-ready"}) #如果售票狀態為已完售,則爬取另一個樣式類別(class) if status == None: status = activity.find("a", {"class": "apcss-btn apcss-btn-block ng-binding activity-card-status-end"}) result.append((title, int(view), int(like), status.getText())) print(result) browser.quit() #關閉Chrome瀏覽器
執行結果
[ ('【FREE】《達內教育》12月平日Python & Java趨勢講座-台北場-學好人工智慧必備語言Python跟上未來趨勢-免費參加', 18, 0, '熱銷中'), ('一天上手!Python網頁爬蟲實戰', 74, 2, '熱銷中'), ('【FREE】《達內教育》12月假日Python & Java趨勢講座-台北場-學好人工智慧必備語言Python跟上未來趨勢-免費參加', 6, 0, '熱銷中'), ('🔥【 Python資料分析與機器學習實戰】🔥關鍵數據資料分析應用,打贏5G大數據應用戰! 11/7開課', 348, 10, '熱銷中'), ('非同步 PYTHON 爬蟲實作 & 部署在 heroku|學程式主題小聚 Mike', 242, 4, '熱銷中'), ('智慧機械-Python 應用實作進階班', 166, 4, '熱銷中'), ('Python程式設計入門班', 298, 11, '熱銷中'), ('【國高中證照營】PYTHON核心能力-微軟MTA國際認證營|第一張程式證照入門必備,原場地即測即評', 59, 4, '熱銷中'), ('第三屆《用 Python 打造你的 AI 股票交易引擎》業界專家實戰教學', 187, 11, '熱銷中'), ('【FREE】《達內教育》11月假日Python & Java趨勢說明會-台北場-學好人工智慧必備語言Python跟上未來趨勢-免費參加', 32, 3, '已完售'), ('Python課程線上學習平台|YouTube免費試聽', 215, 16, '已完售'), ('智慧機械-python程式設計基礎班', 218, 5, '已完售') ]
這邊要特別注意的是,數字類型的資料如果未來會進行排序使用,就要進行轉型的動作,如以上範例的第32行,將「觀看人數」及「喜歡人數」轉型為整數(Integer)。
四、存入Pandas DataFrame
接下來,就可以建立Pandas DataFrame物件,存放Python網頁爬蟲所取得的資料,如下範例第35行:
from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup import pandas as pd browser = webdriver.Chrome(ChromeDriverManager().install()) #安裝Chrome驅動程式及建立Chrome物件 browser.get("https://old.accupass.com/search/r/0/0/0/0/4/0/00010101/99991231?q=python") soup = BeautifulSoup(browser.page_source, "lxml") activities = soup.find_all("div", {"class": "apcss-activity-card ng-isolate-scope"}) result = [] for activity in activities: #活動名稱 title = activity.find("h3", {"class": "apcss-activity-card-title ng-binding"}).getText().strip() #觀看人數 view = activity.find("span", {"class": "apcss-activity-pageview ng-binding"}).getText().strip() #喜歡人數(去除其中的中文字) like = activity.find("span", {"class": "apcss-activity-card-like ng-binding"}).getText().strip().replace(" 人喜歡", "") #售票狀態 status = activity.find("a", {"class": "apcss-btn apcss-btn-block ng-binding activity-card-status-ready"}) #如果售票狀態為已完售,則爬取另一個樣式類別(class) if status == None: status = activity.find("a", {"class": "apcss-btn apcss-btn-block ng-binding activity-card-status-end"}) result.append((title, int(view), int(like), status.getText())) df = pd.DataFrame(result, columns=["活動名稱", "觀看人數", "喜歡人數", "售票狀態"]) print(df) browser.quit() #關閉Chrome瀏覽器
執行結果
五、篩選Pandas DataFrame資料
將Python網頁爬蟲取得的資料存入Pandas DataFrame後,想要進行各種的資料處理,就非常的方便了,舉例來說,想要篩選出「熱銷中」的活動,可以利用以下範例的第37行語法:
from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup import pandas as pd browser = webdriver.Chrome(ChromeDriverManager().install()) #安裝Chrome驅動程式及建立Chrome物件 browser.get("https://old.accupass.com/search/r/0/0/0/0/4/0/00010101/99991231?q=python") soup = BeautifulSoup(browser.page_source, "lxml") activities = soup.find_all("div", {"class": "apcss-activity-card ng-isolate-scope"}) result = [] for activity in activities: #活動名稱 title = activity.find("h3", {"class": "apcss-activity-card-title ng-binding"}).getText().strip() #觀看人數 view = activity.find("span", {"class": "apcss-activity-pageview ng-binding"}).getText().strip() #喜歡人數(去除其中的中文字) like = activity.find("span", {"class": "apcss-activity-card-like ng-binding"}).getText().strip().replace(" 人喜歡", "") #售票狀態 status = activity.find("a", {"class": "apcss-btn apcss-btn-block ng-binding activity-card-status-ready"}) #如果售票狀態為已完售,則爬取另一個樣式類別(class) if status == None: status = activity.find("a", {"class": "apcss-btn apcss-btn-block ng-binding activity-card-status-end"}) result.append((title, int(view), int(like), status.getText())) df = pd.DataFrame(result, columns=["活動名稱", "觀看人數", "喜歡人數", "售票狀態"]) new_df = df[df["售票狀態"] == "熱銷中"] #篩選資料 print(new_df) browser.quit() #關閉Chrome瀏覽器
執行結果
六、排序Pandas DataFrame資料
而另一個最常見的資料操作就是排序,這時候就可以透過Pandas DataFrame的sort_value()方法(Method),來排序Python網頁爬蟲取得的資料,如下範例第39行:
from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup import pandas as pd browser = webdriver.Chrome(ChromeDriverManager().install()) #安裝Chrome驅動程式及建立Chrome物件 browser.get("https://old.accupass.com/search/r/0/0/0/0/4/0/00010101/99991231?q=python") soup = BeautifulSoup(browser.page_source, "lxml") activities = soup.find_all("div", {"class": "apcss-activity-card ng-isolate-scope"}) result = [] for activity in activities: #活動名稱 title = activity.find("h3", {"class": "apcss-activity-card-title ng-binding"}).getText().strip() #觀看人數 view = activity.find("span", {"class": "apcss-activity-pageview ng-binding"}).getText().strip() #喜歡人數(去除其中的中文字) like = activity.find("span", {"class": "apcss-activity-card-like ng-binding"}).getText().strip().replace(" 人喜歡", "") #售票狀態 status = activity.find("a", {"class": "apcss-btn apcss-btn-block ng-binding activity-card-status-ready"}) #如果售票狀態為已完售,則爬取另一個樣式類別(class) if status == None: status = activity.find("a", {"class": "apcss-btn apcss-btn-block ng-binding activity-card-status-end"}) result.append((title, int(view), int(like), status.getText())) df = pd.DataFrame(result, columns=["活動名稱", "觀看人數", "喜歡人數", "售票狀態"]) new_df = df[df["售票狀態"] == "熱銷中"] #篩選資料 sort_df = new_df.sort_values(["觀看人數"], ascending=False) #依據觀看人數來遞減排序 print(sort_df) browser.quit() #關閉Chrome瀏覽器
執行結果
七、匯出Pandas DataFrame資料到Excel
最後,如果想要將Python網頁爬蟲取得的資料匯出至Excel檔案,則可以利用Pandas DataFrame的to_excel方法(Method)來達成,如下範例第41行:
from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup import pandas as pd browser = webdriver.Chrome(ChromeDriverManager().install()) #安裝Chrome驅動程式及建立Chrome物件 browser.get("https://old.accupass.com/search/r/0/0/0/0/4/0/00010101/99991231?q=python") soup = BeautifulSoup(browser.page_source, "lxml") activities = soup.find_all("div", {"class": "apcss-activity-card ng-isolate-scope"}) result = [] for activity in activities: #活動名稱 title = activity.find("h3", {"class": "apcss-activity-card-title ng-binding"}).getText().strip() #觀看人數 view = activity.find("span", {"class": "apcss-activity-pageview ng-binding"}).getText().strip() #喜歡人數(去除其中的中文字) like = activity.find("span", {"class": "apcss-activity-card-like ng-binding"}).getText().strip().replace(" 人喜歡", "") #售票狀態 status = activity.find("a", {"class": "apcss-btn apcss-btn-block ng-binding activity-card-status-ready"}) #如果售票狀態為已完售,則爬取另一個樣式類別(class) if status == None: status = activity.find("a", {"class": "apcss-btn apcss-btn-block ng-binding activity-card-status-end"}) result.append((title, int(view), int(like), status.getText())) df = pd.DataFrame(result, columns=["活動名稱", "觀看人數", "喜歡人數", "售票狀態"]) new_df = df[df["售票狀態"] == "熱銷中"] #篩選資料 sort_df = new_df.sort_values(["觀看人數"], ascending=False) #依據觀看人數來遞減排序 sort_df.to_excel("accupass.xlsx", sheet_name="activities", index=False) # 匯出Excel檔案(不寫入資料索引值) browser.quit() #關閉Chrome瀏覽器
執行結果
八、小結
一般情況下,使用Python網頁爬蟲來爬取網頁時,如果該網站沒有提供相關的排序或篩選功能,想要在爬取下來的資料中進行資料操作,像是本文所提到的篩選、排序及匯出Excel檔案,都需要額外撰寫非常多的程式碼來處理,而整合Pandas套件強大的資料處理功能後,就能夠輕鬆的進行許多資料操作及分析,也讓程式碼更加簡潔,大家不妨找一個網站來實作看看吧。
留言
張貼留言