文中只是拿小程式做例子,你可以套用到想用的任何地方。
場景
你們有個產品是基於微信小程式的,然後呢,微信小程式後臺有相關的資料支撐,一般顯示如下:
微信小程式預設後臺
稍微有一些規模的小程式,一般來說可能會接入各種亂七八糟的埋點方案,然後,我們自己也有一套與之對應的後臺管理(資料後臺)。
這個時候,作妖的業務方來了,跟產品說,我們希望把微信後臺的一些資料整合到我們自己的資料中臺去……
問題
這個需求可行嗎?有一些爬蟲經驗的小夥伴可能就要說了,行是行,但是成本太高了。
作為一名聽說過爬蟲的你,可能就迷惑了,這怎麼做?爬微信後臺的資料嗎?
一來,資料介面是加密的;二來,要死的微信後臺,時不時把你踢出去;三來,恐怕不想面向監獄程式設計吧。
這也是為什麼成本高的原因,資料不好獲取,不定時提出登入狀態還需要掃碼登入(只能掃碼,不能長按識別哦,你可以試試看),非公開資料如果被公開還有可能進局子。
就在大家一籌莫展,準備讓苦逼的業務方繼續在兩個平臺跳來跳去的時候,你們的資深前端說了句,“你們是不是太小看前端了?”
解決方案
其實說起來,解決方案很簡單,只是在於你是否這麼搞過而已。
首先,我們開啟控制檯,解析一下這個頁面的標籤結構:
你會發現,這個資料塊的 class 是
mod_default_box,並且為了保險,你還重新整理了,發現沒變,於是乎,你就想到了,我自己去繪製一個塊,然後放到它前面(後面一樣)不就好了,然後拿到資料填充進去,嘿!我不能爬你微信後臺資料,還不能讓我自己把資料插到你的後臺裡面嘛?
你一拍桌子,我去……妙啊!
先是 querySelectorAll(‘。mod_default_box’) 找到第二個是你的目標。
吶,你要的益達,不對,你要的模組來了。
這裡是偷懶,因為我不知道你是什麼鬼業務,所以這裡複製了一份以假亂真。你自然是根據自己需要的
業務來手寫 HTML 了。
為了搞得更像一點,我做了一點點修改,如下:
是不是看出來差異了?
到此你拿到了第一份可用的程式碼:
let wx_module = document。querySelectorAll(‘。mod_default_box’)[1]// 以下根據業務特殊處理let new_moduel = wx_module。cloneNode(true)wx_module。insertAdjacentElement(‘beforeBegin’, new_moduel)new_moduel。querySelector(‘h4’)。innerText = ‘我就是個Demo’
還剩下兩個問題:
不可能每次進來都需要複製這份程式碼吧,業務方那些技術小白也不會啊
介面呢?我要拿資料啊
別急,還有。
掃尾處理
問題一,複製程式碼這個事情肯定很傻,我們需要做到的是,不需要開啟控制檯,不需要 Ctrl + V 就可以直接執行,那麼為了方便,我們加個
alert('我是自動執行')
來標記下。
忘了說了,你想自動,就得給業務方使用人員安裝下外掛,這個沒辦法……
如果你是個前端,相信對 FeHelper 應該很熟悉,他有自帶的油猴工具,當然了,你也可以去下載老油猴,這個隨便你,我只是懶得裝太多,就用一個了,老油猴這樣的:
這是 Edge 的搜尋結果,如果你用的是 Chrome ,請自行處理。
我們拿 FeHelper 的面板舉例子:
除了隨便取的名字外,最底下的就是程式碼,上面框框標記的是匹配的地址,支援萬用字元。
因為微信小程式後臺首頁的連結是這樣的:https://mp。weixin。qq。com/wxamp/index/index?lang=zh_CN&token=xxxxxxxx
通配成 https://mp。weixin。qq。com/wxamp/index/index* 這樣,就意味著,哪怕token重新整理了或其他語言,都可以執行。
當然,你也可以直接一個*號,不過那樣就所有頁面都會執行,就很奇怪。
ok,我們關閉偵錯程式,重新整理頁面看看:
好像行了……
但是你點選確認後,發現,沒卵用,這個原因可以從頁面看出來,你的指令碼運行了,但是目標模組還沒有,所以你複製錯了,不信你往下拉,你會發現,指令碼是有bug的。
因為 document。querySelectorAll(‘。mod_default_box’)[1] 不安全,導致拿錯資料了,我們再進行《一點點》最佳化:
(() => { function handler() { // 以下根據業務特殊處理 let wx_module = document。querySelectorAll(‘。mod_default_box’)[1] let new_moduel = wx_module。cloneNode(true) wx_module。insertAdjacentElement(‘beforeBegin’, new_moduel) new_moduel。querySelector(‘h4’)。innerText = ‘我就是個Demo’ alert(‘我是自動執行’) } let interval = setInterval(() => { let wx_modules = document。querySelectorAll(‘。mod_default_box’) // 這種 === 4 的程式碼都是不健壯的,根據具體業務處理,這裡僅僅是示例 if (wx_modules。length === 4) { clearInterval(interval) handler() } }, 1000)})()
說白了,就是一秒查一次,是不是跟我業務匹配(我這裡 Demo 的業務就是發現有四個模組),沒匹配即繼續查,匹配了,就執行業務程式碼。
問題二
這個實際需要你們後端支援,放開 CORS 的跨域設定(建議單獨給目標網站放開,如這裡的微信小程式後臺)。
我在這裡模擬下不考慮跨域的情況,就是直接 GET 來請求這個網頁的 HTML 檔案內容。
(() => { function handler() { // 以下根據業務特殊處理 let wx_module = document。querySelectorAll(‘。mod_default_box’)[1] let new_moduel = wx_module。cloneNode(true) wx_module。insertAdjacentElement(‘beforeBegin’, new_moduel) new_moduel。querySelector(‘h4’)。innerText = ‘我就是個Demo’ alert(‘我是自動執行’) fetch(location。href)。then(ret => ret。text())。then(text => new_moduel。querySelector(‘h4’)。innerText = text。slice(0, 15)) } let interval = setInterval(() => { let wx_modules = document。querySelectorAll(‘。mod_default_box’) // 這種 === 4 的程式碼都是不健壯的,根據具體業務處理,這裡僅僅是示例 if (wx_modules。length === 4) { clearInterval(interval) handler() } }, 1000)})()
注意“我就是個Demo”這裡的變化,後面填充的內容是請求的 HTML 文件的字元。
搞定!!!
總結
其實很簡單,主要還是你能不能想到這個方案,並且善用工具而已。