Python 初心者的第一個專案 − 登山共乘資訊整理

Python 學習紀錄

邱泊瑜
Dec 29, 2020

前言:

最近因為參加 ccClub 的 Python 課程,開始製作自己的第一個小專案「登山共乘趣」,專案目標是將網路上的共乘資料統整起來,並透過 LINE Bot 的介面,讓山友能夠透過日期去找到合適的共乘資訊。

而我個人負責的是 PTT Hiking 版的爬蟲、資料整理與寫入,讓後端能夠利用這些數據,回傳相對應的共乘資訊給使用者,而這篇文章將會分享我是如何透過 Python 爬蟲與整理資料格式!在開始前,先讓大家看看我們做出的成品!

專案製作發想

當初在思考如何讓使用者找到共乘資訊時,我們有考慮將登山口設定為一個搜尋參數,在實際蒐集共乘文章時,發現同一個山頭的共乘終點,會有很多不同的說法,像是去玉山的共乘,不同山友會寫成「塔塔加登山口」、「玉山」或「東埔山莊」等等。

在製作專案有時限的情況下,我們很難建出一個囊括所有同義詞的資料庫,最終,我們決定直接用日期作為主要搜尋方式,除了資料庫建置比較簡單外,也是考量到很多山頭的登山口,彼此就在附近,不一定要完全匹配的登山口才能一起共乘,反而時間搭得上更重要,例如要去爬雪山跟武陵四秀就可以配對共乘。

專案運作流程

專案製作步驟

  1. 爬蟲 Hiking 版的文章
  2. 再將文章標題包含「共乘」跟「揪人」的文章撈出來
  3. 從標題中擷取「出發時間」
  4. 寫入後端資料庫 ,再串接到 LINE Bot 上

第一步:網頁爬蟲

這個步驟我借助了 jwlin 大神寫的 ptt-web-crawler 套件操作,再進一步針對我不需要的欄位跟格式做修正。

套件設定的爬取內容,基本上涵蓋了整個 PTT 網頁的資訊,不過我們這次的專案並不需要所有資料,因此我修改相關程式碼,最終只爬取了Article_title、Author、Content、Date、URL 五個欄位。

初期目標是希望能直接將此套件當作函式庫使用,將資料爬蟲與整理放在同一個 Python 檔去執行,但實際操作時,發現這樣對於新手來說有點難 debug,因此最終版本,我們是將爬蟲檔跟資料整理檔分開執行。

下方為爬蟲下來的 Raw Data

未截圖到範圍還有 URL 和 Date (發佈日期)

第二步:資料篩選與整理

爬蟲下來的 JSON 格式包含了整份 Hiking 版的文章資訊,其中我們只需要「共乘」跟「揪人」主題,並不需要類別為「遊記」、「新聞」的文章。

要完成這樣的篩選方式,首先需要將導入的 JSON 檔轉換成 Dict ,才能讓我們只單純搜尋文章標題,接著透過正則表達式,找出標題欄位中,有包含「共乘」、「揪人」的文章,再將這些文章資訊導入到 filtered_list 當中。

2021/01/21 註記:最近在學習用 json 套件來讀檔,發現自己當時根本亂搞原始資料,基本上這邊的讀取檔案,跟各位直接用 ptt-crawler 的檔案,得到的各式有很大的不同,還請注意!

最終整理出來的文章標題,會如下圖所示。

篩選後的文章標題

接下來,就是要將這些在標題中提到的出發時間擷取出來,提供後續搜尋配對使用。

第三步:出發日期擷取

開始寫程式之前,我先研究了一下大部分的使用者,是如何書寫出發日期,可以發現主要格式為「數字+符號(./-)、空白+數字」,即便有年份或是多個天數,也脫離不了兩個數字夾著一個符號的形式,因此我利用正則表達式設計了三組不同的日期規則,來抓出在標題中的日期。

同時,為了避免沒有日期的標題讓迴圈產生錯誤,因此在三種日期規則都不符合時,我為 start_date 設其 default value 為 0,然後再將抓出來的日期統一用「-」來間隔。

舉例來說:

標題為 「[揪人] 2020/12/14 奇萊南華」的 Value ,會透過「rule2」,將 start_date 的值設定為「2020-12-14」

標題為 「[揪人] 12/17–12/18北大武共乘」的 Value ,會透過「rule1」,將 start_date 的值設定為「12–17–12–18」

第一次整理到這裡時,以為這樣的資料格式就能透過模糊搜尋法,讓 LINE Bot 匹配使用,但實際給後端使用後,隊友告知我說 LINE Bot 需要固定格式去匹配,不能一下有年份、一下又出現「12–14–15」這種字串, 沒辦法看成 12/14 和 12/15 去辨識,反而連「12–14」都沒辦法匹配到。為了解決這樣的問題,我需要將出發日期整理成「月/日」這種格式。

首先,將各個數字放進 List 當中,再進一步跑迴圈去判斷是否大於 31 ,這邊主要是先將年份剔除掉,因為不管是西元年或民國年,皆會大於 31 。

再來根據台灣人書寫日期的習慣,會將日期寫成「月/日」的格式,因此小於 31 的第一個數字,一定會是月份,第二個數字則會是日號。當 start_date 拿到兩個值以後,就跳出迴圈,讓每個 start_date 都會只有一個「月/日」的 Value。

第四步:將資料寫到資料庫

這裡的資料庫是隊友建好,讓我針對此 API 丟資料上去而已。

唯一要說明的就是,我現在還是必須每天更新資料,為了確保不會有重複的資料被 POST 上去,特別設定一個條件式,來偵測發文時間是不是當天。

最終到資料庫的數據如下所示:

以上就是我第一個 Python 專案的開發製作,雖然用了很多網路上現成的資源,但看著自己想要的成果,透過一行一行的程式碼跑出來的時候,那種感覺還是很棒阿!現在就是持續加強能力,讓自己在未來能完成更多有趣的作品!

最後補充關於這個專案,未來將進一步優化的方向:

  1. 爬取臉書上的共乘資訊,增加資料基數
  2. 將上山跟下山日期隔出來,讓使用者有兩個參數能找到相對應的共乘資訊
  3. 將爬蟲跟資料整理的程式包成一個 Package,並設定能夠定時自動更新

如果有任何建議或是想法,歡迎留言跟我說喔,謝謝!

--

--