前往
大廳
主題

【Electron + React】巴哈瀑布流 - Side Project 開發筆記

燐火幽冥 | 2022-11-15 12:12:22 | 巴幣 1146 | 人氣 1260

巴哈瀑布流 - Side Project 開發筆記


無廣告 · 不收集資料 · 完全開源

本文將會把怎麼建構巴哈瀑布流、所有遇到的問題毫不保留全部紀錄,之後也會發布至iT邦幫忙


  • Side Project 主題發想
之前非本科菜雞如我,用 React 做了個失智列車網站,就去投了兩個前端實習
(講白了整個作品集裡算得上個人前端個人作品的只有一個,星塵之路官網甚至沒有RWD)
結果沒一家鳥我,連電郵前測都沒收到,雖然感覺跟那封自殺一樣的求職信脫不了關係

確實,現在前端職缺多,競爭者也多,我這種條件肯定被其他做了更多作品的人輕鬆擠下去
......仔細想想還蠻令人焦慮的耶
我也只能多做作品,不然非本科系又沒去上坊間知名培訓班,人家老闆也想不到一個錄取我的理由吧

我在投履歷之前有先去問一些前端群組的人:

嗯...... 串api是吧! 我不會
咳咳,因為投履歷被當空氣,所以我決定下一個作品必須要跟抓資料有關

這一次 Side Project 主題發想有比較認真 至少比失智列車網站認真
先上概念發想圖:

原本是想串政府開放資料的 api,翻了很久看哪個有興趣,最後找到一個「集會遊行資訊」
欸唷?好像有料喔?
我興致勃勃地 做了一張跟上面一樣的圖表(沒錯,這張圖是第二版了),正準備要動工時-
發現這個「集會遊行資訊 api」 竟然不包含集會遊行的主題

......??? 你這資料等於是廢了吧...

不知道是政府很怕還是出於什麼傻逼原因,連主題都不知道的集會遊行查詢網站沒有存在的意義啊!
於是只能整個構想打掉重來,這邊我是有點小崩潰的,我也不想再翻那破爛資料平台了
所以選擇了方案二:巴哈

我知道網路上好像有一個 用 Go 語言寫的巴哈 api
但因為我不確定那個還能不能用,而且我也看不懂他的Ducument,所以我想說能不能自己爬蟲
就我淺薄的見識所知,爬蟲好像都是用Python,但我的加拿大好朋友小哈片刻說 JS 也可以爬
所以我上網查了一下資料,意外地發現了這篇文章!


這篇文章讓我對於這個 Side Project 的可行性信心大增,因為確實有人成功將巴哈場外重新排版
雖然我點進去看,那個專案的Github儲存庫不知為何已經被揚了


  • 快速開始 - Electron React Boilerplate(TypeScript)
之所以決定在這個專案導入 Electron 並實戰學習

是因為我在那篇 ptt排版巴哈文章 看到了一個關於「CROS」的問題
爬蟲大概也是會被擋掉吧?我實在不太想冒著做了一般的網頁卻發現沒辦法爬蟲的風險

再者是我從赫赫有名的 2022 前端工程師路線圖 中,發現 Electron 晉升為紫色勾勾
如果我想當前端工程師,能先接觸到紫勾的東西應該還不錯吧!
而且我上一個作品也是 React,如果下一個 Side Project 沒點新花樣,有點像是在原地打轉

我使用了「Electron React Boilerplate」這個模版
它直接幫你把 Electron + React 這件事打點好,把兩者結合開發的前置作業處理得七七八八了

  • Electron
Electron 是一個將 JavaScript、HTML 與 CSS 等網頁技術轉換為桌面應用程式的框架
我查了一下後發現 VSCode 就是用 Electron 寫的?!! 好喔,那怎能不來摸一下
簡單地說,可以想成它就是個包著瀏覽器的應用程式,能讓你寫的網頁在裡面呈現

如果要打開一個我寫的網頁,就要先新增一個 BrowserWindow 在裡面設定長寬、icon等
然後 .loadURL(resolveHtmlPath('index.html')); 這也能輸入網址用來打開某個網站的頁面

  • Node.js
Node.js 主要用來讓桌面應用程式與電腦系統進行溝通
它並非是一個程式語言,只是能夠讓你寫 JavaScript 然後在電腦上跑
可以把 Node.js 想成「能在後端運作的 JavaScript」,剩下的我其實也了解得不深入
Electron的主進程就是在運行 Node.js

  • Husky
Husky 是 Electron React Boilerplate 大禮包裡面的本來就有的
我也不太確定為什麼要加這個料,查了一下這個哈士奇說是跟 Git 有關的工具
它好像能自訂一些 Git 功能,比方說提交一個新版本之前先執行一些 npm 指令之類的
總之我是用不到,但也怕隨意刪除後對大禮包的運作造成什麼影響

會特別提到它是因為我發現, Husky 讓我沒有辦法再使用 GUI 操作 Git
沒錯,不管是 VSCode 還是 GitHub Desktop 那邊都不行了
我必須在終端機手打指令 git commit -am "xxxxx" --no-verify 才能提交新版本,真是謝了


  • CSS框架與響應式 - Tailwind
我之前的幾個專案其實沒有注重 RWD 這件事,包括星塵之路官網、失智列車網站
都是巴友提醒,或直接縮放視窗把排版整個玩壞了截圖傳給我看,我才驚覺其重要性
不過搞 media query 真的很痛苦,於是我決定去學習CSS的框架

  • Tailwind 是什麼?NB的嗎?
屬實NB,我現在是 TailwindCSS 的狗了

一切盡在不言中,汪汪

幽冥:這就是... 我的正確答案吧......

笑死,我是真的花了非常多時間在拉CSS百葉窗,已經快要受不了了

  • module.exports通靈 & plugins 設定
安裝 Tailwind 之後還有一些前置作業要做
首要便是去 tailwind.config.js 把 Tailwind 會作用在哪些文件上給設定好

其實在學校用筆電做的時候,Tailwind 有在沒設定的元件上作用,所以我一直覺得設定檔沒漏寫
git 推到雲端,回家下載進度後突然就出問題了
在那之前你明明一直有幫我通靈的,難道是為了我,一整天下來,力量已經消耗殆盡了嗎...?
Tailwind  我的超人

另外我有安裝一些官方推薦的小插件,像是:@tailwindcss/line-clamp
這是一個可以自訂文本在固定行數後截斷的實用小工具

  • 闇黑模式 & localStorage
Tailwind 除了做 RWD 很方便之外,其中還有讓你做闇黑模式超級方便的好處
只要把各個 Element 闇黑模式(dark:)的顏色樣式都加上,然後在最頂層上個 dark class
搭啷!闇黑模式製作完成!! 是不是很省事?
記得要去 tailwind.config.js 設定 「darkMode: 'class',」,不然是沒有用的喔

由於開關是用元件的State判斷,而我不能讓使用者重整(觸發元件 re-render)後就丟失設定
這個時候可以使用 localStorage ,這玩意就算你應用程式關掉重開,也能記住一些資料
利用它來做闇黑模式和按鈕狀態的設定記憶

詳細原始碼可以看我 Github 開源儲存庫的 setting Component 和 App Component
不過這部分牽扯到 Hook,闇黑模式我是最後才做,往後一些的標題我會說一個蠻重要的 Hook 應用

另外我知道闇黑模式之下,有些本來就被原作者設定文字樣式的文本,會顯得難以閱讀
這就要說到巴哈的文字編輯器:你幫文字加了三種樣式,它就有三層無名DIV,每一種樣式一個效果
就算我在內文有預設的文字顏色,也會被覆蓋,除非要去分析這些顏色之類的,不過這樣搞太複雜
而且有時候寫的人是故意這樣藏文字,不如就算了,這我真的舉雙手投降


  • 巴哈場外休憩區B頁爬蟲 - 文章瀑布流
應該不少場外老巴友都知道,巴哈場外有分成B頁和C頁
B頁是標題列表,也就是你各位整天縮在電腦前瘋狂刷新的宅宅小世界

我自己滑場外是比較常用列表樣式,但縮圖樣式顯示的資訊會比較多
瀑布流的文章塊資料主要就是從縮圖排版抓的
接下來要說的是 JS 怎麼做到把別站的內容爬到自己這邊來

  • Axios & Cheerio(去置頂 / 去廣告)
AJAX == Asynchronous JavaScript and XML
它是 JS 非同步請求的技術 :
我跟和伺服器要了資料後,不需要等待結果,程式仍然繼續做其他事,對面把結果傳回來給我之後,就放進當下頁面裡

Axios 是一個實現非同步請求的套件,這是構成專案最重要的一部份,沒有它我拿不到巴哈的HTML

當然,用爬HTML的方式來實現巴哈瀑布流也有一個非常致命的缺點
就是當巴哈官方又在更新些有的沒的時,原站的HTML結構若是改動,可能我這邊也得修改
甚至最慘會出現前功盡棄,需要重新分析編寫架構的狀況

Cheerio 則是一個參照 Jquery 設計的套件,它們 API 極其相似,但 Cheerio 並不代表 Jquery
簡單地說:Cheerio 能做很多 Jquery 能做的事情,但 Jquery 能做的事情 Cheerio 並不一定都能做

現在我們來爬蟲:(這張截圖是很早期的開發畫面,現在改了很多,但已經足夠表示)

眾所周知,巴哈把廣告塞在文章列表裡面,所以爬蟲一定會爬到:

列表總共30篇文章,爬回的總數卻是31,然後第10個元素一定是空陣列
這是什麼? 是 Sega 的 money 阿

那麼...怎麼把 站長的生財工具 廣告給去掉呢? ──── Cheerio!
除了廣告之外,我們也該把置頂文章給去掉,畢竟不會有人想到重複看到特定文章:

這段什麼意思?
「如果標題不是空的(廣告)、如果沒有置頂標籤(板務文)、如果沒有精華標籤(精華+板務文),
那麼就爬回來我這邊。」

這是一個很基礎的資料篩選,你要什麼、不要什麼,都可以這樣子搞定


  • chcp 65001
有沒有發現上面那張截圖,底下終端機印出來的東西都是亂碼?

阿,這個搞得我很崩潰,因為我很確定爬到的都是對的資料,最後發現是文字編碼設定問題
去 package.json 加入 "start": "chcp 65001" ,就會正常顯示中文字了
chcp 是 windows cmd 的指令,65001 則是指示 cmd 換成中文顯示環境

  • React Hook & 為什麼棄用 Class Component
React 元件分成兩種:Class Component 與 Function Component
事情是這樣的:原本只有 Function Component ,但大家非常需要的一個功能「State」隨著 Class Component 問世了,於是開發者們紛紛把專案轉成編寫 Class Component

就在大家覺得情況大致底定了之後,事情又有了變化:
官方發布了新的功能「Hook」,讓你不必寫 Class Component 就能使用 state 以及其他 React 的功能
然後他們宣布 Hook 只能在 Function Component 裡面用

......整人? 已經用 Class Component 寫了87%的大專案,是不可能給他這樣瞎折騰
React 也可能發現這操作造成不少疑問,特別發布了一篇 Q&A
他們的論調是說:希望大家以後開發新專案的時候,再改成使用 Function Component

Function Component 寫法少很多,可讀性比較高
在 React Hook 問世之後,兩者有了相同的功能,Function Component 卻在程式碼可讀性上勝出
只能說 Hook 出現得太晚,給開發者一種被整的感覺,一個歷史債的概念
我應該是不會回去用 Class Component 了,相信 Function Component 也會回歸主流寫法


  • 巴哈場外休憩區C頁爬蟲 - 樓層內文顯示
接下來是C頁的內容,也是閱覽器的重點,畢竟大家不是看看標題就飽了對吧?
我是先做顯示文章的主樓,再加入顯示主樓留言區的功能,最後再將所有樓層的顯示做出來,以及換頁

  • 把 Function 當 Props 在傳
這招是小哈教我的,失智列車網站也有應用,而在這個 Side Project 則是頻繁用到
設定 Hook 的 State ,必定是利用 setState 這個函式
嗯?那如果我們把函式當作某個子元件的 Props ,把它傳進去,然後在子元件內觸發呢?
也就是說,我可以做到在子元件內判斷要不要改變父元件的狀態

具體是在哪些地方用到? 比如說:頁面開關

ArticleBlock 有個 Props 「setOpen」、「Set_ArticleData
就是用來放入父元件 App 設定狀態所使用的 setOpenArticleBoolsetDisplay_article 函式
當某個 ArticleBlock 被點擊時,ArticleBlock 改變父元件的 OpenArticleBool 與,Display_article
假如 OpenArticleBool 為真,則在主頁顯示對應的文章內文(ArticleBody)

其他還有很多,包括闇黑模式也都有用到,但上方的舉例都有說到重點,這邊就不一一細講

  • 內文一把抓 - dangerouslySetInnerHTML
還記得上面闇黑模式提到的無解問題嗎?

其最根本原因就是因為:巴哈瀑布流的樓層內文是直接把整段HTML原封不動抓下來顯示在對應區域

辦到這一點的便是「dangerouslySetInnerHTML」
用法很簡單,它就像一個HTML的屬性,你爬回來一整段HTML後,存成變數當作屬性的值即可

  • 替換巴哈對於媒體內容的的自訂屬性
當然最終結果也不是說真的原汁原味,我抓下來之後還是有做一些基本的篩選潤飾

像是巴哈的連結,全部都有data前綴(例如 data-src),這爬回來不就沒辦法正常顯示了嘛?
所以我要將爬回來的內文篩出所有我需要改的 Element ,將原本的屬性去掉再加上新的屬性和原本的值


資料篩選反而是這 Side Project 最累人的部分

  • 換頁與層數
巴哈文章中,所有內文區域的東西,都是 class 叫作「c-section」的玩意兒
我是靠 for迴圈 去抓每一個 c-section 內的東西來拿這個樓層的內容,沒有更好的方法

而這之中,關於 c-section 的排序,我觀察出幾個狀況:

  1. 回覆數不到21個,所以開頭沒有頁碼
  2. 回覆數破20,所以開頭有一個 c-section 顯示頁碼
  3. 無論有沒有頁碼,主樓下面肯定是該死的猜你喜歡,它也是一個 c-section
  4. 當有文章被刪除被噓到摺疊,將會生成兩個該樓層的 c-section
  5. 大家都在看是一個 c-section
  6. 內容幾乎沒在變的 ACG 同好圈 X 閒聊取暖 X 自由經營公會新手村 也是一個 c-section

看出讓人皺眉的點了嗎?這些會影響 for迴圈抓資料的因素,同時也會影響我怎麼顯示層數

這就又得讓 Cheerio 篩資料,決定要不要爬取、要不要為該 c-section 計數了
明明需要找出各個 Element 不同之處,而這些HTML根本是同工異曲,最痛苦莫過於此


  • 巴哈場外休憩區C頁爬蟲 - 樓層留言區顯示
這邊我其實卡過好一陣子,就是不知道為什麼邏輯撞車

總之,我是設計 ArticleBody 會包著 ArticleReply
Reply 的值本身就是一個物件裝陣列,會儲存該樓所有留言和留言的各個部件

  • 超連結無法預覽 - 被 JavaScript 加工過的 HTML
巴哈的留言內容本體,在初始的HTML內完全就是個純文本
使用者的留言送出疑似超連結的東西時,會被巴哈偵測,自動轉換成可以預覽的狀態
可能在稍後被 JS 轉換成有 <a> 或 <img> 包起來的東西

Cheerio 只是一個解析器,它只解析 Axios 拿回來的 HTML
也就是說, 它不會讓巴哈原站上面的 Javascript 被執行,進而影響到它爬回來的 HTML 的內容
所以我爬回來的留言一定是原始的純文本,所有的超連結都無法預覽或打開

雖然老用戶仔細回想使用經歷,確實該會是這樣,但當下這個事實有驚到我
那,我要怎麼顯示留言區的媒體內容?

  • 正則表示法
一樣是小哈提點的辦法,利用正則表示法篩出所有可能會是超連結的文本,加上對應的前後HTML標籤
正則表示法看起來像天書,但懂規則就其實很好理解,雖然看上去是真的凌亂......

任何你覺得會出現的符號,一律以「\」開頭
篩出 GIF 舉例:(https:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]*[-A-Za-z0-9+&@#\/%=~_|]\.gif)
「https:」後面是不是要接「//」? 仔細看上面那串,就是在每個「/」之前都加上了「\」,對吧?

而如果你 不確定會接什麼 ,但是你對於它 可能會是什麼 有個底的話
就使用中括號「[]」篩出那個 Range
例如「A-Za-z」就是指你覺得 大寫與小寫的字母A~Z 都有可能出現,請它留意有滿足條件的就算通過



  • 匯出成品
我們 Electron React Boilerplate 大禮包比較特殊一點阿

如果照著官網文檔乖乖地 npm run package ,執行檔打開來就會得到快樂 Error:

好,現在可以把 build 資料夾刪掉了,這執行檔屬實是廢了

來看一下 VSCode 的報錯:

「找不到你的入口文件耶。」

我有去 package.json 檢查過,我確實是有設置 main 文件的,那麼原因出在哪兒呢?

這一篇非常有幫助

裡面有人說,"react-scripts" 會把你 build 資料夾刪得七七八八,直接殘廢
為什麼會這樣我不知道,但既然它會刪我檔案,那我就先刪了它
其他人有給出另一種解法,設置禁用擴展:「"extends": null,」,不過這個辦法我沒有親測

刪除 "react-scripts" 後, VSCode 終於不報錯了,exe檔也成功執行!


  • 結語
原本是有要做用戶自訂油圖桌布,但後來怕畫面太凌亂而且有點難搞,所以該功能就放棄了
如果覺得我幹得不錯的話,希望可以幫我去 Github 按個星星......

巴哈瀑布流 Figma 的設計稿,其實是開發階段很早期的產物,那個是等我放作品集時裝逼用的
我覺得嘎姆官網蠻可惜的是我沒有用 Figma 產平面設計稿,它明明是UIUX設計專案...
這專案剛好是我從零設計,很適合弄到 Figma 上面,之後會慢慢更新,改成桌面應用的樣式

這個 Side Project 搞得我這兩個月精神錯亂,整天在DC群裡鬼叫,終於是告一段落了
當然只做這樣,恐怕還是遠遠不足以讓我找到一份正常的實習
下一個專案要做什麼我還沒想到,估計會弄一個 todoList 網頁,或學 Vue 做一個什麼...嗎

希望大三結束前就能把畢業門檻的實習分數給解決





創作回應

RRRRRRRR
爬網站不等於業界預期的串接 API 喔~ 建議還是找一個公開的 api,看懂他的文件,搞懂 http request 怎麼發,才會比較像是實務上的做法
2022-11-15 12:41:45
RRRRRRRR
而當你會了以後你通常你也就會處理很多像是你上文提到的問題了,像是登入狀態、c-section 其實就是你 cheerio selector 沒下準的問題而已,data-src 是巴哈為了做 lazyload 才有的東西 (等你的流量需要付費的時候你就會開始考慮的東東
2022-11-15 12:44:52
燐火幽冥
! 了解,我之後再弄一個真的有串到 API 的作品吧
2022-11-15 12:57:35
乂巧天琴乂
好酷喔..正在學習如何寫app,雖然是不同領域,但看到這篇感覺多了一點動力自學一些酷東西
2022-11-15 12:52:22
燐火幽冥
加油!我目前還不會做手機應用程式,不過 React Native 好像可以做多平台的 app,之後想摸摸看
2022-11-15 13:00:24
御安鴨·摸頭害鴨哭
我看到了藍黑色的星爆氣流
2022-11-16 08:06:20
燐火幽冥
Tailwind 也星爆
2022-11-16 09:45:09

更多創作