Quantcast
Channel: WFU BLOG
Viewing all 784 articles
Browse latest View live

Google Apps Script 如何進行加密解密+取雜湊值(hash)﹍MD5 SHA HMAC RSA AES 操作說明

$
0
0
使用「Google 試算表做為資料庫」後,除了需要瞭解「資料庫防駭技巧」,為了安全性著想,一些需要加密的運算不可在前端執行(Javascript會被看光)。 舉例來說,前端發送修改資料的請求時,後端必須先驗證這個請求的身份、權限,也就是檢查前端附上的 token 通行金鑰。這個金鑰當然不可由前端產生,否則 JS 演算邏輯被看到,就可任意偽造通行金鑰。 那麼 Google 試算表的後端語言 Google Apps Script(簡稱 GAS),是否有足夠安全的加密演算法、是否需要安裝外掛?請見本篇的說明 (圖片出處: pexels.com)

一、GAS 內建工具

前端向後端發送請求時,反應速度是非常重要的,如果 GAS 在後端進行加密時還要讀取外掛,導致伺服器回應請求的時間過長,那麼前端的使用者體驗一定不佳,訪客遲早跑光光。 值得慶幸的是找了很久,終於發現 GAS 官方提供了內建的各種知名加密演算法,並提供了範例說明,請參考這個頁面有詳細列表: 1. 工具介紹從官網頁面的函數列表,我們看到 GAS 提供了這些工具:
  • base64:將字串轉換為 64 位元編碼,只使用英數符號。如果使用了英數以外的字串例如特殊符號、中文,最好先經 base64 編碼處理
  • Digest 演算法:包含了 MD5、SHA 等雜湊演算法
  • Mac 演算法:一樣使用 MD5、SHA 等雜湊演算法,但需要提供加密金鑰
  • RSA 演算法:RSA 是一種非對稱加密演算法,需要公鑰與私鑰
2. 加密演算法概念如果不了解各種加密演算法的話,建議先閱讀以下參考文章建立基本概念: 3. MD5、SHA 雜湊值從參考文章我們可瞭解到,MD5、SHA 這類演算法可計算出「雜湊值」(hash),這與「加密」的概念不同,因為「加密」代表可以「解密」,而「雜湊值」是不可逆的,意思就是說 MD5、SHA 這類演算產生的字串無法解密及還原。 用比喻來說的話,MD5、SHA 演算法是產生供辨識身份的 "指紋"、"簽名",這是獨一無二難以偽造的,實作上多用於產生驗證碼、檢查碼之用。如果只是從後端產生 token 通行金鑰的話,雜湊演算法就已足夠,不一定要用到「加密」功能。 官網可看到 DigestAlgorithm 提供了這些演算法:MD2、MD5、SHA-1、SHA256、SHA384、SHA512。 而參考文章除了說明以安全性而言,越後面的演算法越安全(雜湊字串位元數越高),另外提到 2017 年 Google 已經破解了 SHA-1 演算法,所以現今的年代建議使用 SHA256 以後的演算法。 4. MAC 雜湊值根據參考文章,MAC、HMAC 演算法一樣是產生「雜湊值」(不可逆),但不一樣的地方是需要提供「加密金鑰」(key) 才行。 使用金鑰的好處是,進行通訊的兩方都擁有 key,就能進行傳輸不加密的明文,並附上「雜湊字串」做為檢驗碼,收到的一方同時檢驗明文與檢驗碼,就能知道傳輸過程是否被攔截與竄改。 如果同樣一件事使用 MD5、SHA 做為檢驗碼,那麼攔截者修改內容後再附上新的檢驗碼,收到訊息的人就檢驗不出是否被竄改了。 5. RSA 加密「對稱加密」演算法使用共同的金鑰(key)來加密與解密,RSA 為「不對稱加密」演算法,需分別產生 "公開金鑰" 與 "私密金鑰"。 傳輸訊息方將訊息使用 "公開金鑰" 加密,收到訊息方擁有 "私密金鑰" 即可解密,還原原始訊息。 「不對稱加密」演算法耗費 CPU 計算的時間比較久,不過是最安全的加密方式。

二、MD5、SHA 操作

官方說明書大概是寫給工程師看的,沒有一定的基礎知識八成看不懂這些函數要如何運作。 MD5、SHA 函數及使用參數如下: computeDigest(algorithm, value, charset)
  • algorithm 填入演算法名稱,參照官網「DigestAlgorithm
  • value 填入原始字串
  • charset 為編碼方式,參照官網「Charset
但是 computeDigest 函數回傳的雜湊值為陣列型態,實務上需要轉換為文字才能使用。一種作法是參考外國網友寫的轉換字串程式「MD5 function for GAS」,而我的作法是利用官方提供的 base64 編碼也可轉成英數字串。 下面程式碼以 SHA_256 演算法舉例: var sourceStr = "Blogger 調校資料庫", // 原始字串 含 UTF8 中文字串 SHA_256_hash = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, sourceStr), // SHA_256 雜湊值 非 UTF8 編碼 SHA_256_hash_utf8 = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, sourceStr, Utilities.Charset.UTF_8), // SHA_256 雜湊值 UTF8 編碼 base64_SHA_256_hash = Utilities.base64Encode(SHA_256_hash), // SHA_256 雜湊值 非 UTF8 編碼 經 base64 編碼轉為英數字串 base64_SHA_256_hash_utf8 = Utilities.base64Encode(SHA_256_hash_utf8); // SHA_256 雜湊值 UTF8 編碼 經 base64 編碼轉為英數字串 console.log(SHA_256_hash); // [ -70, 36, 121, -47, -80, -76, -98, -14, 97, 106, 15, -57, 44, -122, -69, 58, -1, -128, -126, 39, -27, 17, 86, 42, 16, 23, -34, 92, 64, 43, -11, -10 ] console.log(SHA_256_hash_utf8); // [ -66, -35, 9, -38, 15, -43, 107, 103, -87, 17, 54, -104, -117, -29, 76, -27, 42, -108, -60, 9, -61, -14, 55, -80, 6, 0, 46, 16, 18, -74, 6, -86 ] console.log(base64_SHA_256_hash); // uiR50bC0nvJhag/HLIa7Ov+AgiflEVYqEBfeXEAr9fY= console.log(base64_SHA_256_hash_utf8); // vt0J2g/Va2epETaYi+NM5SqUxAnD8jewBgAuEBK2Bqo=

三、MAC 操作

使用 MAC 演算法產生雜湊值的 MD5、SHA 函數及使用參數如下: computeHmacSignature(algorithm, value, key, charset)
  • algorithm 填入演算法名稱,參照官網「MacAlgorithm
  • value 填入原始字串
  • key 填入加密私鑰
  • charset 為編碼方式
以下程式碼以 HMAC_SHA_384 演算法舉例: var sourceStr = "Blogger 調校資料庫", // 原始字串 含 UTF8 中文字串 key = "WFU BLOG", // 私鑰 HMAC_SHA_384_hash_utf8 = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_384, sourceStr, key, Utilities.Charset.US_ASCII), // SHA_384 雜湊值 UTF8 編碼 base64_SHA_384_hash_utf8 = Utilities.base64Encode(HMAC_SHA_384_hash_utf8); // SHA_256 雜湊值 UTF8 編碼 經 base64 編碼轉為英數字串 console.log(HMAC_SHA_384_hash_utf8); // [ 4, -36, -68, 59, 82, -127, -13, 111, -28, -52, 65, 7, -72, 109, -38, 107, -83, -36, -39, -60, 72, 80, 68, -37, -12, 62, -45, -45, 33, -89, -9, 67, 63, -57, -29, -128, 53, 42, 94, -26, -21, 111, 72, -66, 112, -20, 27, 69 ] console.log(base64_SHA_384_hash_utf8); // BNy8O1KB82/kzEEHuG3aa63c2cRIUETb9D7T0yGn90M/x+OANSpe5utvSL5w7BtF

四、RSA 操作

GAS 提供的 RSA 加密函數研究一陣子才發現沒有用處,無法生成公鑰、私鑰(要自己想辦法取得),只能產生雜湊值,不能加密也無法解密。 仔細想了一下,難怪函數名稱幾乎都有 "Signature",原來 GAS 本篇提供的工具作用就是製作 "簽名"。既是如此的話,不如直接使用前兩個方案就好,不需特別操作更複雜的 RSA 方案。不過既然都花時間了,還是把研究結果貼一下。 computeRsaSha256Signature(value, key)以下為範例程式碼: var sourceStr = "Blogger 調校資料庫", // 原始字串 privateKey = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAxiiQ5NEDMH3RRd1+gp5yDnT1r1cnVTQumaC1n6uK9JcHrDlfMASbMPO0adz1kMBN3jcMY3dRRcT4SoEkNxW1oQIDAQABAkBRNtcLsM5J1YcrxzfOePnuCumWz3WDajufI0rNAhWVYIbtSfgNQj0eZtMa2xshapGu7F7ov4UFb2YOlRhGl9xxAiEA/vnwYUZu4WmDbsemHTcxnpn6ivVs6bnzVDLx2rR1lZMCIQDG9Dr82jMAQ3SHCake6WGrU1oScP27BxtM9fFaGNTIewIhALnuLJnisIxzUsJ/l+SKEQbkpcya91bgoE3v8GlZWr09AiBIJQZC7Ijz/oIB+dHXAMBHFTmjWE/aA1C2DrVPe5OlgwIhALPUSYLt194IO89G79FCzCu+Cn3IxL0Xmxq7kzaCFERd", // 私鑰 從線上工具產生 privateKeyStr = "-----BEGIN PRIVATE KEY-----\n" + privateKey + "\n-----END PRIVATE KEY-----\n", // 完整私鑰字串 RsaSha256_hash = Utilities.computeRsaSha256Signature(sourceStr, privateKeyStr), // Rsa Sha256 雜湊值 base64_RsaSha256_hash = Utilities.base64Encode(RsaSha256_hash); // Rsa Sha256 雜湊值 經 base64 編碼轉為英數字串 console.log(base64_RsaSha256_hash); // MGnoHZQu2ZZFPACoMZMwMEC3dwUsc//EINixWsTjasydxc12nCIiDmkRpoF0G3O3ZRik69wSIgRurwjjjhNJ1A==

五、AES 加密、解密

AES 為知名的「對稱加密」演算法,介紹說明可參考維基「進階加密標準」。如果在 GAS 有加密、解密需求的話,因官方未提供內建工具,可參考以下的作法。 1. AES 工具這個網頁「CryptoJS libraries for Google Apps Script」將知名的 CryptoJS 函式庫搬到 GAS 使用,此頁面有操作說明,同時完整的程式碼放在這個頁面: 進入上面這個 GAS 頁面後,將「AES.gs」的所有程式碼複製到自己的 GAS,就可以進行操作了。 2. 範例程式碼以下的範例請自行修改原始字串、加密金鑰,就能進行加密與解密了: var sourceStr = "Blogger 調校資料庫", // 原始字串 使用 UTF8 編碼 Key = "WFU BLOG", // 加密金鑰 encodeStr = CryptoJS.AES.encrypt (sourceStr, Key).toString(), // 加密字串 decodeStr = CryptoJS.AES.decrypt (encodeStr, Key).toString(CryptoJS.enc.Utf8); // 解密字串 還原 UTF8 編碼 console.log(encodeStr); // U2FsdGVkX186XFuduXNEWWWUY02bhb+2IVKYyGcOoSg7dtmXxugjfTlGQ4TKC8qJ console.log(decodeStr); // Blogger 調校資料庫

六、補充說明

本篇使用到 GAS 官方提供的 base64 編碼工具,效果等同於前端 JS 的 btoa() 函數。然而官方提供的 base64 解碼工具跟 atob() 截然不同,解出來的不是字串,而是一個陣列,很難想像這是什麼東西,詳情可參考官網說明文件「base64Decode」:"Decodes a base-64 encoded string into a UTF-8 byte array"。 要還原 base64Encode() 字串的話不可直接用 base64Decode(),務必參照官方提供的範例程式碼,先解碼成陣列再製作出一個 blob 物件,再轉成字串才能成功: Utilities.newBlob(Utilities.base64Decode("這裡是 base64 編碼字串")).getDataAsString()
更多 Google Apps Script 相關技巧:

Blogger 群體被駭事件始末﹍淺談「社交工程」如何入侵網站

$
0
0
blogger-hacked-posts-deleted-social-engineering.jpg-Blogger 被駭事件始末﹍淺談「社交工程」入侵網站使用 Blogger 超過十年,上禮拜發生有史以來最嚴重事件,整個平台所有網站都被牽連:
  • 當天早上所有 Blogger 網站都被判定為「詐騙網站」,前、後台都無法進入
  • 部分網站不斷收到郵件通知,表示文章內容違反 Blogger 政策,因而被自動刪除
情況看起來很是危急,不過直接說結論,Blogger 很快就恢復全部異常狀態:
  • 「前、後台都無法進入」的狀況大約 1 小時左右,全部網站恢復正常
  • 「所有被自動刪除的文章」大約 12 小時後全部救回,且文章網址沒有異動,不影響 SEO
完整的事發經過可參考這個 FB 社團討論串,最早是成員 Ellen 通報「Blogger 網站無法進入且文章被刪除」。這次事件雖然有驚無險,但我認為背後有十分重要的意涵及警訊,特此進行記錄做為給所有站長的提醒。 (圖片出處:pexels.com)

一、為何 Blogger 文章被大量刪除

1. 事件記錄對多數 Blogger 站長而言,此次可說只是虛驚一場,但對少數站長而言就是心驚動魄了。因為大量文章被刪除,多年心血也不知能否救回,若平日還沒有備份的習慣,上禮拜那天將會很不好過。 blogger-hacked-posts-deleted-social-engineering-1.jpg-Blogger 被駭事件始末﹍淺談「社交工程」入侵網站手上經營的 Blogger 網站起碼有十多個,其中一個遭到文章被刪,從我這個小樣本推估也許全球有 1/10 ~ 1/20 的網站遭波及(當然也許沒那麼糟)。我在 FB 社團做了「事件記錄」,以下簡單摘要:
  • 收到郵件通知,不斷告知我的XX文章因違反Blogger政策「惡意軟體和病毒」而遭到刪除。
  • 接著前後台開始無法進入,出現「你要瀏覽的是詐騙網站」字樣
  • 根據「Blogger 官方論壇」的回報,全世界發生的時間都差不多,有大量使用者受害
  • 這代表 Google 一度偵測到有大量 Blogger 網站,網頁內容含有「惡意軟體和病毒」,故而啟動自動防護機制,將所有 Blogger 平台網站顯示警告字樣,避免訪客進入受到詐騙、釣魚內容的傷害
從以上現象來看,Google 的作法是值得肯定的,就像全球疫情的作法,發現病毒後需立刻進行隔離、圍堵。雖然訪客與站長會受到不便與驚嚇,但可確保所有人不受詐騙內容的影響。 2. Blogger 被駭然而問題就出在,為何我網站的文章會出現「惡意軟體和病毒」呢?有兩種可能,要嘛我的帳號被駭了,要嘛 Blogger 被駭。但無論是哪一種,可以確定的是 Blogger 被入侵了。 理論上來說 Google 是網路巨擘,要我相信有人能駭入 Google 伺服器還是相當困難的,應該會是世界性的新聞。比較有可能的狀況大概是這樣:(以下為個人分析,不代表為實際狀況)
  • 假設全球有 1/20 Blogger 站長帳號同時被駭、且同時發動攻擊 → 這個數量及難度實在大高也太誇張,可能性趨近零
  • 假設某個 Blogger 官方擁有高權限的工程師帳號被駭,駭客取得他的權限後就可操作 Blogger API 修改所有使用者的文章,植入惡意程式碼 → 這發生的可能性相對較高
  • 假設後者為真,駭客也知道相關動作很快就會被察覺,所以必須短時間內能改多少文章就算多少,才會全球差不多時間一起被攻擊
假如實情接近我的猜想,那就不是 Google 伺服器被攻擊,而是內部帳號權限被「社交工程」這樣的手法攻破,那麼這個手法也是本篇要探討的主題。

二、「社交工程」入侵案例

進入主題之前,先來看幾個案例。 1. 3C達人 Tim這是「3C達人Tim哥」半年前 50 萬訂閱數的 YouTube 頻道,被盜的過程自述影片: 簡單摘要一下重點:
  • Tim帳號被盜,但不是Tim的電腦或手機被盜,而是他同事的電腦被盜,因為他同事也有他的帳號權限
  • Tim 同事在被盜過程,曾被誘導下載不明檔案,Tim 推測就是帳號被盜的關鍵
  • Tim 有設定兩階段驗證,但他同事的電腦沒有,可能成為被攻擊的破口
  • 也可能 Tim 某個同事搜尋資訊的過程點過釣魚連結,增加帳號被攻擊的機會
  • Tim 另外分享有個 YouTuber 被盜,是因為收到合作邀約信件,裡面附的連結其實是釣魚網站,可以用來釣帳號
無論真實情況是哪一種,這些攻擊都不屬於外部的駭客攻擊手法,而是屬於內部攻擊(直接奪取帳號)。 2. YouTuber 腦洞烏托邦這是超過 80 萬訂閱的「腦洞烏托邦」,上個月 YouTube 頻道被盜的過程自述影片: 簡單摘要一下重點:
  • 小烏曾開啟一封促銷郵件,點了裡面的促銷連結,結果網頁一直顯示 loading 不動,很是可疑,結果後來就發現她老公在為電腦殺病毒,而隔天正式發現 YouTube 頻道被盜
  • 小烏有設定兩階段驗證,但沒作用,因為帳號相關資訊都被置換,她判斷是 Google 帳號被奪走,導致 YouTube 頻道被盜
  • 後來小烏老公告知,事發的同一天曾收到商業合作郵件,下載了郵件附件,才開始後來的殺病毒舉動
3. 歸納整理從以上兩個案例比對,可看到這些帳號被駭的手法重疊性很高,主要都是點擊可疑連結,或是下載了可疑檔案。對駭客來說,攻擊伺服器是比較困難的,但攻擊人性是比較簡單的,只要能想辦法誘使目標點擊連結、下載檔案,就能駭走帳號,這樣的手法就是本篇的主題「社交工程」。

三、「社交工程」的原理及防禦

1. 原理根據維基「社交工程」的定義:
在電腦科學,社交工程指的是通過與他人的合法交流,來使其心理受到影響,做出某些動作或者是透露一些機密資訊的方式。這通常被認為是欺詐他人以收集資訊、行騙和入侵電腦系統的行為。
同時該頁面也說明了社交工程學的犯罪手法演進:
  • 釣魚式攻擊:利用電子通訊偽裝知名單位(可能是詐騙電話),騙取機密資訊
  • 電腦蠕蟲:利用郵件附檔散播蠕蟲惡意程式
  • 垃圾郵件:以電子郵件夾帶木馬程式
  • 惡意軟體:例如網路上偽裝成實用軟體、APP,引誘下載的程式
2. 「社交工程」如何攻破心防瞭解以上手法後,在配合本篇看到的所有案例,可知駭客、攻擊者,都是不斷研發各種手法、精進文案內容,想盡辦法利用人性心理弱點,來誘使點擊釣魚連結,下載惡意程式並執行。 以 YouTube 頻道主、部落格站長而言,最容易卸下心防的就是「業配合作邀約」,當看到賺錢機會時,有誰會去懷疑這封郵件內含釣魚連結嗎?廠商提供的合作說明附檔,有可能忍住不下載嗎? 當然釣魚郵件的手法還有很多,假冒系統通知信、製造恐慌內容、偽裝知名官網或企業都有。除了這些郵件舉例,我也遇過粉絲團有人傳訊希望合作,並附上他的公司網址連結,只不過看起來有點特別,網域是 .jp ,如果是你有可能忍住不去點擊嗎? 3. 防禦「社交工程」從本篇提供的所有案例過程來看,我大致歸納一下想法:
  • 「兩階段驗證」保護帳號是有一定成效的,前提是帳號權限不能失去,就像 Tim 利用「兩階段驗證」守住了他自己手機的帳號
  • 會失去帳號權限主要是曾下載不明檔案,例如 Tim 同事、小烏的先生
  • 若只是點擊了釣魚連結,有可能該帳號會被釣、存取權會被取得,但還不至於失去帳號權限。只要有設定「兩階段驗證」,當駭客想取得帳號權限時,我們手機就會收到通知,那麼帳號就不至於被盜。
至於為何下載惡意檔案後,會讓兩階段驗證失去效用、失去帳號權限,這方面我不是專業人士,無法細說原理,只能簡單說:「點擊釣魚連結後,駭客取得的權限限於瀏覽器環境;下載惡意檔案,駭客取得的權限是整部電腦,因此更為可怕」。 不過對於如何防禦「社交工程」的攻擊,以下是我的分析與理解:
  • 下載不明來源的檔案並執行,是風險最大、最嚴重等級的動作
  • 一定要下載的話,請使用不重要的電腦,該電腦沒登入過重要帳號
  • 如果要點擊不明連結,該台電腦使用的帳號,一定要設定兩階段驗證
  • 如果有某台電腦的帳號沒有兩階段驗證,又必須點擊不明連結,可傳送到使用兩階段驗證帳號的電腦再點擊。

四、Blogger 防護概念

回到本篇的 Blogger 被駭事件,因為 FB 社團多位成員表示從未備份過文章,我想有必要讓站長們瞭解基本的防護概念,保護自己的網站不單是為自己也是為粉絲。 1. Blogger 官方的職責前面有提過,想要從外部駭入 Google 伺服器我認為非常困難,所以這部分 Blogger 站長們是可以放心的。 只是這次的事件看起來是 Blogger 內部被攻破,導致某些站長們失去了不少文章,也讓我一度懷疑 Google 有沒有能力回復被修改的文章內容? 同時 FB 社團也有成員提出質疑,是否搬去 WP 會比較安全?我給他的回覆是,Blogger 被駭還有 Google 工程師能幫忙救,如果 WP 被駭有能力自己救的話就可以搬到 WP。 事實上我曾經幫客戶維護 WP 過,也遭遇過駭客入侵,解決方式就是靠備份,將網站還原到備份的時間點就正常了。這種防護方式不十分完美但已經足夠了。如果會有損失,主要就是還原的時間點到被駭的時間點之間,網站曾做過的變更需要重來。 而這次的事件 Blogger 並不是使用還原的某個時間點的處理方式,而是所有被修改過內容並植入惡意程式碼,然後被刪除的文章逐一還原,這樣的技術遠超 WP 自行維護的效果。 因此我必須說,Blogger 後端的防護交給 Google 工程師,比任何其他部落格平台都更為放心。 2. Blogger 站長的職責後端若出了問題 Google 會負責,但前端站長們若沒把自己的網站、帳號守好,出了問題就非常難救。因此請建立以下正確的防護概念:
  • 網站需要自行定期備份:這是我遇過的案例「Blogger 文章不小心誤刪了怎麼辦?救回及善後技巧整理 」,只要是人為操作都有可能失誤,所以文章一定要備份,後面會提供有效率的作法。
  • 網站少裝不明第三方外掛:可參考「為何部落格最好避免第三方外掛」系列文章,如果外掛不是由信任的網站提供,那麼不小心裝了木馬就慘了
  • 瀏覽器外掛:例如 Chrome 只安裝官方套件,不安裝來路不明的 apk,很有可能是釣魚軟體
  • 兩階段驗證:Google 帳號一定要設定兩階段驗證,否則帳號被盜網站也跟著被拿走了
  • 下載檔案:要下載並執行不明檔案請使用沒登入重要帳號的電腦,否則帳號有可能被盜走
3. Blogger 自動備份定期備份文章是一件瑣碎的工作,沒幾個人有耐心與毅力執行,所以這件事最好交給程式自動執行。 過去我寫了不少備份的方法,請站長們擇一進行就可以了:

五、補充

粉絲團貼文」有讀者留言,覺得非常實用,引用分享如下:
分享如何判斷假業配:查信用、看國籍、問價碼和付款方式。可疑的郵件和連結如果真的要開,用虛擬機開,反正還原只要五分鐘。那種風平不佳的國家(包括台灣和日本),除非將近五星,都不要考慮。付款方式模稜兩可,支吾其詞的嫌疑都很高。台灣勞工福利低,目前還沒有外包客戶評價平台,是個需要改進方向。路過的大大有興趣可以考慮。
更多「資訊安全」相關文章:

如何製作無圓點單選、多選按鈕(Input radio+checkbox)﹍純 CSS 技巧免 JS

$
0
0
HTML 表單提供了基本款 input 單選功能(圓點效果 type="radio"),以及多選功能(核取方塊 type="checkbox")。如果不求版面質感的話,瀏覽器預設效果已經算實用了。 但網頁設計如果不想跟別人家撞衫,那麼預設的圓點效果、核取方塊可能稍微陽春了一點。偏偏瀏覽器內建的 "圓點"、"方塊" 如果想改 CSS 樣式還做不太到,且每個瀏覽器的效果都是不一樣的。如果要跨瀏覽器統一樣式,想來想去似乎只能自己另外製作按鈕,以及寫 Javascript 來實現單選、多選效果。 前陣子有製作大量單選按鈕的需求,但又不想每處都寫一次單選功能的 JS,於是研究了一下能否靠 CSS 解決這件事,還真找到一勞永逸的解法,請見本篇的整理。

一、原理

1. 運用 label 標籤幾年前寫「自訂 Input File 檔案上傳按鈕 CSS 最佳解法」有提過「二、label標籤的妙用」:
  • Label 標籤有一個奇特的特性,只要他包在任何 Input 標籤外面,點擊 Label 就等於點擊 Input
  • 所以當 Label 標籤很寬、很大時,點擊 Input 就很方便
  • 利用這個特性,將 Label 標籤包在 input 上傳按鈕外面,再將 input 上傳按鈕隱藏起來,點擊依然有效
  • 原本對 input 上傳按鈕無法設定的任何 CSS,此時設定在 Label 上即可。
利用同樣原理,製作無圓點的單選按鈕、多選按鈕時,將 label包覆在 input外面,並將 input 隱藏起來就看不到圓點、方框了。 取而代之在 label 中製作一個按鈕樣式,使用 buttonspan標籤都可,並設定按鈕的 CSS 樣式就搞定了。 2. 應用範例這個討論串「CSS selector for a checked radio button's label」除了有本篇主題的相關討論,還夾雜了一個很厲害的範例(目前看起來是第3個回答),遠超出了單選按鈕的功能:
  • 上方有三個選單分頁,是單選切切換的型態
  • 下方則是分頁的內容,點擊該分頁時才顯示對應的分頁內容
一般來說分頁切換都要寫 JS 才能辦到,但這個範例利用點擊單選按鈕,並同時切換分頁內容,完全只靠 CSS,是個非常強大的構想!

二、單選按鈕範例程式碼

以下提供簡單的單選按鈕範例程式碼,實作頁面可參考 "線上看電視" 的「戲劇節目進階篩選」頁面: <div id="radio"> <label><input type="radio" name="label" value="台劇" checked="checked"><span class="round button">台劇</span></label> <label><input type="radio" name="label" value="古裝劇"><span class="round button">古裝劇</span></label> <label><input type="radio" name="label" value="陸劇"><span class="round button">陸劇</span></label> <label><input type="radio" name="label" value="韓劇"><span class="round button">韓劇</span></label> <label><input type="radio" name="label" value="鄉土時代傳統劇"><span class="round button">鄉土傳統劇</span></label> <label><input type="radio" name="label" value="大愛劇"><span class="round button">大愛劇</span></label> </div> <style> #radio input[type="radio"] {display: none; } #radio input:checked + .button {background: #5e7380; color: #fff; cursor: default; } #radio .button {display: inline-block; margin: 0 5px 10px 0; padding: 5px 10px; background: #f7f7f7; color: #333; cursor: pointer; } #radio .button:hover {background: #bbb; color: #fff; } #radio .round {border-radius: 5px; } </style>
  • 所有 name 設定相同字串,才能有單選效果(value 不一定要設定,此處有設定是方便 JS 取值)
  • hover 時加上手掌游標,代表可選取,並設定不同的顏色樣式
  • 已選取的按鈕使用箭頭游標,代表不可選取
下面是以上程式碼的實際效果:

三、多選按鈕範例程式碼

多選按鈕原理一模一樣,前面的 CSS 稍微修改即可,以下提供簡單的範例程式碼,取自 "線上看電視" 的綜藝節目標籤: <div id="checkbox"> <label><input type="checkbox" name="variety" value="綜藝" checked="checked" /><span class="round button">綜藝</span></label> <label><input type="checkbox" name="variety" value="節目" checked="checked" /><span class="round button">節目</span></label> <label><input type="checkbox" name="variety" value="隨選隨看" checked="checked" /><span class="round button">隨選隨看</span></label> <label><input type="checkbox" name="variety" value="直播" /><span class="round button">直播</span></label> <label><input type="checkbox" name="variety" value="台綜" /><span class="round button">台綜</span></label> <label><input type="checkbox" name="variety" value="陸綜" /><span class="round button">陸綜</span></label> <label><input type="checkbox" name="variety" value="韓綜" /><span class="round button">韓綜</span></label> <label><input type="checkbox" name="variety" value="遊戲" /><span class="round button">遊戲</span></label> <label><input type="checkbox" name="variety" value="益智" /><span class="round button">益智</span></label> <label><input type="checkbox" name="variety" value="談話" /><span class="round button">談話</span></label> <label><input type="checkbox" name="variety" value="娛樂" /><span class="round button">娛樂</span></label> <label><input type="checkbox" name="variety" value="網紅" /><span class="round button">網紅</span></label> </div> <style> #checkbox input[type="checkbox"] {display: none; } #checkbox input:checked + .button {background: #5e7380; color: #fff;} #checkbox .button {display: inline-block; margin: 0 5px 10px 0; padding: 5px 10px; background: #f7f7f7; color: #333; cursor: pointer; } #checkbox .button:hover {background: #bbb; color: #fff; } #checkbox .round {border-radius: 5px; } </style>下面是以上程式碼的實際效果:
更多 CSS 相關技巧:

製作 TAB 頁籤選單最簡單的架構﹍純 CSS 實現技巧整理

$
0
0
最近有個需求是製作 TAB 頁籤選單,這功能很常見,理應沒什麼難度。然而客戶希望將來能自行編修、調整選單內容,並製作大量相關頁面,這對於不是熟悉前端程式碼、架構的人來說,要無腦編修 TAB 頁籤的 HTML/CSS 內容實在不太可能(因為這案子的選單內容區塊架構很複雜),而且我也不想順便再教幾堂基礎 HTML/CSS 課程。 於是花了些時間研究,TAB 選單有沒有架構最簡單的實現方式,如果能以純 CSS 實現、不另外處理 JS 更好,研究結果請見本篇的整理。 (圖片出處: .peakpx.com)

一、各種方案比較

第 1 個頁籤內容區塊
第 2 個頁籤內容區塊
第 3 個頁籤內容區塊
1. 理想架構上面是一個簡單的 TAB 頁籤效果,對於目標是建立一個可以無腦維護、容易複製編修重作的架構,我理想中的 TAB 頁籤程式碼模組希望能符合以下需求:
  • 能只用 HTML/CSS 處理、不另外寫 JS 最好
  • 維護時最好只需複製、編修 HTML 區塊,不用另外動到 CSS,也就是 CSS 寫法需要能萬用,如此可減少人為操作失誤
  • 根據前一點,選單頁籤區塊與內容區塊最好位於同一處
    • 根據多年經驗,選單的架構一定是頁籤區塊一處、內容區塊一處,頁籤區塊的順序必須與內容區塊的順序一致
    • 那麼日後增、減內容時,不小心兩邊不一致就會讓頁籤與內容不符合,更別說不熟悉前端的人一定會搞混
    • 所以如果能有一種架構,是頁籤區塊與內容區塊可以打包在一起,日後維護絕對不會出問題
接著以下整理一些純 HTML/CSS 頁籤架構的方案。 2. 利用 :target可參考這篇「純CSS製作HTML頁籤切換的效果與實例」,其原理為:
  • 點擊頁籤的部分利用 A 連結的錨點功能
  • CSS 處理內容區塊切換的技巧為使用偽類 :target,很是巧妙
此方案不符合本篇需求的原因為:
  • 選單架構 HTML 為傳統的頁籤區塊一處、內容區塊一處,維護不便
  • 使用錨點會讓應用方式受限,如果整個選單位於畫面需要捲動之處,點擊頁籤後就只能看到內容、看不到頁籤
3. 利用 input 單選按鈕(1)可參考這個 CodePen 範例「CSS Only Tabbed Content」,其原理為:
  • 使用 Input 單選按鈕製作頁籤效果,原理可參考「如何製作無圓點單選、多選按鈕﹍純 CSS 技巧
  • HTML 使用傳統的 TAB 頁籤架構,頁籤一區、內容一區
  • CSS 處理內容區塊切換的技巧為,使用 input 單選按鈕獨有的偽類 :checked,然而有幾個頁籤就必須設定幾個控制代碼,也是這個架構下無可奈何的事
此方案不符合本篇需求的原因為:
  • 傳統的頁籤選單 HTML 架構維護不便
  • 只要新增頁籤、內容,就必須新增對應的 CSS 控制,維護麻煩
4. 利用 input 單選按鈕(2)可參考這個 stack overflow 討論串「Accessible CSS-only tab view」,其原理為:
  • 同前範例,使用 Input 單選按鈕製作頁籤效果
  • 這是我首次看到使用非傳統 HTML 頁籤架構,頁籤與內容區塊合而為一!
  • CSS 處理內容區塊切換的技巧同上,使用 input 單選按鈕獨有的偽類 :checked
  • 內容區塊的版面處理則是必須使用 position: absolute定位,否則無法出現在該有的版面位置
此方案的感想:
  • 這是目前為止接近滿分的方案,頁籤與內容區塊合而為一,要複製、修改、刪除都非常方便,只要處理一處適合無腦維護
  • CSS 部分為萬用代碼,無論如何新增、刪除頁籤,都不需動到 CSS
  • 唯一的缺點是使用 position: absolute來定位,這會使應用方式受限,必須為內容區塊設定高度(否則版面會爆掉),導致內容區塊無法根據內容彈性調整高度
就差那麼一點點,於是繼續尋找有沒有更好的方案。

二、利用 flexbox

最後找到這個方案,參考這個 CodePen 範例「Pure CSS Tabs 」,其原理為:
  • 同前範例,使用 Input 單選按鈕製作頁籤效果,並且使用非傳統 HTML 頁籤架構,頁籤與內容區塊合而為一!
  • 唯一不同處,內容區塊的版面處理使用 display: flex,這是 CSS 新世代的 flexbox 排版技巧
此方案特點:
  • 目前為止最接近完美的方案,幾乎符合我所有需求。
  • 日後要複製、修改、刪除時,只有一點不方便,必須手動為個別 input 單選按鈕設定 id,且對應的 label 標籤也要設定 for 參數
  • 不過上一點的不便之處,可以另外寫一行 JS 來自動處理,那麼給客戶使用時就能無腦維護了

三、範例程式碼

以下提供整理過,版面效果較佳的範例程式碼: <div class="tab_css"> <!-- TAB1 打包區塊 start --> <input id="tab1" type="radio" name="tab" checked="checked"/> <label for="tab1">頁籤 1</label> <div class="tab_content"> 第 1 個頁籤內容區塊<br/> WFU BLOG | Blogger 調校資料庫<br/> </div> <!-- TAB1 打包區塊 end --> <!-- TAB2 打包區塊 start --> <input id="tab2" type="radio" name="tab"/> <label for="tab2">頁籤 2</label> <div class="tab_content"> 第 2 個頁籤內容區塊<br/> WFU BLOG | Blogger 調校資料庫<br/> 第 2 個頁籤內容區塊<br/> WFU BLOG | Blogger 調校資料庫<br/> </div> <!-- TAB2 打包區塊 end --> <!-- TAB3 打包區塊 start --> <input id="tab3" type="radio" name="tab"/> <label for="tab3">頁籤 3</label> <div class="tab_content"> 第 3 個頁籤內容區塊<br/> WFU BLOG | Blogger 調校資料庫<br/> 第 3 個頁籤內容區塊<br/> WFU BLOG | Blogger 調校資料庫<br/> 第 3 個頁籤內容區塊<br/> WFU BLOG | Blogger 調校資料庫<br/> </div> <!-- TAB3 打包區塊 end --> </div> <style> .tab_css{display:flex;flex-wrap:wrap;justify-content:center;} .tab_css input{display:none} .tab_css label{margin: 0 5px 5px 0; padding: 10px 16px; cursor: pointer; border-radius: 5px; background: #999; color: #fff; opacity: 0.5;} .tab_content{order:1;display: none; width:100%; border-bottom: 3px solid #ddd; line-height: 1.6; font-size: .9em; padding: 15px; border: 1px solid #ddd; border-radius: 5px;} .tab_css input:checked + label, .tab_css label:hover{opacity: 1; font-weight:bold;} .tab_css input:checked + label + .tab_content{display: initial;} </style>

四、展示效果

範例程式碼的 DEMO 效果如下:
第 1 個頁籤內容區塊
WFU BLOG | Blogger 調校資料庫
第 2 個頁籤內容區塊
WFU BLOG | Blogger 調校資料庫
第 2 個頁籤內容區塊
WFU BLOG | Blogger 調校資料庫
第 3 個頁籤內容區塊
WFU BLOG | Blogger 調校資料庫
第 3 個頁籤內容區塊
WFU BLOG | Blogger 調校資料庫
第 3 個頁籤內容區塊
WFU BLOG | Blogger 調校資料庫
更多 CSS 相關技巧:

購買 Blogger 範本遭遇詐騙事件實錄

$
0
0
raintemplates.jpg-購買 Blogger 範本遭遇詐騙事件實錄前陣子有客戶想架購物車網站,沒想到在指定的範本網站付費買了範本後,卻無法下載。 為了確認不是操作錯誤引起的問題,付了兩次費用,也請客人操作一次,結果都一樣無法下載,才確定被騙了。 過去自己及客戶買了無數次範本,沒想到第一次遇到這樣的事,覺得有必要紀錄一下事件始末,歸納所有可疑行為的模式,提醒讀者們小心避免遇雷。

一、購買經過

疑點 1一開始客戶指定購買「Raintemplates」這個網站的購物車範本: raintemplates.jpg-購買 Blogger 範本遭遇詐騙事件實錄看完頁面資訊當下是有疑問的,這未免太佛心了吧,購物車範本通常 USD 20~30 起跳,結果該範本原價 USD 25,特價只要 USD 1.9,一般的心態應該都是 "太好~賺到了!"。 疑點 2下單時發現原來我以前在這網站買過,大概是幫客戶買的,已經有註冊過帳號,所以當下是比較放心的,而且可以使用 PayPal 付款,不必擔心填寫信用卡號有被盜刷的風險。 但很快就遇到了麻煩,因為很久以前註冊的,早就忘了密碼。然而點擊「忘記密碼」的按鈕,要求這網站取回密碼時,卻一直沒收到郵件,所以內心開始遲疑,會不會這網站的某些服務功能早已停止運作?(後來也確定都停止運作,因為怎麼填寫聯絡表單都不會回應) 疑點 3這網站要結帳必須註冊,不得已只好重新註冊帳號,但遇到另一個更引起我懷疑之處,系統要求建立的密碼規則比較複雜,包含英文大小寫及數字,也不准設定簡單的字串。 這非常不尋常,因為這網站並不知名,而通常只有市佔率非常高的服務,才會要求建立安全度相當高的密碼規則。 這讓我開始有警覺會不會有可能是釣魚行為,利用複雜的密碼規則誘使使用者設定與「其他重要線上服務相同的密碼」疑點 4註冊完使用 PayPal 扣款後,結果沒寄發交易成功信,也沒出現「下載」按鈕,一時之間不曉得是不是哪裡操作錯誤,導致沒有交易成功。 因為 USD 1.9 不貴,乾脆重來又下單了一次,結果仍是一樣,開始懷疑是詐騙行為了。 疑點 5於是問問客戶有沒有 PayPal 帳號,請客戶操作購買一次試試看,結果依然不會出現「下載」按鈕,至此可以確定這是詐騙網站。

二、事後處置

1. 防止被駭其實被騙事小,只不過是損失一點小錢,這個事件我最擔心的環節是「要求註冊帳號密碼」,對於比較沒有資安警覺的使用者來說,這裡很有可能會翻船翻很大。 當確立是詐騙事件後,我稍微分析一下該網站的犯罪模式,認為其重點有二:
  • 如果使用者選擇刷卡,該網站就有機會取得卡號資訊,得以進行盜刷
  • 如果使用者註冊的 email、密碼與其他重要服務相同,該網站就有機會駭入該使用者的其他重要服務帳號
所以當下立即告訴客戶,註冊時有沒有使用與其他帳號相同的 email、密碼?如果有的話,請將該帳號「立刻啟用兩階段驗證」。 客戶也立即照做,且幾天後告訴我,他的其他帳號真的收到系統通知,有被 try 密碼的紀錄,並感謝我當初有馬上通知他。 2. 向 PayPal 申訴對於這個網站我自然想要處置他,但後來卻發現根本拿他一點皮條也沒有,因為整個網站找不到「關於我」的頁面,也沒有任何聯絡資訊(沒有 email),完全查不到底細,代表這網站一開始就沒打算長久經營。 退而求其次,我只能讓 PayPal 瞭解該網站的帳號是有問題的,希望 PayPal 能進行處置。我找到了這個網頁: 照著官方的流程提出了申請,並詳述 Raintemplates 收了我的兩次款項但沒給範本檔案。同時也通知客戶按此流程做一次,希望越多人申訴 Raintemplates 的話,PayPal 會將帳戶列為黑名單、警示帳戶之類。 raintemplates.jpg-購買 Blogger 範本遭遇詐騙事件實錄這個流程是漫長的,因為 PayPal 會給雙方兩個星期的時間溝通,沒有結果時 PayPal 才會介入,再等兩個星期若 Raintemplates 還是沒任何回應,當初付的款項才會退回來。 只是 PayPal 對 Raintemplates 會有什麼處置我無從得知。 3. 公諸於世最後能做的,就是將這件事公諸於世。因為我很少在國外論壇打轉,所以也只能讓中文體系的使用者知道了。 如果有讀者常上相關的國外論壇的話,希望能用英文、其他語言、其他管道,讓國外網友注意到這個網站的事跡,別讓更多人被騙、以及被盜刷、被駭了

三、總結

最後從這件事總結一下如何避免網路購物被詐騙:
  • 如果要線上刷卡,一律只能在業界知名、龍頭的網站刷,否則很有可能被盜刷。
  • 不夠知名的網站只能使用「業界知名、龍頭的第三方支付」,例如 PayPal,萬一出了事還有一道防火牆
  • 在不夠知名的網站線上購物,最好先做身家背景調查,閱讀「關於我」頁面、查該網站的聯絡 email
  • 註冊帳號密碼時,絕對不可使用跟重要帳號一樣的密碼
如果保有以上這幾點的警覺性,就可以將損失降到最低了。
更多「Blogger 範本」相關文章:

Google 帳號資訊如何辨別真偽﹍後端驗證用戶資料與 token 的技巧

$
0
0
過去曾使用「Google 試算表」來打造及存放會員系統,而會員註冊的部分可利用「FB API 製作登入按鈕」取得帳號資訊。但 FB API 限制較多也不好操作,後來使用「Google API 製作登入按鈕」取得基本資訊,並搭配「People API」取得更多個人資訊。 有第三方 API 處理會員註冊問題真的方便又安心,不用經手棘手的帳號密碼問題,可參考「FB API 製作登入按鈕」的詳細說明。不過久了可能會面臨一種狀況:「被大量惡意註冊怎麼辦?」當提供的服務如果出名、爆紅了,就會有各種原因出現大量註冊,例如用來鑽漏洞、或是被公關公司盯上成為目標。 前端經第三方 API 取得的使用者資訊不會有什麼問題,但傳送到後端的資料就無法保證了,一方面所有中繼傳輸設備都可能被攔截,一方面有心人說不定已寫好了執行腳本,跳過前端直接發送大量的假帳號註冊請求給後端,一次註冊了幾百個帳號也說不定。 依照這樣的攻擊手法,我們有可能在後端辨識出,這幾百個註冊的 Google 帳號是真是假嗎? (圖片出處: pixabay.com)

一、Google API 使用者資訊

首先複習一下「Google API 登入按鈕」,Google 登入後可以取得這些公開資訊:ID暱稱頭像Email。接著儲存到資料庫後,要拿 ID 或 Email 做為單一不重複的帳號依據都可。 然而前端傳送到後端的註冊請求,資訊想造假並不困難,"暱稱"、"頭像"、"Email" 就不用說了,如果 "ID" 資訊是假的,後端有辦法判斷嗎?畢竟 ID 是第三方 API 產生的,我們不會知道運算邏輯,所以哪知道這字串是真是假~ 好消息是,實際上別說 "ID",我們連 "暱稱"、"頭像"、"Email" 全部的資訊都有辦法辨別真偽!趕快來看看是怎麼回事。

二、後端進行身份驗證

根據 Google 官網文件「使用後端服務器進行身份驗證」,官方明確告知我們要如何對使用者進行身份驗證:
如果您將Google登錄用於與後端服務器通信的應用或網站,則可能需要識別服務器上當前登錄的用戶。為了安全地執行此操作,請在用戶成功登錄後,使用HTTPS將用戶的ID令牌發送到您的服務器。然後,在服務器上,驗證ID令牌的完整性,並使用令牌中包含的用戶信息建立會話或創建新帳戶
意思就是說,使用者在前端登入 Google 帳號後取得的資訊,其中包含了 "ID令牌",也就是 ID token,必須傳到後端伺服器進行驗證。驗證無誤後,再將 ID token 中包含的使用者資訊(這才是不會被竄改的資訊)進行註冊之用。 根據官網說明,驗證 ID token 的網址如下: https://oauth2.googleapis.com/tokeninfo?id_token=這裡是 ID token 字串如果 id_token 驗證無誤,就會傳回使用者資訊,此時可以跟前端接收到的使用者資訊一一比對,就能驗證 Google 帳號的註冊資料真假了。官網也提供該網址回傳的資料範例,大概長這樣: { "iss": "https://accounts.google.com", "sub": "110169484474386276334", "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com", "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com", "iat": "1433978353", "exp": "1433981953", "email": "testuser@gmail.com", "email_verified": "true", "name" : "Test User", "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg", "given_name": "Test", "family_name": "User", "locale": "en"}主要看看 name、email、picture(頭像網址) 這幾項是否吻合就可以了。

三、取得 id token 範例程式碼

修改一下「Google API 登入按鈕」的範例程式碼,就可取得 id_token、access_token 等資訊: <script src="https://apis.google.com/js/platform.js" async="async"></script> <meta name="google-signin-client_id" content="5432xxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com"/> <div class="g-signin2" data-onsuccess="onSignIn"></div> 目前狀態: <span id="GOOGLE_STATUS_1"></span> <script> // 登入之後 function onSignIn(googleUser) { var profile = googleUser.getBasicProfile(), target = document.getElementById("GOOGLE_STATUS_1"), html = ""; html += "ID: " + profile.getId() + "<br/>"; html += "會員暱稱: " + profile.getName() + "<br/>"; html += "會員頭像:" + profile.getImageUrl() + "<br/>"; html += "會員 email:" + profile.getEmail() + "<br/>"; html += "id token:" + googleUser.getAuthResponse().id_token + "<br/>"; html += "access token:" + googleUser.getAuthResponse(true).access_token + "<br/>"; target.innerHTML = html; } </script>
  • 紅色字串改為自己的「用戶端 ID」,請參考前一篇所有流程注意事項

四、驗證 id token

下面是以上範例程式碼「官方 Google 登入按鈕」的效果,執行登入可取得各項資料:
目前狀態: 如前面「二、後端進行身份驗證」的說明,以下紅字改為自己的 id token 字串即可取得驗證結果: https://oauth2.googleapis.com/tokeninfo?id_token=這裡是 ID token 字串

五、驗證 access token

前面的範例程式碼附帶提供了 access token 資訊,取得的方式請參考討論串「How to properly get Access Token from logged in Google Sign In」。 這裡額外說明如何驗證 access token 真偽。此討論串「How can I verify a Google authentication API access token?」提到 Google 兩個版本的驗證網址: https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=這裡是 access token 字串https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=這裡是 access token 字串任選一個將紅字改為自己的 access token 字串即可取得驗證結果。
更多「資訊安全」相關文章:

Adsense 自動廣告優化心得

$
0
0
adsnese-auto-ad.jpg-Adsense 自動廣告優化心得前陣子接到需求想要優化網站 Adsense 廣告,因 Adsense 推出的自動廣告已經實驗滿長一段時間,便問客戶要不要試試看。且自動廣告有實驗功能,可根據實驗結果決定是否採用,不必立即做決定。 本篇整理這段期間的優化心得,且因某些功能不易找到,也會附上相關操作說明。

一、所有自動廣告格式

從 Adsense 後台,可看到「自動廣告」其實包含了 4 種格式: adsnese-auto-ad-1.png-Adsense 自動廣告優化心得1. 網頁內廣告可參考官網說明「自動廣告簡介」:
  • 自動廣告會分析網頁,根據版面配置、內容和現有的 Google 廣告,在合適的位置自行產生廣告區塊。
  • 網頁已含現有 Adsense 廣告的位置,不會進行變更
  • 如果文章內容越長,則自動廣告的數量可能越多,沒有以往的數量限制(4個)
2. 相符內容廣告可參考官網說明「相符內容簡介」:
  • 相符內容只開放給特定發佈商使用,網站必須達到流量及不重複網頁數目的最低需求條件,才能使用相符內容。(沒有符合資格的網站應該看不到選項)
  • 這等於是安裝了「相關文章」這樣的工具,但某些欄位 Adsense 會穿插廣告
  • 只會在有適合的廣告時,才會顯示廣告,所以不一定會出現廣告
3. 錨定廣告 / 穿插廣告可參考以前寫的「Adsense 廣告(錨定/穿插)使用心得」:
  • 錨定廣告:會固定在使用者螢幕邊緣
  • 穿插廣告:這類全螢幕廣告會在網站載入網頁的空檔顯示 → 代表切換頁面之間才會顯示
  • 跟以往不同的是,現在兩種廣告在網頁版也可出現

二、進行實驗

1. 實驗說明自動廣告是由 Google 的 AI 演算法自動產生,會出現什麼效果不是我們能預期的,怕影響網站美觀的站長們不一定放心使用。 不過 Adsense 很貼心的提供「實驗」功能,可參考官方頁面「在 AdSense 中執行實驗」、「實驗常見問題」:
  • 進行實驗時,自動廣告只會出現在 50% 的網頁瀏覽,也就是採 A/B 測試
  • 實驗期間預設為 90 天,可隨時看到自動廣告的執行成效,與沒有自動廣告的成效對比
  • 若成效不佳,可隨時終止實驗;若覺得成效不錯,也可立即全部採用自動廣告
2. 開始實驗進入「Adsense」後台 → 選單 → 最佳化 → 實驗 adsnese-auto-ad-2.jpg-Adsense 自動廣告優化心得如上圖,點擊右方紅框「建立實驗」 adsnese-auto-ad-3.png-Adsense 自動廣告優化心得選擇要實驗的網域後,點擊「選取網站」 adsnese-auto-ad-4.jpg-Adsense 自動廣告優化心得在「廣告格式」頁籤,可啟用 4 種廣告格式、選擇是否在「寬螢幕」顯示,請依照自己需求選擇。 在「廣告載入量」頁籤,可設定廣告顯示的數量。 最後按下方的「開始實驗」即可。 4. 實驗成效adsnese-auto-ad-5.jpg-Adsense 自動廣告優化心得想要看實驗成效的話,隨時可在 Adsense 後台 → 選單 → 最佳化 → 實驗,選擇進行中的那個實驗即可看到。 3. 終止實驗adsnese-auto-ad-6.jpg-Adsense 自動廣告優化心得上圖是我剛建立的實驗,所以沒有任何數據。
  • 如果對數據不滿意,隨時可按「保留原始版本」,即可終止實驗
  • 如果對數據滿意,隨時可按「套用變化版本」,網站就會正式 100% 執行自動廣告

三、自動廣告設定

1. 調整自動廣告設定沒有進行實驗,也可直接啟用「自動廣告」功能,操作方式為 Adsense 後台 → 選單 → 廣告 → 總覽 adsnese-auto-ad-7.jpg-Adsense 自動廣告優化心得選擇要執行的網域,按右方的「編輯」圖示,進入設定畫面。 adsnese-auto-ad-8.jpg-Adsense 自動廣告優化心得除了在右方「自動廣告」頁籤,可啟用「自動廣告」,上圖「廣告格式」頁籤展開後,可設定所有「自動廣告」的格式選項。 adsnese-auto-ad-9.jpg-Adsense 自動廣告優化心得
  • 如果啟用了「網頁內廣告」,左邊可看到預覽效果。
  • 上圖為預設的手機版預覽畫面,如果是自動產生的廣告,會有「自動廣告範例」字樣
  • 還可按上方的「網頁版」圖示,來看不同版面的廣告預覽效果
設定完畢後,按右下的「套用到網站」即可。 2. 排除特定廣告位置如果不喜歡某些自動廣告出現的位置,可以從後台進行移除。如前圖紅框標示的「垃圾桶」圖示,按下後該處的廣告就不會再出現。 adsnese-auto-ad-10.jpg-Adsense 自動廣告優化心得上圖為網頁版的預覽效果,如果不喜歡圖中的橫幅大廣告,可按「垃圾桶」圖示將之移除。 3. 文章頁面設定adsnese-auto-ad-11.jpg-Adsense 自動廣告優化心得後台預覽畫面預設只會顯示首頁效果,實際上文章頁面也是可以設定的。如上圖紅線,可輸入文章頁面網址,令其出現文章頁的預覽效果。 如上圖,文章頁側邊欄那個自動廣告位置很突兀,一樣可按「垃圾桶」圖示將之移除。 4. 排除特定網頁有時我們不希望所有頁面都出現自動廣告,例如業配文章一般不喜歡有過多的廣告,那麼就可設定該頁面不要出現自動廣告。 adsnese-auto-ad-12.jpg-Adsense 自動廣告優化心得如上圖,右方頁籤切換到「網頁排除」,按「管理」即可設定所有不顯示自動廣告的網址。

四、補充說明

此次實驗中發現,客戶的文章內容中無法出現自動廣告,這是很不尋常的狀態,也失去了自動廣告的最大獲利區塊。 剖析後發現客戶文章內容使用的 HTML 碼過於複雜,有可能因此而讓 Adsense 的演算法無法判斷該於何處插入廣告。所以要讓自動廣告正常出現,文章使用的 HTML 碼需越單純越好。
更多 Adsense 相關文章:

如何讓 Win10 徹底停止自動更新

$
0
0
win10-stop-auto-update.jpg-如何讓 Win10 徹底停止自動更新Windows 10 可算是所有 Windows 版本之中最讓我嫌惡的了,但偏偏市面上的筆電也只能配備這個版本。之前為了輸入法問題折騰了很久,記錄在這篇「自然輸入法購買使用心得及許氏鍵盤替代方案」。 Win10 每 2~3 星期就要面對一次自動更新的問題,我的 Acer 筆電還曾自動更新後故障而送修。本篇紀錄 Acer 筆電與 Win10 自動更新的奮鬥過程,及分享最後找到的終極解決方法,想節省時間的讀者可直接跳到「三、完全避免更新的原理」 (圖片出處: pixabay.com)

一、Acer 筆電與 Win10 更新奮戰過程

1. 硬體故障送修這台筆電的型號是 SWIFT 3,買了用沒幾次就在某次自動更新後,鍵盤忽然沒有反應了。因為在保固期自然立即送去維修,等了幾天領回時,說是鍵盤有問題就幫我換了一組全新的鍵盤模組(結果原本鍵盤下方的所有漂亮貼紙都被收回了)。 雖然不瞭解是什麼狀況,但如果是硬體問題,應該沒更新前也會出問題才是吧?會不會是工程師懶得多花時間查問題,發現換一組鍵盤可正常就乾脆結案了?不過也懶得管那麼多,反正鍵盤正常能用是最重要的。 2. 無法正常開機過陣子在某次自動更新後迎來新的里程碑──無法正常開機,螢幕會顯示「正在更新系統,請稍後...」之類的訊息,但跑了很久會自動重新開機,然後繼續同樣的訊息鬼打牆,永遠進不了 Windows。終於在一個多小時後,我受不了直接把筆電強制關機。 由於送修要等好幾天,不如自己先試著修看看。網路上查到 Acer 筆電開機時進入系統還原選單介面的熱鍵是 ALT + F10,這件事說明書找不到,神奇吧!在選單介面 try & error 好久才找出問題所在: win10-stop-auto-update-1.jpg-如何讓 Win10 徹底停止自動更新上圖是進入選單後的畫面,選擇「使用另一個作業系統」 win10-stop-auto-update-2.jpg-如何讓 Win10 徹底停止自動更新測試幾次才發現,「Windows 10」是可正常開機的,而「Windows Rollback」則會進入鬼打牆狀態。 結論為,Win10 自動更新後不知為何,筆電會自動跳到「Windows Rollback」,只要按上圖底部「變更預設值」,將開機作業系統改為「Windows 10」就正常了。 逃過一劫後,趁著目前還能開機,趕緊將筆電 C 槽及重要工作資料完整備份、並設定還原點,以免哪天被自動更新完還不知道會發生什麼事。 3. 還原 Win10果不其然,之後歷經幾次 Windows 自動更新,真的發生了更嚴重的事故,不是開機進入還原選單介面改改設定就好,而是真的再也開不了機了! 雖然早已有備份算是有恃無恐,但還原 C 槽及所有重要資料也是得耗費不少時間,難不成得每幾個禮拜就折騰一次,用 Windows 10 豈不是找最罪受嗎? 相信問題癥結大家都很清楚,只有徹底讓 Win10 不能自動更新才能終止災難,以下來看看我做了哪些努力。

二、各種關閉自動更新教學

網路可找到的教學文章真是琳瑯滿目,讀了無數篇後看到重複的內容都快背起來了,然而要驗證是否有效都得等到 2~3 個禮拜後才能知道。 歷經數月後我必須說,這些技巧在當時應該都很厲害,也都曾經有效,但 Windows 官方也都查得到這些內容,那麼 Windows 工程師在不願意使用者關閉自動更新的前提下,每次執行自動更新時就可能植入新的系統程式碼,讓這些網路上的手法一一失效。 因此我可以很負責任的說,在 2021 年中的時間點、我的 Acer 筆電,以下這些熱門教學文章都是沒有任何作用的:

三、完全避免自動更新的原理

雖然過去的努力都失敗了,但不代表這件事沒有終極解法,很可能只是我下的關鍵字不對、問的問題不正確。 在爬文過程中,忘了在哪個討論區的推文找到靈感,有人提到「不讓 Windows 自動更新的原理,就是不讓系統連到更新伺服器。」這就對了!有了正確關鍵字相信答案很快就呼之欲出。 搜尋到了這篇「Win10這幾天莫名其妙自動更新...」,這是 Microsoft 官方社群,在茫茫留言之中,我爬到了官方社群小編的回答,說明了如何關閉自動更新,這樣的官方認可的作法,應該再也不會錯了吧,以下引用小編發言內容:
如果需要關閉自動更新,論壇這邊的辦法是更改更新檢查伺服器, 將下面内容拷貝到文本保存,副檔名更改為 .reg 之後右鍵點擊進行使用。 Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate] "WUServer"="127.0.0.1" "WUStatusServer"="127.0.0.1" "UpdateServiceUrlAlternate"="127.0.0.1" [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU] "UseWUServer"=dword:00000001 如果以後需要更新,可以Windows+R 輸入 regedit 找到 HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate 將幾碼清理掉
這原理很容易理解,把微軟的更新伺服器改成 127.0.0.1 自然找不到檔案可以更新了。 完成以上動作後,靜靜的過了 2~3 個星期,果然關機時再也沒出現「安裝更新並關機」的字樣了。災難結束,哈雷路亞!
更多 相關文章:

Facebook 帳號被停權復權全記錄

$
0
0
fb-account-suspension.jpg-Facebook 帳號被停權復權全記錄經營許久的「Blogger 社團」今年曾發生一件慘劇,因為我的 FB 帳號被停權,導致無論是 FB 粉絲頁、社團,都無法進入後台。以往只從新聞或討論區看到經營多年粉絲頁被盜走的案例,這次可是親身體會了一回這樣的痛苦。 然而 FB 帳號停權這樣的事要發生在我身上,才是更離奇的事,因為我根本就很少使用 FB,原因大致是這樣:
  • 幾年前寫過「SEO 紅利還剩多少空間可以操作?」,說明了 FB 紅利早已結束
  • 由於使用者太多了,現在把時間花在 FB 上是一件 CP 值極低的事,你得拼命貼文才能搶得到低的可憐的觸擊率
  • 比較有價值的部分是 FB 社團,因為只有 FB 社團可以無視觸擊率。如果你經營的社團具有專業內容、高價值的資訊,會啟用通知的社員就多,那麼投入精力在這樣的社團 CP 值才夠
  • 所以追蹤者不多的 FB 個人帳號,我已經不太發佈貼文了,可以說是浪費時間
那麼為何很少使用 FB,只經營特定領域社團,這樣帳號還會被停權呢?本篇是我尋找答案的過程記錄。 (圖片出處:pixabay.com)

一、FB 常見停權原因

首先需要瞭解為何會被 FB 停權,這是官網文件「停用帳號」的相關內容,會被停權的常見原因為:
  • 張貼違反 Facebook 使用條款的內容 → 很少使用 FB,確定不會是此原因
  • 使用假名 → 我使用「英文稱謂」,不確定是否為此原因
  • 冒充他人
  • 持續在 Facebook 上做出不被允許、違反《社群守則》的行徑 → 不可能,原因同第1點
  • 基於騷擾、廣告宣傳、推銷或其他我們不允許的行為目的而與他人聯繫 → 不可能,原因同第1點
下面是停權時,收到的 FB 通知郵件: fb-account-suspension-1.png-Facebook 帳號被停權復權全記錄沒有明確說明到底違反了什麼社群守則,所以無法知道明確原因。 爬到了這篇文章「fb被停權至帳號恢復過程全紀錄」,受害者貼出了 FB 寄給他的郵件內容,指出 FB 帳號必須使用本名。 根據這個案例,雖然我沒使用中文名稱,而是使用英文名稱,但我的停權通知並未提到使用假名、或冒充他人的敘述,所以我判斷可以排除這兩個因素。 至於我到底違反了什麼 FB「社群守則」,只好慢慢查證推敲。 更多的 FB 停權案例,可參考這篇整理「FB帳號停用封鎖72小時搶救與預防」。

二、FB 停權處理方式整理

1. 官網說明依照官網文件「停用帳號」的指示,點擊以下連結進行: 2. 注意事項這篇「FB停權驚心動魄三天心情紀錄」的操作說明與我的經驗類似,可參考該篇的重點:
  • 依FB指示提供身份證明
  • 不要立刻申請新帳號
  • 每一天發一封EMAIL給FB
我當初也是急著申請新帳號,結果後來通通被砍,所以不申請新帳號是對的。 而我提供身份證明文件、發郵件給 FB 沒幾天後,帳號就恢復了,所以證明只要確定沒有做出違反 FB 的事情,依照這篇流程很快就能拿回帳號。

三、被停權原因推測

誠如本篇開頭提到的,很少使用 FB 的我,自然非常有自信不會做出違反 FB 規範的事,如果說被人檢舉的話,也得有相關的貼文、留言可以檢舉吧!然而 FB 抓違規更多的是靠 AI、演算法,偵測到可疑行為模式後自動舉發。那麼究竟是我的什麼行為會被 AI 判定為違規呢?還是得查個明白。 1. Chrome 套件思考了一下出事前後曾發生過什麼事,似乎比較有關連的是,有個 FB 相關的 Chrome 套件被下架了,那個實用套件可以即時顯示 FB 的通知數,不必進入 FB 才看到,但安裝該套件自然需要提供 FB 帳號的授權。 而該套件被下架,說不定代表有惡意程式碼,也許 Google 發現該套件做的壞事,會不會很多人的 FB 帳號權限被用來做什麼事呢? 2. 不明活動記錄恢復帳號後,不經意從我的 FB 活動記錄看到了以下內容: fb-account-suspension-2.jpg-Facebook 帳號被停權復權全記錄這真是嚇壞我了,我根本不知道 "孟波" 是誰,也沒有回應上圖匿名者的留言。這也就是說,有人取得了我的 FB 權限做了這些事,但並沒有動我的帳號密碼,我還是可以用原本的密碼登入。 3. 歸納原因看來帳號被停權的原因找到了,兇手就是 Chrome 套件,取得了我的 FB 帳號權限後,利用我的身份持續不斷進行按讚、留言,很有可能是惡意的 Chrome 套件將帳號權限賣給了公關公司,而我的帳號變成了 AI 機器人供其操作。 很可能我的不明活動出現在各種不同的 IP 被偵測到異常,也可能活動頻率超出 FB 限制,被 FB 判定為濫用資源,所以就被停權了。

四、後續注意事項

1. 更改密碼瞭解真正原因後,趕緊更改我的 FB 密碼,這樣惡意程式得重新取得授權,如此就不用擔心帳號權限被拿走了。 自此之後,查閱活動記錄時就沒再看到奇怪的行為了。 2. 小心 FB 授權網站現在有許多免費線上服務,登入、建立帳號時提供 FB 帳號的管道,屆時就得將 FB 帳號授權給這些服務。 有了本篇的被停權經驗,以後有任何授權 FB 帳號的舉動之前,最好先確定該網站是值得信任的,並仔細檢視要求授權的內容,否則 FB 帳號很可能拿去做我們不知情的行為。 3. 定期檢查活動記錄就算 FB 授權的網站或服務都值得信任,也不該完全相信這些網站都不會被駭、或發生個資外洩,所以還是得定期檢查自己的 FB 活動記錄,看看有沒有不是自己做出的行為,以免不小心被停權了。 4. 粉絲團、社團建立多個管理員這是最重要的一個動作,如果粉絲團、社團只有一個管理員,而剛好該帳號又被停權了,那麼整個粉絲團、社團等於廢了。 為了防止這樣的事情,建議:
  • 把多個家人帳號通通加入粉絲團、社團成為管理員
  • 每多一個帳號也會多一個破口,所以每個管理員帳號都需要使用兩階段驗證,以保安全
更多 Facebook 相關文章:

Blogger 圖片大瘦身!官方提供密技轉換成 WebP 格式

$
0
0
Blogger 圖片大瘦身!官方提供密技轉換成 WebP 格式前陣子 FB 的 Blogger 社團分享了一篇「Blogger 圖片無痛轉換 WebP」,原來 Blogger 圖片網址加上特定參數後,就能直接轉換成 WebP 格式,檔案得以大瘦身,圖片載入時間縮短不少。 這對圖片為主的 Blogger 部落格站長可說是一大幅音,例如美食、旅遊等主題,網頁載入時需要花費很多時間在圖片讀取上,現在改成了 WebP 格式,相信可以大大提升使用者體驗。 順帶提件事,由於幾個月前 Blogger 上傳圖片的網址格式改了,若要轉換 WebP 格式,新、舊型態的網址格式都需要知道如何處理。 本篇除了介紹 WebP、說明此格式如何轉換,也會對此官方功能進行實測,以瞭解圖片改善程度為何,並說明所有相關該注意的地方。 (圖片出處: pexels.com)

一、什麼是 WebP

WebP 是一種新的圖片壓縮演算法,詳細說明可參考維基頁面「WebP」。就像以前的 .png、.jpg 圖檔格式,副檔名 .WebP 也是新的圖檔格式。由於格式比較新,壓縮比更大,一開始不一定所有瀏覽器都支援,最早是 Google 在 2010~2012 年從自家瀏覽器 Chrome 開始推廣。 時至今日九成以上的瀏覽器都已經支援 WebP,那麼現在開始全面使用 WebP 圖檔也是一個很好的時機點,不怕使用者瀏覽器看不到我們網站的圖片。

二、新舊圖片網址格式差異

進入主題之前,最好先了解 Blogger 後台上傳的圖片,網址格式為何: 1. 舊網址格式參數請參考「Blogger 上傳的圖片網址參數」,說明了一些基本的參數修改方法。 這裡只舉例最基本的、後台上傳後會產生的舊網址格式: https://1.bp.blogspot.com/-G607thP7cWc/XDg22TxSSUI/AAAAAAAAYLc/bWQMrxhgneEBSKKiJ3TCuqYnxpcAyofVACLcBGAs/s1600/girl.jpg紅字 s1600 代表原圖尺寸,之後修改會用到。 更多網址格式參數可參考這篇「Blogger 圖片 URL 參數2. 新網址格式參數現在 Blogger 後台上傳圖片產生的網址格式,「撰寫模式」與「HTML模式」長得並不一樣,以下為範例: https://blogger.googleusercontent.com/img/a/AVvXsEiOVkeZUJSFIfRlvL4UuHGyi8f2NhNYuzBXzD_B_B-d-Qzd1WEsa0EqS9KTTS61R2l7A2QdU-ScHK4m6EJRWcPGDC1w1nRCWRPqvtYh-lFXlndICqDQ9NKTk9oEr2nKvN4knhELVJtaUOlRUqnGz2bCzq5uLafGBh6HzLFLCJEfUtAK7Y24aqH6FaGfsA=s16000
  • 上圖為「撰寫模式」下的格式,多了紅字參數 "=s16000",代表是原始尺寸
  • 如果是「HTML模式」,則沒有紅字參數,但一樣是原始尺寸
  • 如果要改變尺寸參數,方法就是在圖片網址最後加上 "=" 及參數即可

三、新舊圖片轉換為 WebP

有了前面的概念之後,現在可以說明如何轉換為 WebP 格式: 1. 加上 -rw 參數原理非常簡單,就是在新、舊圖片網址格式中,圖片參數的地方,加上字串 "-rw" 即可。 然而這件事我找遍了網路,都沒有任何官方文件提及,不曉得是不是 Google 還在等 WebP 真正一統江湖之時,才會正式放入文件。 我只找到了一個疑似 WebP 開發團隊工程師留言的討論串「Why does Google Images Service convert my WEBP images into JPG when serving them?」,代表早在 2013 年 Google 就以經釋出 "-rw" 這個轉換參數了,留言的 Sebastian Kreft 還表示會回報使用者提出的 bug,這也是我猜測他是開發團隊相關人員的原因。 2. 舊圖片網址轉換為 WebP參照前面的舉例,舊圖片網址轉換為 WebP 的範例如下: https://1.bp.blogspot.com/-G607thP7cWc/XDg22TxSSUI/AAAAAAAAYLc/bWQMrxhgneEBSKKiJ3TCuqYnxpcAyofVACLcBGAs/s1600-rw/girl.jpg3. 新圖片網址轉換為 WebP參照前面的舉例,新圖片網址轉換為 WebP 的範例如下: https://blogger.googleusercontent.com/img/a/AVvXsEiOVkeZUJSFIfRlvL4UuHGyi8f2NhNYuzBXzD_B_B-d-Qzd1WEsa0EqS9KTTS61R2l7A2QdU-ScHK4m6EJRWcPGDC1w1nRCWRPqvtYh-lFXlndICqDQ9NKTk9oEr2nKvN4knhELVJtaUOlRUqnGz2bCzq5uLafGBh6HzLFLCJEfUtAK7Y24aqH6FaGfsA=s16000-rw

四、圖片轉換效果實測

為了加快網頁載入速度,我常常需要教育客戶壓縮圖片的重要性,以及建議用什麼軟體進行壓縮、使用的壓縮百分比等等。若是偷懶沒花時間壓縮 JPG 檔,肥大的圖檔載入時間是很可怕的。 而此次的 WebP 格式轉換,客戶提出一個很好的問題:「jpg 圖片是否不用壓縮,用 WebP 格式就好?」,因此以下就來進行各種測試: 1. JPG 未壓縮 vs WebP這張戴墨鏡的少女,使用 CC0 免費圖庫搜尋引擎的「StockSnap 圖庫」搜尋。 圖片尺寸 960x628,未壓縮 JPG 原始檔案為 237 kb: Blogger 圖片大瘦身!官方提供密技轉換成 WebP 格式使用 -rw 參數改成 WebP 後檔案為 43 kb: Blogger 圖片大瘦身!官方提供密技轉換成 WebP 格式2. JPG 壓縮 80% vs WebP以下使用同一張圖片,經 JPG 壓縮 80%,檔案大小 52 kb: Blogger 圖片大瘦身!官方提供密技轉換成 WebP 格式使用 -rw 參數改成 WebP 後檔案為 40 kb: Blogger 圖片大瘦身!官方提供密技轉換成 WebP 格式3. PNG vs WebP這張音樂演奏圖片的 PNG 透明圖,來自 ICON 免費素材搜尋引擎的「PngTree 圖庫」搜尋。 圖片尺寸 1000x1000,PNG 原始檔案為 727 kb: Blogger 圖片大瘦身!官方提供密技轉換成 WebP 格式使用 -rw 參數改成 WebP 後檔案為 611 kb: Blogger 圖片大瘦身!官方提供密技轉換成 WebP 格式4. PNG 轉 JPG 80% vs WebP以下使用同一張圖片,經 JPG 壓縮 80%,檔案大小 93 kb: Blogger 圖片大瘦身!官方提供密技轉換成 WebP 格式使用 -rw 參數改成 WebP 後檔案為 76 kb: Blogger 圖片大瘦身!官方提供密技轉換成 WebP 格式5. 測試結果經由以上測試可以得出以下推論:
  • 上傳後的(JPG/PNG)圖片官方似乎會進行加工,檔案大小與原始略有差異,有可能變大也可能變小,請自行下載可看出差異。
  • Blogger 官方轉換後的 WebP 圖片效果不錯,跟原圖相比完全看不出差別
  • Blogger 官方 WebP 壓縮後的檔案已經比 JPG 壓縮 80% 還小
  • 所以上傳 JPG 之前的確可以不必另外再壓縮,可以交由 Blogger 幫我們轉換為 WebP,無形中等於我們省下不少處理圖檔的時間!
  • 若 PNG 是透明圖檔,使用 JPG 壓縮後會破壞透明圖
  • PNG 轉換成 WebP 後仍可維持透明圖
6. 補充說明
  • GIF 檔:根據這個 FB 社團討論串「BLOGGER 圖片無痛轉換 WEBP」,GIF 檔轉換為 WebP 格式使用的參數為 "-rwa"。
  • WebP 檔:Blogger 上傳 WebP 檔的話不會有作用,仍然會以 JPG 顯示。依照同樣規則,必須額外加上參數 "-rw" 才能顯示 WebP格式。

五、總結

  • 根據本篇的實測結果,Blogger 使用者將來可以節省圖檔壓縮的流程,直接上傳 JPG/PNG。圖片網址加上參數 "-rw" 後就能轉換為最佳壓縮比的 WebP 格式
  • 雖然知道了這樣的密技,新文章的圖片都可以這樣處理,但整個網站範本各處的圖片,所有小工具產生的縮圖(例如相關文章等等),以及所有舊文章的圖片,也要一個個手動處理。
  • 如果網站有幾百篇、數千篇文章時,就不太可能手動修改,需要請前端工程師處理。
  • 那麼順帶一提,如果覺得自己網站圖片量龐大,想要處理新舊文章及網站各處的圖片,提升網頁載入速度、進行圖片瘦身的工程,可以再與本站聯繫。
更多「網站效能」相關文章:

如何將 G Suite 郵件匯出到 Gmail 帳號

$
0
0
如何將 G Suite 郵件匯出到 Gmail 帳號前幾天 Google 宣布以下「公告」:
如果您使用的是舊版 G Suite (免費版),則必須升級至 Google Workspace 付費訂閱,才能繼續使用服務。自 2022 年 7 月 1 日起,Google 將停止供應舊版 G Suite (免費版)
此公告的重點如下:
  • 如要保留服務和帳戶,需升級至 Google Workspace,才不會造成服務中斷
  • 升級後,可享有至少到 2022 年 7 月 1 日的免付費優惠
  • 2022 年 7 月 1 日之後如未付費,Google Workspace 訂閱將遭到停權
  • 停權 60 天後,將無法再使用 Google Workspace 核心服務,例如 Gmail
這項變更帶來的影響非常之大,如果你的 G Suite 帳號用來處理商業事務,重要往來郵件都在這個帳號裡面的話,就必須考慮付費升級,否則生意都不用做了。 若一直不理會這件事的話,最終停權後會導致該帳號 Gmail 無法使用、不能收發郵件,甚至想要將郵件匯出都沒辦法。 本站也有一個郵件使用 G Suite 自訂網域功能,由於使用量沒那麼大,付費的充足要件還不太夠。那麼如果不打算付費的話,無論將來做什麼決定,目前第一要務就是將 G Suite 帳號的郵件匯出備份到他處,以免將來來不及處理。 本篇會分享 G Suite 匯出郵件到 Gmail 帳號的心得,並說明一些郵件自訂網域替代方案該考慮的地方。 (圖片出處: pexels.com)

一、搬到免費自訂網域信箱服務

G Suite 郵件該搬到哪裡的確很頭痛,以下提供一些替代方案,及判斷的思路。 1. 免費自訂網域信箱根據「阿力獅 FB 社團討論串」,推薦的免費自訂網域信箱有:
  • ZOHO Mail:不需要 SMTP、POP3、IMAP4 等傳統電子郵件通訊協定
  • Yandex Mail:俄國,需要 SMTP、POP3、IMAP4 等傳統電子郵件通訊協定
2. Improvmx 信箱別名服務根據這篇「讓你用個人Gmail也可以擁有免費又專業的自訂網域信箱」,介紹了一個免費的 Improvmx 信箱別名服務:
  • 不需搬到其他免費郵件服務,可使用現有的 Gmail 進行設定
  • 一個網域有 5 個郵件帳號的免費額度
  • 一天有 500 封郵件的免費額度
3. 自訂網域免費信箱的考量直接說結論,我認為 G Suite 郵件要搬走的話,第一首選還是搬到其他 Gmail 帳號,原因及需要的考量點如下:
  • 其他服務是否有中文介面?功能、操作是否能快速上手?
  • 垃圾郵件過濾功能是否能比得上 Gmail?(我個人使用過的 Yahoo、Hinet 郵件垃圾信實在慘不忍睹)
  • 將來這些免費服務如果開始收費,且費用比 Google Workspace 還高時,是否知道如何把郵件從該服務搬走?
如果以上這幾點沒有 100% 把握的話,我認為放在 Gmail 才是最好的決定。 同時前面提到的 Improvmx 服務可解決 Gmail 自訂網域信箱的問題,之後我也會分享一篇如何不靠第三方服務,直接在 Gmail 郵件設定自訂網域的技巧。

二、Gmail 匯出郵件流程

這裡先說明一下 Gmail 匯出郵件的流程與原理,G Suite 郵件本質上也是 Gmail 郵件,但細部設定會不一樣,之後再詳細說明 G Suite 郵件如何處理,若不想看這一段也可直接跳到「三、G Suite 郵件匯出到 Gmail 帳號流程」。 Gmail 匯出操作步驟請參考官網文件「查看其他帳戶的電子郵件」:
  • 步驟 1:(這裡設定要匯出的帳號)
    • 在其他帳戶中變更設定 → 其他 Gmail 帳戶,按照步驟操作即可
  • 步驟 2:(這裡設定要匯入的帳號)
    • 變更 Gmail 設定 → 按照步驟操作
    • 做完就會發現輸入 G Suite 帳號密碼無效,也連不上郵件伺服器,因為 G Suite 要填入的設定完全不一樣
  • 伺服器拒絕 POP3 存取:
    • 找到這個區塊,查看到連不上郵件伺服器時要如何處理,跟 G Suite 有關的處理方式列在下面
    • 如果 G Suite 帳號使用兩步驟驗證,那麼輸入的密碼必須是「應用程式密碼」
    • G Suite 帳號「POP 伺服器」部分中輸入 pop.gmail.com,然後將通訊埠設為 995。
    • 還是無法登入帳戶,建議開啟「低安全性應用程式存取權」,可能還必須「停用安全碼或人機驗證功能

三、G Suite 郵件匯出到 Gmail 帳號流程

以下根據前面官網文件提到的操作步驟,以及錯誤排除方法,來展示 G Suite 郵件匯出到 Gmail 帳號流程。 1. 設定要匯出的 G Suite 帳號如何將 G Suite 郵件匯出到 Gmail 帳號
  • 在電腦上登入匯出郵件的 G Suite 帳戶
  • 按右上方「設定」圖示 →「查看所有設定」
  • 按「轉寄和 POP/IMAP」分頁標籤
  • 在「POP 下載」部分中,選取「對所有郵件啟用 POP 功能」
  • 在「當郵件以 POP 存取後」旁邊選取「在收件匣保留 Gmail 的副本」
  • 按底部的「儲存變更」
2. 設定要匯入的 Gmail 帳號
  • 在電腦上登入用來匯入郵件的 Gmail 帳戶
  • 按右上方「設定」圖示 →「查看所有設定」
  • 按「帳戶和匯入」分頁標籤
  • 「查看其他帳戶的郵件」→ 按「新增郵件帳戶」
  • 輸入 G Suite 電子郵件地址 → 按「繼續」
  • 從我的其他帳戶匯入電子郵件 (POP3) → 按「繼續」
如何將 G Suite 郵件匯出到 Gmail 帳號參考上圖:
  • 使用者名稱:填入 G Suite 電子郵件地址
  • 密碼:填入 G Suite 帳號密碼(但很有可能失敗,處理方法之後說明)
  • POP 伺服器:填入 pop.gmail.com
  • 通訊埠:選 995
  • 勾選「擷取郵件時,一律使用安全連線 (SSL)」
  • 按「新增帳戶」
如果「新增帳戶」成功的話,之後的選項很容易判斷,不用特別說明。 失敗的話會轉圈圈等待很久,並顯示「伺服器拒絕存取」之類的提示文字,以下進行錯誤排除。 3. 處理「伺服器拒絕存取」
  • 兩階段驗證:
    • 如果你的 G Suite 帳號使用兩步驟驗證,那麼輸入的密碼必須是「應用程式密碼」而非帳號密碼
    • 請依照官網說明「使用應用程式密碼登入帳戶」→ 依照步驟取得應用程式密碼後,在前面的步驟「密碼」之處輸入即可
  • 低安全性應用程式存取權:
    • 如果取得「應用程式密碼」有困難的話,建議暫時先取消兩階段驗證,等郵件都移轉成功後,再恢復兩階段驗證
    • 同時官方建議開啟「低安全性應用程式存取權」,這樣前面的步驟「密碼」之處,輸入 G Suite 帳號密碼就能成功
4. 等待郵件匯入以上設定成功之後,接下來需要等待很長的時間,如果郵件很多的話,有可能要幾個小時才能全部匯入。 不放心的話可以隔一段時間到收件匣查看,會看到郵件慢慢匯進來的過程。

四、自訂網域

Gmail 郵件自訂網域的作法,本篇已經有一個替代方案。但是依靠第三方免費服務總是難以讓人放心,什麼時候服務會收起來都很難說。 下一篇會再詳細說明 Gmail 郵件如何設定,可以模擬出自訂網域的效果,讓寄信、收信都能顯示自訂網域郵件網址。
更多 Gmail 相關文章:

Gmail 自訂網域的技巧﹍寄信與收信顯示更專業的商務郵件信箱

$
0
0
Gmail 自訂網域的技巧﹍寄信與收信顯示更專業的商務郵件信箱上一篇「如何將 G Suite 郵件匯出到 Gmail 帳號」提到 G Suite 即將關閉,如果沒有付費升級的準備,首要之務是將郵件搬到另一個 Gmail 帳號。 那麼原本自訂郵件網域的功能該如何處理呢?本篇會說明如何在寄信、收信時,都能顯示自己網域的郵件網址,而非看起來較不專業的 Gmail 郵件網址。 (圖片出處: pixabay.com)

一、操作的原理

1. 收件者顯示自訂網域通常網址代理商都會提供郵件轉址的功能,有可能需要設定郵件 DNS,這部分請找找網址代理商的操作說明。 如果覺得麻煩的話,推薦使用「Google Domains」,後台可以無腦設定,不需了解背後原理。 設定郵件轉址後,可將含有自訂網域的電子郵件信箱位址,轉信到 Gmail 郵件信箱。那麼客戶收到我們郵件時,「收件者」資訊欄可顯示我們網域的專屬電子郵件信箱。 2. 寄件者顯示自訂網域然而實際上,我們並非真正擁有自訂網域的專屬電子郵件信箱,所以從 Gmail 寄出信件時,「寄件者」資訊欄還是會顯示 Gmail 郵件信箱。 這部分 Gmail 提供了「在 Gmail 中使用別名傳送電子郵件」功能,只要按著步驟操作,就能在「寄件者」資訊欄選擇顯示自訂網域的電子郵件信箱位址。

二、Google Domains 郵件轉址

以下示範利用「Google Domains」進行郵件轉址:
  • 首頁 → 選擇網域 → 電子郵件
  • 按「新增電子郵件別名」→ 輸入「別名電子郵件地址」→ 輸入現有收件者郵件地址 → 新增
Gmail 自訂網域的技巧﹍寄信與收信顯示更專業的商務郵件信箱如上圖,輕輕鬆鬆完成設定。 請注意,一定要先完成以上「郵件轉址」的設定,才能繼續設定 Gmail 別名功能,順序不可顛倒,否則之後會收不到驗證碼通知信

三、Gmail 使用別名傳送郵件

以下參照「在 Gmail 中使用別名傳送電子郵件」進行示範,將原本的 waynefu.g@gmail.com改為 contact@wfublog.com1. 產生應用程式密碼Gmail 自訂網域的技巧﹍寄信與收信顯示更專業的商務郵件信箱Gmail 自訂網域的技巧﹍寄信與收信顯示更專業的商務郵件信箱
  • 「選取應用程式」→ 選擇「郵件」
  • 「選取裝置」→ 選擇「其他(自訂名稱)」
Gmail 自訂網域的技巧﹍寄信與收信顯示更專業的商務郵件信箱輸入自訂網域 → 按「產生」 Gmail 自訂網域的技巧﹍寄信與收信顯示更專業的商務郵件信箱記下產生的黃底 16 字元密碼,之後會用到2. 新增電子郵件別名
  • 在電腦上登入 Gmail 帳戶
  • 按右上方「設定」圖示 →「查看所有設定」
  • 按「帳戶和匯入」分頁標籤
  • 「選擇寄件地址」→「新增另一個電子郵件地址」
Gmail 自訂網域的技巧﹍寄信與收信顯示更專業的商務郵件信箱請依照上圖進行設定,輸入寄件者名稱、自訂網域郵件信箱、勾選「視為別名」 Gmail 自訂網域的技巧﹍寄信與收信顯示更專業的商務郵件信箱請依照上圖進行設定:
  • 「SMTP 伺服器」輸入 smtp.gmail.com
  • 「通訊埠」選 587
  • 「使用者名稱」欄位中輸入 Gmail 郵件
  • 「密碼」輸入前面取得的 16 字元「應用程式密碼」
  • 勾選「採用 TLS 的加密連線」
  • 按「新增帳戶」
3. 確認地址Gmail 自訂網域的技巧﹍寄信與收信顯示更專業的商務郵件信箱接著出現上圖畫面,前面有設定「郵件轉址」的話,現在就可在 Gmail 信箱收到一封驗證碼信件,填入上圖按「驗證」即可。 4. 顯示別名Gmail 自訂網域的技巧﹍寄信與收信顯示更專業的商務郵件信箱
  • 回到設定畫面,可看到「選擇寄件地址」這裡,已經多了剛剛設定的自訂網域郵件信箱 contact@wfublog.com
  • 如紅框處將其改為「預設」,將來「寄件者」欄位都會自動使用這個別名來寄出郵件

四、測試效果

Gmail 自訂網域的技巧﹍寄信與收信顯示更專業的商務郵件信箱來看看自訂網域郵件信箱的效果吧,我設定了兩個 wfublog.com 網域的信箱,彼此互相寄信的效果如上圖,寄信者與收件者不再顯示原本的 Gmail 帳號,而是自訂網域信箱,以後不需依賴第三方服務就能實現這個效果了。 同時本篇的解決方案比前一篇提到的免費服務 Improvmx 還好(免費額度為設定 5 個郵件),因為 Google Domains 可以設定郵件轉址的上限為 100,對於一般部落格站長的使用是綽綽有餘了。
更多 Gmail 相關技巧:

Blogger 最新文章 V3﹍相容新舊圖片網址 + WebP 格式

$
0
0
去年底(2021) Blogger 更改了圖片網址格式,詳情可參考「Blogger 圖片大瘦身!官方提供密技轉換成 WebP 格式」→「二、新舊圖片網址格式差異」。 雖不知官方為何要這麼做,但此舉卻是影響很大,許多需要顯示縮圖的工具都可能異常,也包括以前製作的「Blogger 最新文章 V2」。 此次更新的最新文章 V3 版,除了修正新舊圖片網址格式的相容性,也順便加入了 WebP 圖檔格式轉換功能,讓圖片載入速度更快。 (圖片出處: pexels.com)

一、版面示意圖

基本上版面沒有變動,直接放前一版的示意圖: blogger-recent-post-custom-thumbnail-Blogger 最新文章 V2﹍任意尺寸縮圖 + HTTPS

二、安裝程式碼

如果安裝過舊版本的話,先刪除原本的小工具,按以下步驟重新新增一個「HTML/JavaScript」小工具即可。 如果沒有安裝過的話,請到後台 → 版面配置 → 新增小工具 → 選擇「HTML/JavaScript」→ 填入標題、以及以下程式碼: <script src='//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js'></script><div id="rp3_area"></div> <div id="rp3_info"><a href="//www.wfublog.com/2022/02/blogger-recent-post-v3.html">ⓦ Recent Posts</a></div> <script> var rp3 = { startIndex: 1, // 從第幾篇最新文章開始 showPost: 5, // 每頁顯示幾篇文章 width: 108, // 縮圖寬度 height: 72, // 縮圖高度 noImage: "//3.bp.blogspot.com/-4JBpCsqL6a4/Vh3ciHoReQI/AAAAAAAAMq8/WMHCDhvnj4M/s1600-rw/wfublog-post.jpg", // 無縮圖的預設圖片 enableWebp: true, // 圖片不想轉換為 webp 格式請改為 false showSummary: true, // 不需要顯示文章摘要請改為 false previewLength: 60, // 預覽文章摘要的字數 summaryLength: 120, // 顯示文章摘要的字數 showPostTotal: true, // 不需要顯示網站總文章數請改為 false nextLogo: "", // 下一頁圖示 prevLogo: "", // 上一頁圖示 openLogo: "", // 展開摘要圖示 closeLogo: "", // 收合摘要圖示 readMore: "繼續閱讀 »", // 繼續閱讀提示字串 serialText: "編號", totalText: "總共:" }; rp3.switchPage=function(r,e,t){var a=rp3.showPost,n=rp3.showSummary,o=r>a,p=$("#rp3_postIndex"),s="",i=n?"25%":"50%";r=o?a:r,n&&(s+="<a href='javascript:' class='rp3_openAll' style='width:"+i+"' title='摘要全部展開'>"+rp3.openLogo+"</a><a href='javascript:' class='rp3_closeAll' style='width:"+i+"' title='摘要全部收起'>"+rp3.closeLogo+"</a>"),e>rp3.startIndex?s+="<a class='rp3_prevPage' style='width:"+i+"' href='javascript:' title='上一頁'>"+rp3.prevLogo+"</a>":s+="<span class='rp3_prevPage' style='width:"+i+"'>"+rp3.prevLogo+"</span>",s+=o?"<a class='rp3_nextPage' style='width:"+i+"' href='javascript:' title='下一頁'>"+rp3.nextLogo+"</a>":"<span class='rp3_nextPage' style='width:"+i+"'>"+rp3.nextLogo+"</a>",$("#rp3_switchPage").html(s),$(".rp3_openAll").click(function(){$(".rp3_summary, .rp3_openLogo").hide(),$(".rp3_content, .rp3_closeLogo, .rp3_readMore").show()}),$(".rp3_closeAll").click(function(){$(".rp3_content, .rp3_closeLogo, .rp3_readMore").hide(),$(".rp3_summary, .rp3_openLogo").show()}),$("a.rp3_prevPage").click(function(){rp3.init(e-a)}),$("a.rp3_nextPage").click(function(){rp3.init(e+a)}),p.length&&p.html(rp3.serialText+" "+e+"-"+(e+r-1)+", "+rp3.totalText+" "+t)},rp3.main=function(json){var feed=json.feed;if(feed.entry){var nFetch=feed.entry.length,nIndex=parseInt(feed.openSearch$startIndex.$t),nTotalPost=parseInt(json.feed.openSearch$totalResults.$t),total=rp3.showPost>nFetch?nFetch:rp3.showPost,width=rp3.width,height=rp3.height,imgPara="w"+width+"-h"+height+"-n",summaryLength=rp3.summaryLength,previewLength=rp3.previewLength,reg1=/<.*?>/g,html="",j,i,entry,title,preview,summary,pic,link,info;rp3.enableWebp&&(imgPara+="-rw");var _0x4302c5=_0x414d;(function(r,e){for(var t=_0x414d,a=r();;)try{var n;if(504391===parseInt(t(183))/1*(-parseInt(t(185))/2)+parseInt(t(184))/3*(-parseInt(t(193))/4)+-parseInt(t(195))/5*(-parseInt(t(190))/6)+parseInt(t(191))/7*(-parseInt(t(187))/8)+-parseInt(t(181))/9+parseInt(t(186))/10+parseInt(t(179))/11)break;a.push(a.shift())}catch(r){a.push(a.shift())}})(_0x3fb9,504391),eval(function(r,e,t,a,n,o){var p=_0x414d;if(n=function(r){var e=_0x414d;return(r<62?"":n(parseInt(r/62)))+((r%=62)>35?String[e(189)](r+29):r[e(180)](36))},!""[p(188)](/^/,String)){for(;t--;)o[n(t)]=a[t]||n(t);a=[function(r){return o[r]}],n=function(){var r;return p(192)},t=1}for(;t--;)a[t]&&(r=r[p(188)](RegExp("\\b"+n(t)+"\\b","g"),a[t]));return r}('p(1+="<q>",i=0;i<F;i++){p(j=0,3=G.3[i],6=3.6.$t,b=3.b.$t.f(H,"").r(0,I),s=b.k>u?b.r(0,u):b,4=3.v$w?3.v$w.J:7.K,4.L("-x")<0?4=4.f(/y-c/,z):4=4.f(/y-c-x/,z),4=4.f("M:","");j<3.8.k&&"N"!=3.8[j].O;)j++;8=3.8[j].9,1+="<A>",1+="<a 5=\'P\' 9=\'"+8+"\' g=\'h:"+h+"l;\'><Q R=\'"+4+"\' g=\'h:"+h+"l; B:"+B+"l;\'/></a>",1+="<2 g=\'C-S: T-C;\'>",1+="<2 5=\'U\'><a 9=\'"+8+"\'>"+6+"</a></2>",7.V&&(1+="<2 5=\'W\'><d 5=\'X\' 6=\'展開摘要\'>"+s+"... </d><d 5=\'Y\' 6=\'收起留言\'>"+b+"... </d><d 5=\'Z\'><a 5=\'10\' 9=\'D:\' 6=\'展開摘要\'>"+7.11+"</a><a 5=\'12\' 9=\'D:\' 6=\'收起留言\'>"+7.13+"</a></d><14/><a 5=\'15\' 9=\'"+8+"\'>"+7.16+"</a></2>"),1+="</2><2 g=\'17: 18;\'/></A>"}1+="</q>",7.19&&(1+="<2 m=\'1a\'></2>"),1+="<2 m=\'1b\'></2>",$("#E").1(1),7.1c(1d,1e,1f),o="<a 9=\'//1g.1h.1i/1j/1k/1l-1m-1n-1o.1\' 1p=\'1q \' 6=\'1r 最新文章 1s\\n程式設計: 1t 1u\'>&#1v; 1w 1x</a>";1y $e=$("#e");$e.k?$e.1(o):$("#E").1z("<2 m=\'e\'>"+o+"</2>");',62,98,_0x4302c5(194)[_0x4302c5(182)]("|"),0,{})),$(".rp3_text").click(function(r){var e;"rp3_readMore"!=r.target.className&&$(this).find(".rp3_summary, .rp3_content, .rp3_openLogo, .rp3_closeLogo, .rp3_readMore").toggle()})}else $("#rp3_area").html("<div style='text-align: center;'>目前尚無文章!</div>");function _0x414d(r,e){var t=_0x3fb9();return(_0x414d=function(r,e){var a;return t[r-=179]})(r,e)}function _0x3fb9(){var r=["11VOCwOy","4818nntIsd","4062NagNmU","5198610eoQXtn","1992kNJmkk","replace","fromCharCode","1431696veZnXV","2863XgnjXl","\\w+","2216seUmhT","|html|div|entry|pic|class|title|rp3|link|href||summary||span|rp3_info|replace|style|width|||length|px|id||info|for|ul|substr|preview||previewLength|media|thumbnail|rw|s72|imgPara|li|height|word|javascript|rp3_area|total|feed|reg1|summaryLength|url|noImage|indexOf|http|alternate|rel|rp3_pic|img|src|wrap|break|rp3_postTitle|showSummary|rp3_text|rp3_summary|rp3_content|rp3_toggleLogo|rp3_openLogo|openLogo|rp3_closeLogo|closeLogo|br|rp3_readMore|readMore|clear|both|showPostTotal|rp3_postIndex|rp3_switchPage|switchPage|nFetch|nIndex|nTotalPost|www|wfublog|com|2022|02|blogger|recent|posts|v3|target|_blank|Blogger|V3|WFU|BLOG|9446|Recent|Posts|var|after","15gTCuwi","7098993zTdCOK","toString","3264975HBngAB","split"];return(_0x3fb9=function(){return r})()}},rp3.init=function(r){var e="/feeds/posts/summary?start-index="+(r=r||rp3.startIndex)+"&max-results="+(rp3.showPost+1)+"&alt=json-in-script&callback=rp3.main";$("#rp3_area").html("<div style='text-align: center; margin: 20px auto;'><img src='//lh5.googleusercontent.com/-EyVZ0f8J0qQ/UCeEG7aa8nI/AAAAAAAADtY/9sXw53XkYXM/s512/indicator-light.gif'/></div>"),$.getScript(e)},rp3.init(); </script> <style> #rp3_area ul,#rp3_area li{list-style:none;margin:0} #rp3_area li{padding:5px 0;border-bottom:1px solid #eee;text-indent:0;font-size:14px} #rp3_area a,#rp3_info a{text-decoration:none} #rp3_info{float:right;font-size:11px;font-family:helvetica,arial,sans-serif;text-shadow:1px 1px 1px #e6e6fa} #rp3_info a{color:#ccc} .rp3_pic{float:left;margin:0 15px 0 0} .rp3_pic img{margin:0;padding:4px;background:#FFF;box-shadow:0 1px 4px rgba(0,0,0,.3),0 0 40px rgba(0,0,0,.1) inset;-webkit-box-shadow:0 1px 4px rgba(0,0,0,.3),0 0 40px rgba(0,0,0,.1) inset;-moz-box-shadow:0 1px 4px rgba(0,0,0,.3),0 0 40px rgba(0,0,0,.1) inset;opacity:.9} .rp3_pic img:hover{opacity:1} .rp3_postTitle{font-weight:700} .rp3_text{cursor:pointer;margin:5px 0;opacity:.8} .rp3_text:hover{opacity:1} .rp3_toggleLogo{display:none} #rp3_area li:hover .rp3_toggleLogo{display:inline} .rp3_content,.rp3_closeLogo{display:none} .rp3_readMore{display:none;float:right;margin-top:5px;font-size:80%;font-weight:700} #rp3_postIndex{margin:5px 0;text-align:center} #rp3_switchPage{background-color:#eee;margin:5px 0;padding:3px;font-size:20px;line-height:16px} #rp3_switchPage a,#rp3_switchPage span{box-sizing:border-box;display:inline-block;padding:0;border-left:1px dashed #aaa;text-align:center} #rp3_switchPage a:hover{background-color:rgba(100,100,100,0.1)} #rp3_switchPage a:first-child,#rp3_switchPage span:first-child{border-left:0} </style>如果都使用預設值的話,直接存檔就可開始使用。 如果要修改參數,請參照綠字註解,及以下說明:
  • 第一行綠字可參考「引用 jQuery 的注意事項」,檢查範本是否已安裝過 jQuery,如果已經安裝過請刪除此行,以免重複安裝。
  • startIndex: 從第幾篇最新文章開始顯示
  • showPost: 一頁顯示幾篇文章
  • width: 文章縮圖的寬度 (px)
  • height: 文章縮圖的高度 (px)
  • noImage: 藍色圖片網址,請自行置換為文章無縮圖時的預設顯示圖片。
  • enableWebp: 圖片是否轉換為 WebP 格式
  • showSummary: 是否顯示文章摘要
  • previewLength、summaryLength: 設定預覽文章摘要、及所有文章摘要的字元數。
  • showPostTotal: 是否顯示網站總文章數
  • nextLogo、prevLogo、openLogo、closeLogo: 可修改為自訂的圖示字元,請參考「copypastecharacter.com」或「特殊符號字元一覽表」。
  • readMore、serialText、totalText: 自訂顯示的字串

三、使用說明

1. 無法顯示的處理方法如果發現這個最新文章小工具無法顯示,請先檢查以下項目:
  • 後台 → 設定 → 基本 → 網誌讀者 → 請檢查是否開放給「任何人」。
  • 後台 → 設定 → 其他 → 允許網誌資訊提供 → 不可以設定為「無」;如果是「自訂」的話,請檢查「網誌文章資訊提供」,不可以設定為「無」,最新文章才能顯示摘要內容。
  • 文章標題的連結,在文章編輯器 → 文章設定 → 連結 → 這裡請勿使用「標題連結」
2. 圖示字元改用圖片的方法請參考「Blogger 最新文章 V2」→「四、常見 FAQ」→「Q1」。
更多 Blogger 工具:

SEO 不是最重要的事,人只要做好最擅長的事就好

$
0
0
有客戶來找我,覺得搜尋排名不夠好,輸給比她弱的網站,認為一定是自己 SEO 哪裡不夠好,網站架構哪裡有問題,網站速度不夠快,想找出網站可以再優化的地方。 其實這並非客戶首次找我想優化網站,先不談再次優化網站會有多大成效,她的判斷本身就存在不少盲點:
  • 這個她想像中比較弱的網站,真的就比較弱嗎?
  • 這個競爭對手會不會有什麼背後的努力,是她看不到的?
  • 她有辦法取得對方後台流量數據,以佐證網站的強弱嗎?
  • SEO 優化、提升網站速度...這些事情,真的能夠左右搜尋排名嗎?
總之,完整理解她提出的需求後,無論是前提、結論,都可能只是她的想像。因為是非常多年的客戶了,並不希望她把錢花在錯誤的方向,而且跟 SEO 有關的需求不會是小數目。我寧可先不接這樣的需求,也要先導正她的觀念。 至少客戶在做猜測之前,應該先具備基本的能力,來解讀一個網站的強弱,不能只是靠感覺。再來第二步,才是了解真正有效提升搜尋排名的原理是什麼。 所以決定先給客人好好上個課,釐清她的判斷是否準確,如此才能確認提出這樣的 SEO 需求是否合理。 (圖片出處: pexels.com)

一、如何判斷網站實力

1. 評估自己網站首先我請客戶列出自己網站的優缺點,因為以一個第三者的角度,我很快能看出她網站的招牌看點是什麼,但想知道她能否注意到自己網站的最大賣點、最能帶來流量的因素為何。 從所有回答的條列內容,其實她做的事情非常多,圍繞著行銷面、SEO 面的努力、網站的優化,非常鉅細靡遺,但可惜並沒有碰觸我最想看到的決定性因素。這很有可能她的工作就是負責優化,所以完全忽略自己網站的看板明星才是最重要的。 2. 評估同質網站因為我維護的 Blogger 網站相當多,可以知道所有客戶的後台資訊,要評估網站的優缺點、實力是否強大,是非常容易的,也就是說我手上握有標準答案。 接著我挑了 3 個同質網站出來,請她根據自己的觀察,說出這幾個網站的優缺點。這個作業會有相當大的準確性,能看出她的判斷力,了解她評估「競爭對手比她弱」的真實性如何。 同質網站中有一個有看板明星,也就是有露臉的美女,她總算把這個要點列進去,這才是影響流量的最重要因素。這也讓我想到,她是否只是謙虛、不想提自己家的看板人物?或者她有其他原因,想把網站打造成用內容取勝,不靠顏值,也是有可能的吧~ 其實全部 4 個同質網站之中,只有 2 個有露臉,評估強弱排名的結果,她也沒把自己排在前 2,甚至放在最後一個,不曉得是否謙虛過頭,其實她的網站流量贏最後一名一倍,但這也讓我無法信服她所判斷的「競爭對手比她弱」這件事,說不定對手跟本就比較強。

二、提升網站速度能影響搜尋排名?

這個客戶提到 PageSpeed 的次數太多了,這次又想提升網站速度,說自己網頁版分數如何、行動版很低...我一直都覺得這件事是浪費時間,但很多站長樂此不疲,彷彿 PageSpeed 分數一增加,網站排名就有望了。 當然,SEO 該做的我們要做,我也寫過太多文章,例如「為何部落格最好避免第三方外掛」、「Blogger 圖片大瘦身!官方提供密技轉換成 WebP 格式」,提升網站速度最重要的就是減少 http 外連、圖片瘦身這兩件事。只要有做,PageSpeed 分數多少根本不必理他,但很多站長好像沒拿 100 分就會像得了強迫症一般。 這次特地 Google 找到兩篇文章給她: 文中有 Google 內部工程師的相關發言,這下她雖然震驚,但也總算放棄 PageSpeed 的執念。 而有看到本篇文章的站長,也恭喜你可以解脫了。

三、真正影響搜尋排名的因素

1. Google 如何決定排名有些人覺得部落格平台會影響搜尋排名,其實這影響微乎其微,相當於「袂生牽拖厝邊」(生不出來牽拖鄰居),是一種找戰犯的概念,為此我寫了一篇「是否痞客邦、WordPress 的 SEO 比 Blogger 好?」。 更多人覺得 SEO、前面提到的網站速度,是影響排名的重要因素,總之為了找戰犯懷疑東、懷疑西,卻沒有懷疑到自己身上。不知道他們有沒有想過,搜尋排名輸別人,最簡單的原因,就是總體實力輸別人,可能產品沒有別人強,又或是行銷能力別人更好。 真正影響搜尋排名的原因,也就是 Google 如何決定搜尋排名的原則,以前寫過一篇文章「部落格網站是否加強 SEO 就能帶來流量?」,以下整理重點:
  • Google 不會雪中送炭:如果你的網站原本流量就很低、沒什麼人看,Google 給你的起始排名也會非常低,就像 "米其林評鑑" 不會去找沒沒無名的餐館打分數。
  • Google 只會錦上添花:如果你的網站經營得很好,人潮絡繹不絕,Google 也會主動把第一頁的排名頒給你。就像出了名的餐廳,各大媒體、雜誌都會爭相報導一樣。
  • 「自助而後人助」,你必須先有流量,Google 才能給你更好的排名,帶來更多的流量
2. 如何獲得流量同一篇文章也提到了,網站產生流量的重要三要素:
  • 產品 → 好的產品、內容,才能帶來真實、長久的流量
  • 行銷 → 就算產品再好,沒人知道也不會有流量,所以需要到目標客群出沒的地方發傳單,爭取曝光機會,這部分就看站長們的行銷手段了
  • 市場 → 特定產品能得到特定市場的流量,但也有其限度。要擴張版圖得到更多流量,可想辦法開發更多市場。

四、產品的重要性

1. 好產品的條件流量三要素之中最重要的是產品,若產品的天花板不夠高,再怎麼行銷也很難有好效果。所以搜尋排名要好,最重要的當然是有好產品、優質內容。 過去寫的「如何成為部落客中的佼佼者」提到,達到以下三條件之一,就會是不錯的部落格產品或內容:
  • 成為該領域專家
  • 有好的文筆
  • 具備顏值
2. 進行差異化同篇文章也提到,為了市場、流量不被分食,產品需要進行差異化,也就是符合以下特質:
  • 具有辨識度
  • 獨特性
  • 不可複製
所以站長們最該花心思、時間的,是如何打磨獨一無二的產品、內容,而不該先花時間在任何優化之上。文章寫出自己的風格後,自然具有辨識度,別人複製不來,也搶不走你的市場

五、塑造產品

1. 產品設定了解以上所有概念後,接下來請客人試著找出自己網站的優點、獨特性,來看看有沒有辦法進一步打磨自己的產品,讓產品更強,以及了解產品可用來包裝之處。 以我旁觀者的角度來看,客人網站有露臉的看板人物,自然會是最佳的產品、包裝目標,也是能帶來流量的最佳賣點。 只是從客人自行條列的優點、獨特性,她似乎把重點擺在文章內容、圖片品質、提供顧客優惠、網站版面設計等等。把這些項目當成「產品」、「賣點」也不是不可以,就是力道不會那麼強,天花板不夠高。 如果她網站的文章內容,文筆很好、具特殊風格,我會支持把內容當作產品,但實際上我認為目前的水準還沒到具備當作賣點的程度。而如果把「提供顧客優惠」當作賣點,這個層次顯然低了一些,而且不可能每篇文章都會有優惠,其他因素亦然。 我在想,她這樣的回答,問題是出在哪裡呢?也許她有苦衷,看板人物的使用是有限制的。 2. 觀摩同質網站如果客戶的重點想擺在文章內容,那麼我得了解她對「內容」的敏銳度、賞析能力如何,才可知道她有沒有能力打造「文章內容」這樣的產品。 前面比較的 4 個同質網站中,有一個網站未露臉,但目前流量在 4 個中排名算最高,那麼很明顯這個網站的賣點一定是文章內容了。根據排名的結果,我請客戶試著分析這個不露臉的網站,其內容的辨識度、獨特性、不可複製之處在哪? 客戶條列了很多項目,大部分都打上問號(表示她也不知道對不對),在我來看,大部分的回答都是 SEO 細節、行銷、市場、優化相關,跟我想要的答案差距很遠。她也如實說了,"這個網站我看不出任何獨特之處,照片普通、文字也普通",所以我的猜測大致沒錯,她還不具備評鑑產品的能力,所以無法看出該網站流量大的真正原因。 她所有注意到的地方,基本上跟她平常的工作有高度正相關,所以她只能看到她能理解的部分。如果她看不出一個作品(產品)的風格、賣點,那麼要她另外去塑造出一個有賣點的風格出來,我相信會有難度,這件事要學除了不容易也難學得像,畢竟不在她的技能樹之中。

六、做自己擅長的事就好

於是我在想,這個案子的問題出在哪呢?案主的專長看起來是進行優化、後勤輔助性工作,這些事她可以做的非常好。而對需要創意、觀察敏銳度、創造性的工作,似乎沒那麼擅長。一般部落格站長都是校長兼撞鐘,一人需要扛下所有網站事務。我的客戶雖然有團隊,但必然分工無法那麼細,或許客人也要身擔網站排名的重任,而依照她處理擅長事務的邏輯,只能拼命的往優化方面想破頭來解決事情。 這個案子的最佳解也不難,只要別把不擅長的事往自己身上攬就行。找到塑造產品的專家做為顧問,或是團隊另外找到適合做這件事的隊友,由適合的人來執行產品規劃、打磨,就算還要花學習的時間,也會學得比較快。每個人都做自己最擅長的事,團隊才能發揮最大的產值。 所以最後,把這些想法讓她知道,就看她怎麼想、怎麼做了。

七、給站長們的建議

那麼,因緣看到此篇的讀者,應該大部分是部落格站長,也順帶給一些建議吧:
  • 別太早想著要讓部落格營利,否則在你的產品成熟之前,遲早陷入身背流量、排名的困境
  • 為了流量與排名,你腦中所想的,只剩如何優化、行銷,不會想到如何打磨產品。就算有想到,可能也沒時間讓你做了
  • 寫文章需要好文筆,這需要長時間磨練。更重要的是充實自己,肚子沒墨水很快就沒東西寫了。
  • 有墨水自然會產生自己的想法,文章有見地自然能形成自己的風格,自然有屬於你的市場與流量
更多「部落格經營」相關文章:

不用買字型,用 CSS 做出專業的縷空文字+外框

$
0
0
不用買字型,用 CSS 做出專業的縷空文字+外框最近接到一個需求,製作醫學疾病風險自我檢測頁面,客戶提供的設計圖質感不錯,只不過有設計感的畫面在製作 RWD 效果時,難度會提高很多。 其中一個部分需要使用高超的 CSS 技巧「縷空文字+外框」,這樣的效果無法用簡單的 CSS 語法做出來,原設計圖版面如下(紅框標示的部分): 不用買字型,用 CSS 做出專業的縷空文字+外框那麼讀者可以先思考一下,如果使用純 CSS 的話,要怎麼做出這個「文字內部粗體縷空 + 文字外框陰影」效果?

一、文字外框 text-stroke

一開始 Google 到文字外框的效果可用 CSS 語法 -webkit-text-stroke做到,教學範例可參考這篇「透過CSS3屬性text-stroke 實現縷空文字邊框效果」。 1. 效果1-webkit-text-stroke: 1px #fff;先來測試基本效果,以上 CSS 語法先測試 1px 外框,效果如下:
WFU BLOG
文字縷空外框範例
  • 英文字體效果還可以
  • 中文字不太行,看起來 text-stroke 會吃掉字體寬度
2. 效果2-webkit-text-stroke: 1px #fff; font-weight: bold;因為 text-stroke 會佔據 font-size 寬度,所以試著把字體加粗:
WFU BLOG
文字縷空外框範例
這樣子看起來好多了。 3. 效果3-webkit-text-stroke: 2px #fff; font-weight: bold;但是外框要粗一點效果比較好,所以語法改 2px外框:
WFU BLOG
文字縷空外框範例
中文字又不行了,text-stroke 吃掉字體寬度的情況,是必須解決的大問題。

二、文字陰影 text shadow

另一個製作文字外框的技巧,是使用 CSS 語法 text shadow,教學範例可參考這個討論串「Font outline using only CSS」。 text-shadow: 0 0 5px #5b947f, 0 0 5px #5b947f, 0 0 5px #5b947f, 0 0 5px #5b947f; font-weight: bold;利用以上語法測試效果,將字體加粗並設定了 5px 外框陰影,效果如下:
WFU BLOG
文字縷空外框範例
  • 看起來效果很不錯,無論字體多大多寬,text shadow 都不會侵佔字體空間
  • 只可惜這效果跟客戶提供的設計圖稍稍不太一樣

三、完美組合語法

還好找到這篇教學「如何利用 CSS 製作完美的文字外框」。作者製作的原理整理如下:
  • 製作兩層一模一樣的文字內容,位置重疊
  • 上層為原本的文字,會遮蓋下層
  • 下層利用 text-stroke 做出更大面積的文字,自然形成外框效果
作者的這個巧思,完美解決了 text-stroke 無法用於粗體的困境,真的是最佳解。 但可惜的是,Blogger 直接套用其語法時,無法顯示出效果。這代表 Blogger 範本跟此作者使用的 CSS 環境有些微差異,所以我重新整理出可以用於 Blogger 環境的語法。

四、Blogger 實作技巧

以下提供範例程式碼: <div class="stroke" data-stroke="WFU BLOG">WFU BLOG</div> <div class="stroke" data-stroke="文字縷空外框範例">文字縷空外框範例</div> <style> .stroke {position: relative; color: #fff; font-size: 2rem; z-index: 10; background: #A7CFA2; text-align: center; padding: 5px; letter-spacing: 10px; } .stroke:before {position: absolute; z-index: -1; -webkit-text-stroke: 5px #5b947f; content: attr(data-stroke); } </style>下面可看到以上 CSS 的效果,總算比較接近客戶的設計圖了:
WFU BLOG
文字縷空外框範例
更多 CSS 相關技巧:

Node.js 爬蟲開發新手技巧﹍Google Apps Script 替代品

$
0
0
過去一直使用「Google Apps Script 製作網頁爬蟲程式」,並配合「Google 試算表做為資料庫」,基本上不但免費、可應付大多數的需求,同時 Google 試算表還很強大,操作起來不但方便,只要能上網的地方就可使用,省下雲端同步的麻煩,比 Excel 方便太多。 Google Apps Script(以下簡稱 GAS)免費使用的主要限制為,每次執行的時間上限為 6 分鐘,一天最多可執行約 90 分鐘(非手動執行的情況下),如果是簡單的爬蟲不會有什麼問題。不過最近需要製作執行時間較長的爬蟲,GAS 就算是付費版(Google Workspace),雖然一天可執行總時間長達 6 小時,但每次執行時間上限仍然為 6 分鐘,所以只好另尋其他方案。 找到最簡單、方便的方案為 Node.js,跟 GAS 一樣都是使用 Javascript 語言,在 Windows / Mac 作業系統可直接執行,可說是前端工程師的福音,只要學會一種語言就可通吃「前端+後端+資料庫」,本篇將整理使用 Node.js 製作爬蟲需要具備的基本知識、技巧、開發環境等等內容。 (圖片出處: pexels.com)

一、Node.js 開發環境

1. 介紹、安裝 Node.js 跟前端 Javascript(以下簡稱 JS) 不太一樣,是後端環境使用的 JS,所以沒有前端的 window、DOM 等等,詳細的介紹與安裝方式,可參考: 2. 使用 Sublime Text 3 開發我慣用的 JS 開發、編輯工具為 Sublime Text 3(以下簡稱 ST3),這個工具同樣可以做為 Node.js 開發之用。在作業系統安裝完 Node.js 後,可參考以下文章進行: 完成以上流程後,在 ST3 編輯 .js檔並儲存,按下 Ctrl+B就能執行 Node.js 程式碼。 3. 安裝模組 npm yarn Node.js 有數十萬個模組可以取用,如何選擇合適的模組需要一些智慧與判斷方式,例如查看近期下載數量、更新版本、更新頻率等等。而管理這些模組的工具,過去知名的是 npm,近期受好評的是 yarn,如何抉擇與安裝,可參考以下:

二、Node.js 上手資源

開發環境處理完畢後,需要了解如何開始寫 Node.js,以下提供新手可以隨時查閱的上手資訊: 接下來會介紹跟爬蟲相關,需要了解的知識。

三、全域變數

執行爬蟲之前可能需要從檔案讀取資料,完成之後可能需要儲存檔案,那麼有兩個 Node.js 全域變數需要了解:
  • __dirname:執行 js 檔的目錄
  • __filename:該 js 檔的檔案路徑
以下為範例: console.log(__dirname); // D:\WFU console.log(__filename); // D:\WFU\node_test.js

四、原生模組

1. 引用原生模組所有 Node.js 原生模組可在「官方文件」找到,執行模組之前要用 require 來載入,以下為載入 os 模組,取得系統資訊的範例: var os = require("os"); console.log("CPU 資訊:" + JSON.stringify(os.cpus()));以上程式碼可讀取本機的 CPU 資訊,os 的用法可參考「os 操作系統」。 2. 重要原生模組以下為製作爬蟲可能用到的原生模組:

五、外部模組

1. 第三方模組 node.js 除了官方模組,還有許多自行開發且好用的模組,可到官網搜尋需要的功能: 只有原生模組才能直接 require 載入,非原生模組的處理請參考前面的說明用 npm 或 yarn,流程如下:
  • 打開 DOS 命令視窗,進入專案資料夾路徑
  • 執行指令 npm inityarn init進行初始化(加入參數 -y 可省略回答)
  • 執行指令安裝模組 npm install 模組名稱yarn add 模組名稱
  • 完成以上就可以 require 載入第三方模組
2. 自建模組除了第三方模組,也可建立模組自用,方法為:
  • 在 js 檔中建立一個物件
  • 將該物件存入 module.exports
  • 記住此 js 檔的檔名、存放路徑
範例如下: function wfu_module(){ console.log("成功載入模組 !"); } module.exports = wfu_module;引用此模組的範例程式碼如下,假設檔名為 wfu.js: var wfu_module = require("./wfu"); wfu_module(); // 成功載入模組 !
  • require 參數需要加上正確的檔案路徑, "./" 代表「wfu.js」放在同樣的路徑
  • 副檔名 ".js" 可省略
  • 在 ST3 按下 Ctrl+B執行即可看到效果

六、載入外部函數

GAS 用習慣後,Node.js 會稍微不適應,因為 GAS 可以很輕鬆地引用所有外部函數,就跟前端的 JS 操作起來一模一樣。 舉例來說,前端載入一段 script 後,這段 script 的所有全域變數、所有函數等等,在整個網頁的其他地方都可引用。而 Node.js 不一樣,載入了一個外部模組,只能使用那個模組的變數,這代表想要執行 10 個外部模組,得執行載入 10 次的動作,沒有比較簡化的作法,很花時間。 於是研究了一下,能否一次打包多個函數,只要載入一次就好,就能執行多個外部函數,我找到了這個討論串: 該討論串提出了不少實用的作法,列出兩個實用的方法做為記錄。使用這兩個技巧後,就可將多個函數打包入一個檔案,只需載入一次即可。 1. 使用 eval假設外部 wfu.js 內容如下: function wfu_module(){ console.log("成功載入模組 !"); }引用 wfu_module 函數的範例程式碼如下: var fs = require("fs"); // 操作存取檔案的原生模組 eval(fs.readFileSync("./wfu.js") + ""); // 讀取 wfu.js 內容並轉為字串, 用 eval 執行 wfu_module(); // 呼叫外部函數2. 使用 this假設外部 wfu.js 內容如下: module.exports = function() { this.wfu_module = function() { console.log("成功載入模組 !"); }; }引用 wfu_module 函數的範例程式碼如下: require("./wfu.js")(); // 執行 wfu.js 內容, 讓 wfu_module 成為全域變數 wfu_module(); // 呼叫外部函數

七、同步 / 非同步

1. 同步與非同步的差異 JS「同步/非同步」造成的問題可參考「前端 JS 如何避免 callback 地獄?」,這方面不得不令人懷念起 GAS 的單純環境,所有程式碼一律是「同步」執行緒,一件事執行完才會接續下個動作,程式碼非常好寫。 Node.js 以同時間可大量平行運算、執行高效而聞名,可參考「Node.js 單執行緒、非同步、非阻塞 I/O」。那麼在後端執行爬蟲任務時,不可避免會遇上大量「非同步」程式碼,若程式架構寫不好就會形成「callback 地獄」,同時後續也難以閱讀、維護、管理,以下大致說明 Node.js 這部分需要注意、學習的內容。 2. async / await從 JS ES7 這一版開始加入了 async / await 函數,用來讓「非同步」執行緒可以「同步」執行,只要 Node.js 安裝的是 v7.6 以後的版本就可使用 async / await,其原理及操作方式可參考這篇「Async / Await 深度介紹」。 3. 非同步執行範例下面以常用的檔案存取功能 fs 做為範例,說明非同步執行緒會有什麼狀況。 假設要讀取的文字檔 wfu.txt 內容如下: Blogger 調校資料庫執行程式碼如下: var fs = require("fs"); console.log("程式執行開始!"); fs.readFile("./wfu.txt", "utf8", function(err, data) { if (err) { console.log("無法讀取檔案!"); } else { console.log(data); } }); console.log("程式執行結束!");執行結果如下,可以看的出 wfu.txt 檔案的內容無法依序顯示出來(最後一行才顯示): 程式執行開始! 程式執行結束! Blogger 調校資料庫4. 同步執行範例以下利用 async / await 標準寫法,來修改執行程式碼,: var fs = require("fs"); function readFile() { return new Promise((resolve, reject) => { fs.readFile("./wfu.txt", "utf8", function(err, data) { if (err) { console.log("無法讀取檔案!"); reject(err); } else { console.log(data); resolve(data); } }); }); } async function wfu_sync() { console.log("程式執行開始!"); await readFile(); console.log("程式執行結束!"); } wfu_sync();執行結果如下,可以看出 wfu.txt 檔案內容已經依序顯示出來: 程式執行開始! Blogger 調校資料庫 程式執行結束!

八、Node.js 同步技巧

前面介紹的是 JS「非同步改同步」標準作法,Node.js 在這方面提供一些實用工作可以簡化程式碼。 1. 改用 fs 同步方法除了「非同步」版本,Node.js 為所有的 fs 檔案存取方法都提供了「同步」版本,可參考官方文件「fs 文件系統」→「同步的API」,這裡列出了全部方法。 舉例來說,前面用到的 fs.readFile 方法,同步版本就是 fs.readFileSync,字尾一律多出 "Sync" 字串,範例程式碼如下: var fs = require("fs"); console.log("程式執行開始!"); var content = fs.readFileSync("./wfu.txt", "utf8"); console.log(content); console.log("程式執行結束!");簡直是太舒暢了,不用搞什麼 Promise / async / await 這些有的沒的對吧?一行搞定所有工作! 但其實這是最不建議的作法,因為這樣的同步方法,無法使用 callback,萬一讀取檔案失敗,系統會立刻報錯,之後的所有程式碼都會中斷無法繼續執行。 所以若要使用 Node.js 內建的「同步」方法,得每個地方都另外寫 try catch 才行,例如這樣: try { fs.readFileSync("./wfu.txt", "utf8"); } catch (error) { console.log(error); }2. 改用 fs.promises比較推薦的作法會是 fs.promises,可以將 fs 模組的所有方法轉換為 Promise 物件,例如 fs.promises.readFile。經此處理後的程式碼比較簡潔,範例如下: var fs = require("fs"); ~async function() { console.log("程式執行開始!"); await fs.promises.readFile("./wfu.txt", "utf8") .then(data => { console.log(data); }).catch(err => { console.log(err); }); console.log("程式執行結束!"); }();3. 改用 util.promisify Node.js 主要為 fs 模組提供了同步方法,不代表其他模組都有同步方法。還好官方提供了一個超級實用的工具 util.promisify,可以將其他原生非同步模組轉換為 Promise 物件,來執行「同步」效果,以下為範例程式碼: var fs = require("fs"), util = require("util"), readFile = util.promisify(fs.readFile); ~async function() { console.log("程式執行開始!"); await readFile("./wfu.txt", "utf8") .then(data => { console.log(data); }).catch(err => { console.log(err); }); console.log("程式執行結束!"); }();

九、延遲執行

1. 爬網頁不可頻繁最後補充爬蟲程式常會用到的功能。爬網頁時為了不造成對伺服器的困擾與負擔,間隔頻率不可太頻繁,否則就成了「DDOS 攻擊」。而且伺服器對頻繁的爬取也會進行封鎖,所以需要重複爬取同網站時,最好間隔一段時間。 可參考「降低網頁爬蟲被偵測封鎖的實用方法」→「五、設定隨機的延遲時間」,這裡提出的概念:
  • 間隔時間都相同時很容易被偵測到
  • 根據程式碼,延遲的秒數最好都在 5 秒以上
2. Node.js 實現延遲時間一般後端語言都會內建延遲時間(sleep)的相關功能,但 Node.js 並沒有相關的內建模組。找到這篇「nodejs中實現sleep休眠函數」提供了多種作法,由於篇幅的關係不解釋原理了,多數的作法要嘛需耗用大量 CPU 運算,要嘛需要安裝及載入第三方模組,最推薦的作法是使用 JS 原生函數 Atomics.wait,以下提供範例程式碼: // 延遲執行 n 毫秒; function sleep(n) { var sharedArrayBuffer = new SharedArrayBuffer(4), sharedArray = new Int32Array(sharedArrayBuffer); Atomics.wait(sharedArray, 0, 0, n); } console.log("程式執行開始!"); sleep(2000); // 暫停 2 秒 console.log("程式執行結束!");在 ST3 儲存後,按下 Ctrl+B執行可發現,2 秒後才會印出 "程式執行結束!",完美實現延遲時間的功能。 了解本篇基礎知識後,下一篇會分享完整的爬蟲配套方案如何建構。
更多「爬蟲」相關技巧:

Node.js 模組安裝完卻無法引用的最佳解法

$
0
0
寫完前一篇「Node.js 爬蟲開發新手技巧」後發現,在不同的資料夾執行程式碼,有的可以正常執行,有的會報錯「Cannot find module 'xxxxx'」表示找不到第三方模組。 研究後才發現,Node.js 讀取第三方模組有其 SOP,若在系統預設的所有相關資料夾都找不到第三方模組檔案,就會出現以上的錯誤訊息。 這樣的設計很是讓人困擾,如果開了很多不同的爬蟲專案,每個專案都存放在專屬的資料夾,那豈不是同樣的許多第三方模組,都得所有專案個別安裝一次?如果有 10 個專案要用到 axios 模組,硬碟就會有 10 個地方要安裝 axios 模組,存放 10 組一模一樣的檔案,徒然佔用大量硬碟空間。 雖然 npm 有參數 -g可以設定為全域安裝,然而這對於引用第三方模組是沒有幫助的,專案仍然會報錯無法抓到第三方模組。而如果每次為了成功引用第三方模組,都得查詢及填入冗長又記不住的完整路徑,也是滿浪費時間的。為了日後管理、操作方便及節省空間,研究了下這個問題要如何解決,請見本篇的整理。 (圖片出處: pixabay.com)

一、Node.js 讀取模組邏輯

官方對於如何使用 require 載入模組,提供了一大段邏輯程式碼,有興趣可參考「require high-level algorithm」。 相信這個「英文邏輯樹」不容易解讀,這篇「深入Node.js的模組載入機制」提供了中文版說明:
1. 優先載入內建模組,即使有同名檔案,也會優先使用內建模組。 2. 不是內建模組,先去快取找。 3. 快取沒有就去找對應路徑的檔案。 4. 不存在對應的檔案,就將這個路徑作為資料夾載入。 5. 對應的檔案和資料夾都找不到就去node_modules下面找。 6. 還找不到就報錯了。
所以依照以上邏輯,正常情形我們只有在該「專案資料夾」之下,使用指令 npm i 模組名稱安裝第三方模組後,會自動存放在該「專案資料夾」的「 node_modules 資料夾」,才能讓 require 成功讀取。

二、能否讀取全域安裝的第三方模組

1. 原理為了避免在多個專案資料夾重複安裝第三方模組,我想嘗試看看,能否讓 require 讀取全域安裝的第三方模組,找到了這個討論串「NodeJS require a global module/package」。 這個討論串提供了不少作法,有的解法似乎有風險,有的解法適用 Linux,不過提供的概念還是有幫助,Node.js 如通過正確的設定,有辦法可讀取全域安裝的第三方模組。 找到了這篇「Node.js模組全域性安裝路徑配置方法」,即為前述討論串概念的中文操作方法,以下使用 npm 來說明如何操作。 2. 修改全域路徑首先在安裝 Node.js 的目錄(假設是 d:\node)下建立兩個資料夾,名稱分別為 node_global(全域模組)、node_cache(全域快取) 接著執行以下兩個指令: npm config set prefix "d:\node\node_global" npm config set cache "d:\node\node_cache"最後需要修改作業系統的「環境變數」,以 Windows 為例,操作方式為:
  • Win+R→「執行指令 sysdm.cpl」→「進階」→「環境變數」
  • 「使用者變數」→「新增」→ 變數名稱輸入「NODE_PATH」→ 變數值輸入「d:\node\node_global\node_modules」
  • 儲存後,重新啟動 Windows 可生效
重新啟動作業系統後,將來使用 npm 安裝的全域第三方模組(參數 -g),就能直接在程式碼 require 使用了。

三、yarn 操作

以上為 npm 的相關操作,而 yarn 的操作請看以下說明。 1. yarn 全域資料夾位置yarn global dir執行以上指令可找出 yarn 全域資料夾所在位置,而更改全域資料夾的指令,可參考這篇教學「yarn修改全局安裝路徑和緩存路徑」,範例如下: yarn config set global-folder "d:\node\node_global"之後使用 yarn global dir查看,路徑的確變更了。 然而接著使用 yarn global add 模組名稱,會發現並沒有安裝到全域資料夾! 2. 修改 yarn 全域資料夾位置找到 yarn 官網討論串「how to change global folder」,這裡說明了如何修改:
  • 同之前步驟,先執行指令 yarn config set global-folder "d:\node\node_global"
  • 找到 .yarnrc 這個檔案並開啟
  • 將字串 global-folder改為 --global-folder
  • 之後執行指令 yarn global add 模組名稱,就能發現模組出現在全域資料夾了
更多 Node.js 相關文章:

操作 Sheet API 讀取 Google 試算表取得 JSON 資料

$
0
0
Google Sheet API」可用來存取 Google 試算表資料,但卻是我少數不推薦使用的 Google API,原因可參考之前寫的「利用 Google 試算表當小型資料庫 (4)使用 SQL 語法讓搜尋功能更強大」→「1. Sheet API 功能不佳」,因為 Sheet API 無法對資料進行篩選、搜尋,導致每次都得讀取所有資料後,再自己寫程式進行過濾。 然而去年 Google 試算表進行某次更新後,之前寫的「利用 Google 試算表當小型資料庫 (2)讀取資料庫」方法已然失效,無法從試算表 feed 讀取資料。根據官方的說法「GData API Directory」→「Google Spreadsheets Data API → Deprecated. Replaced by the Google Sheets API v4.」,意思就是 Google 宣布舊的試算表 API 已失效,建議即日起改用 Sheet API V4 取代原本的讀取方式。 因此本篇整理如何操作 Sheet API,取代原本的操作方式,來取得 JSON 格式的試算表資料。 (圖片出處: pexels.com)

一、Sheet API 準備動作

以下流程請參考這篇「取得 Google API Key(金鑰) 流程」進行操作: 1. 啟用 Sheet API
  • 按照該篇文章完成「一、建立專案」
  • 進行「二、啟用 Google API 服務」時,可輸入 Sheet API,找到後「啟用」
2. 取得 API KEY
  • 接著依照「三、取得 API Key」的流程,建立一組「API 金鑰」,請記住這組字串,之後會用到。
  • 如果這組「API 金鑰」在前端使用的話,會被使用者看到,那麼建議按「限制金鑰」進行其他設定。
  • 同上,為了避免金鑰被別人拿去用,建議「應用程式限制」設定為自己網址,「API 限制」設定為「Sheet API」才能使用。
3. 調整試算表共用權限要讀取的試算表,記得要開放權限,不能只有自己才可讀取,至少要開放為「任何知道這個連結的網際網路使用者都能查看」。

二、Sheet API 讀取資料

1. 官網文件讀取試算表資料的操作語法說明請見「spreadsheets.values.get」: GET https://sheets.googleapis.com/v4/spreadsheets/[試算表 ID]/values/[工作表名稱及範圍]官方也提供了「Sheet API 測試工具」,進入後切換到「HTTP」可看到以下語法: GET https://sheets.googleapis.com/v4/spreadsheets/[試算表 ID]/values/[工作表名稱及範圍]?key=[API 金鑰]自行輸入以上參數就可看到取回的資料,JSON 格式大致長得像這樣: { "range": "sheet1!A1:Z4850", "majorDimension": "ROWS", "values": [ [ "時間", "稱謂", "性別", "註解" ], [ "2016/11/29 0:00:00", "Wayne", "male", "測試寫入功能" ], [ "2016/11/29 0:00:00", "Mary", "female", "成功!" ] ] } 2. 參數說明這裡說明前述的參數如何填寫:
  • 試算表 ID:試算表網址字串中 ~/d/xxxxxxxxxxxx/edit~ xxxx 這一長串就是試算表 ID
  • 工作表名稱及範圍:這部分的詳細說明可參考官網文件「Google Sheets API Overview」→「Cell」→「A1 notation」或「R1C1 notation」,最簡單就是填入工作表名稱就好,例如「工作表1」,代表選擇全部範圍
  • API 金鑰:填入前面「一、Sheet API 準備動作」取得的金鑰字串

三、操作範例

本篇同樣以這個試算表當做範例說明: 以下為 jQuery 範例程式碼: <div id="wfu_sheet_json"></div> <script src='//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js'></script> <script> var spreadsheet_id = "106tP9D89pnEgvZTuM3_ahMJRPjCSD3qthth-GEhGMIE", // 填入試算表 ID tab_name = "sheet1", // 填入工作表名稱 api_key = "xxxxxxxxxx", // 填入 API 金鑰 url = "https://sheets.googleapis.com/v4/spreadsheets/" + spreadsheet_id + "/values/" + tab_name + "?key=" + api_key; $.getJSON(url, function(json) { var values = json.values, // 所有試算表資料 html = ""; html += "<table>"; values.forEach(function(rows) { html += "<tr>"; rows.forEach(function(item) { html += "<td>" + item + "</td>"; }); html += "</tr>"; }); html += "</table>"; $("#wfu_sheet_json").html(html); }); </script>以下是程式碼的執行效果範例,只取前 5 筆顯示:
時間稱謂性別註解
2016/11/29 0:00:00Waynemale測試寫入功能
2016/11/29 0:00:00Maryfemale成功!
2017/01/12 16:06:13
2017/01/13 0:01:00testfejj
用 Google Apps Script 操作試算表系列文章:
更多「Google 試算表」相關文章:

E-ink 螢幕 Paperlike Pro 使用心得﹍(2) 護眼檯燈 + 環境優化

$
0
0
paperlike-pro-eink-monitor.jpg-E-ink 螢幕 Paperlike Pro 使用心得﹍(2) 護眼檯燈 + 環境優化上一篇「Paperlike Pro 入手及開箱心得」介紹了這個電子墨水顯示器,使用一段時間後發現有個重大技術問題需要解決,而且看到這個 FB 討論串,也證實不只我有這個顧慮:「Eink前光燈的重要性」:
  • 檯燈光源要是光度不夠,會有部份亮部份不夠亮的問題
  • 反光問題...很容易會有一團強烈的反射光團刺眼且影響閱讀,需要調整至某些特別角度,但這些特別角度可能並非最舒服的閱讀位置,就算設置好那更加不能隨意變動位置...
要讓 Eink 螢幕發揮作用,最重要的因素是環境光源,然而除非是大型商場、書店等營業場所,一般家庭不可能有那麼充足的光源(天花板滿滿的燈泡),所以一定必須使用檯燈來補足光源,而使用一般檯燈又會遇到以上兩點問題。 為了解決這些難題,以下分享我找到的智慧檯燈使用心得,同時補充 Windows 作業環境的優化重點。 (圖片出處: chimei.com.tw)

一、智慧檯燈挑選重點

1. 三個要點根據前述提到需要克服的幾件事,以下是挑選適合 Eink 螢幕光源的要點:
  • 可微調亮度:為了避免「一團強烈的反射光團」,檯燈必須能微調亮度,以找出該環境最適合的亮度
  • 燈管需為長條形:如果燈泡形狀為球形,螢幕受光處必會不均勻,最好是長條形才能讓光佈滿整個螢幕
  • 燈管可微調角度:為了讓受光面積能均勻打到整個螢幕,產品必須能調整高低及各種旋轉角度,其中最重要的是燈管面對螢幕那一面的角度,必須是可以旋轉的
  • 不可太笨重:這一點是額外加分項,功能強的檯燈多半很笨重,使用起來會有壓迫感。如果能有符合前3點又不笨重的,將會是最佳選擇。
  • 可切換情境:這也是加分項,能切換晝光、黃光的話,將可增加不同情境的用途。
2. CHIMEI LT-BT100D查了多個購物網站、跑了多個賣場之後,最終找到這兩個符合我需求的智慧檯燈: 根據在現場實際使用的結果,功能上兩個用起來差不多:
  • 都符合三個基本要求
  • 都滿足額外的兩個需求,都有四種情境可以切換
最後我選擇購買的是奇美這一款,除了品牌比較大,雖然貴一些,但產品做工的確更有質感,看了心情舒服一些。 paperlike-pro-eink-monitor-0.jpg-E-ink 螢幕 Paperlike Pro 使用心得﹍(2) 護眼檯燈 + 環境優化上圖為「奇美 LT-BT100D」與 Paperlike Pro 調整擺放位置後的效果:
  • 燈管角度稍微調整轉向螢幕,頂端略高於螢幕上方,燈與螢幕距離約 10~20 公分,受光面積較均勻
  • 切換到「晝光(白光)」模式
  • 螢幕上方看起來有反光,是因為拍照角度所致,實際眼睛略高於燈管的高度,是不會看到反光的
  • 手機拍照效果看起來環境沒有很亮,實際整個螢幕範圍看起來受光相當明亮清楚

二、外接螢幕注意事項

如果你的主機、顯示卡沒有雙螢幕的問題,可以跳過這一段。 因為我的主機比較舊,上一篇有提到,光是直接裝 Paperlike Pro 都問題一堆,更別提接雙螢幕了。目前我能順利使用的環境是 Win10 筆電 + 獨立顯卡 + Paperlike Pro,以下補充一些我 PC 接雙螢幕踩到的坑。 1. 不能外接 USB 顯示卡由於舊主機雙螢幕能力不佳,上網查到可以買 USB 外接顯卡(HDMI 接頭),使用的結果目前全是悲劇。 接上 Paperlike Pro 後雖可顯示,但執行了官方軟體後卻發現,「A2 功能沒有作用」,螢幕底色就算設成白色依然看起來是灰灰的,這樣就失去 Eink 螢幕的效果了,還不如不用。 重新爬了第一篇的心得,才發現我有寫過「官方 FAQ 有說,不要使用 HDMI 分接器」,這大概就是問題所在吧,Paperlike Pro 一定要直接插主機的 HDMI 接頭才行,用 USB 轉接後訊號就無法正常處理了。 2. 聲音沒了後來心生一計,把主機的 HDMI 接頭給 Paperlike Pro 使用,而主螢幕改接 USB 外接顯卡。這樣會變成 Paperlike Pro 是主螢幕,而原來的螢幕要進入 Windows 後才看得到畫面,雖然兩光了些但看看能否湊合著用。 一試之下居然成功了,想著以後可以雙螢幕作業真是雀躍不已,結果多做幾件事後未爆彈就一個個出現了:
  • 主機 CPU 不夠力的話,大螢幕的影像輸出不會很順
  • 主機原本的 HDMI 接頭可能會把聲音傳輸到 Paperlike Pro,代表聲音可能就不見了
  • 換了一台 CPU 比較強的主機測試,聲音、影像回來了,但 Paperlike Pro 抓不到了...
3. 結論由於我的三台主機都是 Win7 準系統,或許將來主機壞了有機會升級時,比較新的 Win10/Win11 雙螢幕主機,是可以順利與 Paperlike Pro 共存的。

三、Windows 環境調整

關鍵技術(檯燈)解決後,接下來補充前一篇沒提到的,作業系統環境的優化。 1. 高對比布景paperlike-pro-eink-monitor-1.jpg-E-ink 螢幕 Paperlike Pro 使用心得﹍(2) 護眼檯燈 + 環境優化 E-ink 螢幕適合白底黑字顯示,因此作業系統務必修改布景配置。以 Win10 為例,操作方式如下:
  • 桌面 → 滑鼠右鍵 → 個人化 → 背景 → 高對比設定 → 選擇佈景主題 → 白底黑字
2. 更換字型E-ink 螢幕若字體太細不方便閱讀,作業系統預設的字型最好粗一些、黑一些,看起來才不費力。 如果是 Win7 此事很容易,從「桌面 → 滑鼠右鍵 → 個人化 → 視窗色彩」操作,就可單獨為標題、內容等各處個別設定字體及粗體。但 Win10 就很麻煩了,已經拿掉了這部分的功能,有幾種方法可以修改,整理如下: 另外補充一些處理心得:
  • 我使用微軟雅黑體(Microsoft Yahei),尺寸 14,系統設定改字體縮放為 150~175%,效果就不錯了。
  • 若使用 Winaero Tweaker 修改各處字型設定,必須在 Paperlike Pro 螢幕執行。如果在主螢幕執行 Winaero Tweaker 後切換到 Paperlike Pro,可能重開機後設定會跳掉,又必須重新設定了。
  • Winaero Tweaker 設定完後,不要再調整「系統設定的字體縮放」,否則設定又會跳掉,必須重新來過
3. 快速切換雙螢幕 Windows 預設幾組快速鍵雙螢幕、作用中的程式,務必一記:
  • Win + P:切換雙螢幕的顯示方式
  • Win + Shift + 左(右):將作用中的程式,快速切換到不同的螢幕
4. 關閉筆電螢幕使用雙螢幕後,筆電預設 n 分鐘後會自動關閉螢幕,連帶也會讓第二個螢幕無法使用,這是很麻煩的一件事。不但如此,只要為了想要省電而將筆電螢幕關上,也會造成同樣的結果。所以必須想辦法讓筆電螢幕關閉時,Paperlike Pro 仍能繼續運作。 請參考這篇「筆記型電腦如何蓋上螢幕,而不進入休眠或關機」,進行以下設定即可:
  • 開始 → 設定 → 系統 → 電源與睡眠 → 其他電源設定 → 選擇蓋上螢幕時的行為 → 當我關閉筆記電腦螢幕時 → 不進行動作

四、軟體調整

補充一些常用工具環境設定的調整。 1. Chrome以前的 Chrome 若使用 E-ink 螢幕,需要另外安裝「高對比模式套件」,最近發現新版本的 Chrome 大有進步,似乎偵測到作業系統使用高對比模式(例如白底黑字)時,也會自動幫網站轉換成白底黑字。 以「線上看電視」為例,這是原本的樣子: paperlike-pro-eink-monitor-2.jpg-E-ink 螢幕 Paperlike Pro 使用心得﹍(2) 護眼檯燈 + 環境優化這是筆電上 Win10 使用白底黑字模式,Chrome 自動調整的樣子: paperlike-pro-eink-monitor-3.jpg-E-ink 螢幕 Paperlike Pro 使用心得﹍(2) 護眼檯燈 + 環境優化所以 Chrome 已經不需另外處理高對比模式,只需改一下字型就好,操作方式為:
  • 右上角選單圖示 → 設定 → 外觀 →「字型大小」改成「大」→「自訂字型」改成最黑、最粗的微軟雅黑體(Microsoft Yahei)即可
  • 提醒一下,改 Chrome 字型只是加減做的動作,因為不是每個網站都能成功套用(要看 Chrome 的 CSS 語法能否覆蓋該網站的設定)
paperlike-pro-eink-monitor-4.png-E-ink 螢幕 Paperlike Pro 使用心得﹍(2) 護眼檯燈 + 環境優化2. PTT如果常用 PTT 的話,建議使用網頁版的「PttChrome」最方便調整,原因如前所述,新版 Chrome 會自動偵測作業系統是否使用高對比模式,自動將 PttChrome 改成白底黑字,如此不必煩惱如何微調顏色的問題。 另外需要調整的是字體,因為預設字型「新細明體」在 Paperlike Pro 視覺體驗相當差,以下參考討論串「關於PTTCHROME的字體設定」說明如何改成「微軟雅黑」:
  • 進入 PttChrome 頁面後,按滑鼠右鍵 → 設定
  • 一般 → 介面 → 字型 → 輸入「SymMingLiu,Microsoft Yahei」即可
下面是 PttChrome 在 Paperlike Pro 上的效果,字體看起來是不是很舒服呢: paperlike-pro-eink-monitor-5.jpg-E-ink 螢幕 Paperlike Pro 使用心得﹍(2) 護眼檯燈 + 環境優化3. 文書軟體我常用的文書處理為 Notepad++,寫程式使用 Sublime Text 3,主要需改成淺底的布景主題,例如「Solarized-light」,如果可以的話另外也把字型改成微軟雅黑、或粗體 。 以下補幾張作業效果實拍,希望本篇對於「文書寫作」、「程式設計師」等長時間用眼的工作,如果想要尋找護眼神器時可以做為參考。 Notepad++: paperlike-pro-eink-monitor-6.jpg-E-ink 螢幕 Paperlike Pro 使用心得﹍(2) 護眼檯燈 + 環境優化 Sublime Text 3: paperlike-pro-eink-monitor-7.jpg-E-ink 螢幕 Paperlike Pro 使用心得﹍(2) 護眼檯燈 + 環境優化
更多 Eink 產品相關文章:

使用 Node.js 爬蟲定期抓網頁資料,結合 Google 試算表作為資料庫

$
0
0
使用 Node.js 爬蟲定期抓網頁資料,結合 Google 試算表作為資料庫上一篇「Node.js 爬蟲開發新手技巧﹍Google Apps Script 替代品」說明了為何我選擇 Node.js 作為爬蟲程式,並搭配 Google 試算表這個免費雲端資料庫,只要學會 Javascript 就能通吃「前端+後端+資料庫」,非常方便好上手。 閱讀本篇之前最好先瞭解上一篇的這些內容:
  • 建立 Node.js 開發環境
  • 操作開發工具 Sublime Text 3
  • Node.js 原生/外部模組如何引用
  • 同步/非同步的概念與技巧
接下來本篇會說明爬蟲需用到的第三方模組,提供範例,及瞭解 Windows 如何定期自動執行爬蟲程式。 (圖片出處: pixabay.com)

一、安裝 Axios、Cheerio 模組

以下分別說明兩個 Node.js 爬蟲會用到的重要模組。 1. Axios Jquery 爬取網頁資料使用的方式為 $.ajax,Google Apps Script(簡稱GAS) 爬取網頁資料使用的方式為 UrlFetchApp.fetch。而 Node.js 爬取網頁有很多模組可用,例如: 本篇介紹的是比較熱門的第三方模組 Axios: 使用前需要先安裝,用 npm 或 yarn 都可以: npm i axios -g yarn global add axios2. Cheerio爬回來的網頁資料,無論是 HTML 或 XML 格式都不方便處理,此時需要一個類似 Jquery 的工具來操作 DOM 比較方便。而 Node.js 知名的「類 Jquery」第三方模組為 Cheerio: 使用前需要先安裝,用 npm 或 yarn 都可以: npm i cheerio -g yarn global add cheerio

二、Node.js 爬蟲範例

1. 取得 HTML 資料爬網頁 HTML 內容難度最低,使用 Cheerio 操作 DOM 會更方便(使用技巧可參考「Cheerio 輕鬆解析 HTML 與 XML 」)。 使用 Node.js 爬蟲定期抓網頁資料,結合 Google 試算表作為資料庫那麼就以本站 WFU BLOG 為例,如上圖,練習爬取「本站服務」區塊的文章標題及圖片,資料位於 #HTML8 之下每個 .item 裡的的 .title 及 .thumb。 var axios = require("axios"), cheerio = require("cheerio"), url = "https://www.wfublog.com/"; axios.get(url).then(function(res) { var data = res.data, $ = cheerio.load(data), title_thumb_array = []; $("#HTML8 .item").each(function () { var $this = $(this), title = $this.find(".title").text(), thumbUrl = $this.find(".thumb img").attr("src"); title_thumb_array.push([title, thumbUrl]); }); console.log(title_thumb_array); });下圖為執行結果,成功! 使用 Node.js 爬蟲定期抓網頁資料,結合 Google 試算表作為資料庫2. 取得 JSON 資料如果網頁內容是用 JS 動態產生,那麼撈 HTML 資料就沒用了,此類網頁可參考「製作網路爬蟲工具抓動態產生的網頁資料」,用 Chrome 開發人員工具找出儲存資料的連結。 使用 Node.js 爬蟲定期抓網頁資料,結合 Google 試算表作為資料庫本篇同樣以 NBA 官網作為範例,找出當日的比賽結果。找出 json 檔的流程省略,如上圖,今天是總冠軍賽最後一場,勇士 4-2 獲勝,資料檔案放在 scoreboardv3.json: var axios = require("axios"), url = "https://cdn.nba.com/static/json/staticData/scoreboardv3.json"; axios.get(url).then(function(res) { var data = res.data, scoreboard = data.scoreboard; console.log(scoreboard); });下圖為執行結果,成功! 使用 Node.js 爬蟲定期抓網頁資料,結合 Google 試算表作為資料庫

三、寫入資料庫

1. 寫入檔案處理完爬蟲資料後,寫入檔案可用原生模組 fs(教學文章可參考「Node.js 檔案系統」),操作方式如下: var fs = require("fs"); fs.writeFile("檔案路徑及檔名", "檔案內容"); // 寫入檔案 fs.appendFile("檔案路徑及檔名", "新增內容"); // 新增內容至檔案2. 寫入 Google 試算表將資料寫入資料庫可以有更多的應用方式及情境,例如寫入 Google 試算表,可以隨時從網路存取非常方便,這部分的操作可參考「用 Google Apps Script 操作 Google 試算表」系列文章。

四、Windows 自動執行程式

以前使用 GAS 可以設定自動排程,Google 會自動在雲端幫我們執行,不會有忘記的時候,但缺點如前一篇所提,每次最多只能執行 6 分鐘。 如果 Node.js 爬蟲任務需要每天定時撈資料並自動處理後續,有兩種作法: 1. Node.js 排程模組可參考「node-schedule模塊的使用」,安裝 node-schedule 這個第三方模組來進行設定。 這個方法適合已經執行 Node.js 以後,再呼叫模組來進行排程,也等於是半手動排程,不適合機械化執行。 2. Windows 排程如果想要電腦開機後,每天設定的時段一到自動執行,可利用 Windows 內建的排程工具,參考「如何設定工作排程」,以 Win7 為例:
  • Win+R→ taskschd.msc → 可開啟工作排程器
  • 建立基本工作 → 填入名稱 → 設定執行頻率 → 設定開始時間 → 啟動程式
  • 「瀏覽」後找出、或填入 node.exe 完整路徑 →「新增引數」填入要執行的 js 檔名 →「開始位置」填入這個 js 檔的路徑
  • 之後「下一步」到完成即可
這樣的做法需要每天記得手動開機,跟 GAS 還是差了一點點。除非有閒置的主機,例如 24 小時不關機,或是想辦法自動開機、自動執行排程、自動關機,就看是否要花這樣的心思了。
更多「爬蟲」相關技巧:
Viewing all 784 articles
Browse latest View live