Electron + Puppeteer + Robotjs 實現工做自動化

前言

當年在百度搜索團隊的時候作的一個小工具,能夠把一些平常工做自動化,確實解決了一些問題。正值五一,分享點有趣的東西。但願能給你們一些啓發。javascript

故事的開始

就在不久以前,我入職了百度的搜索團隊,參與 pc 搜索的一些業務。搜索業務這麼多年,歷史積累的技術債務蠻多的,其中影響效率的主要是開發過程的問題。好比,首頁常常要切換登陸態和非登陸態來看效果,每次切換都要手動輸入用戶名密碼,並且由於有的 http 的資源會涉及跨域而失敗,須要單獨請求下。好比,每次上線以前都要過幾遍 checklist,繁瑣也花時間,因此幾乎沒人會認真的一遍遍過 checklist,等等,一些問題。並且由於咱們開發時也是直接代碼推到服務器來看效果,因此常常登陸跳板機和切換不一樣機器,須要記住一些機器名和密碼,也很耗費時間。我在熟悉流程和架構之餘就一直在想着怎麼去解決這些痛點。有一次走查,UE 和 PM 說每次走查的登陸都好麻煩哦。聽到這,發現這是個共性問題,就以爲能夠正式着手作了。前端

最初的目標

最開始的目標就是一鍵登陸和退出登陸,一鍵跑 checklist,還有一鍵登陸跳板機和一鍵切環境,涉及到瀏覽器的自動化,天然就想到了 puppeteer,一個用於前端自動化測試的庫。而登陸跳板機和切換登陸的機器不在瀏覽器中,須要涉及到系統的自動化(鼠標和鍵盤事件等),最後選擇了 robotjs。這倆庫都是在node環境下才能跑的,而UE和PM的電腦不會裝 node,加上功能多了之後有個圖形界面會更好,就想到了 electron(提供node環境和圖形界面)。vue

先簡單介紹下這三門技術:java

1. Puppeteer

Puppeteer 是一個 Node 庫,它提供了一些高級API來經過 DevTools 協議控制 Chromium 或 Chrome。node

它能作的不少,好比:web

  • 生成頁面的截圖和PDF;
  • 抓取 SPA 並生成預渲染的內容(即「SSR」);
  • 從網站抓取內容;
  • 自動錶單提交,UI 測試,鍵盤輸入等;
  • 建立一個最新的自動化測試環境。 使用最新的 JavaScript 和瀏覽器功能,直接在最新版本的 Chrome 中運行測試;
  • 捕獲你網站的 Timeline Trace,來幫助診斷性能問題;

Most things that you can do manually in the browser can be done using Puppeteer!chrome

它提供了這些apinpm

  • Puppeteer:經過DevTools協議與瀏覽器通訊,建立Browser實例。
  • Browser:瀏覽器實例,能夠擁有多個BrowserContext。
  • BrowserContext:定義了一個瀏覽會話,能夠擁有多個Page。
  • Page:至少有一個Frame:主框架。 可能存在由iframe或框架標籤建立的其餘幀。
  • Frame: 至少有一個執行上下文 - 默認執行上下文 - 執行框架的JavaScript。 Frame可能有與擴展相關聯的其餘執行上下文。
  • Worker: 具備單個執行上下文,便於與WebWorkers交互。

2. Robotjs

Robotjs 是 nodejs 的第一個用於桌面自動化的庫。他能自動化鼠標、鍵盤和讀取屏幕,而且提供了 Mac, Windows, Linux 的跨平臺支持。json

3. Electron

Electron 可讓你使用純 JavaScript 調用豐富的原生(操做系統) APIs 來創造桌面應用。 你能夠把它看做一個 Node. js 的變體,它專一於桌面應用而不是 Web 服務器端。api

Electron進程分爲主進程和渲染進程,Electron 運行 package.json 的 main 腳本的進程被稱爲主進程。 在主進程中運行的腳本經過建立web頁面來展現用戶界面。 一個 Electron 應用老是有且只有一個主進程, 每一個 Electron 中的 web 頁面運行在它的叫渲染進程的進程中。因此作 electron 應用會常常用到 ipc 來作進程通訊,不少操做只能在主進程作。

以後界面的展現用任何組件方案均可以,原本想用 san(百度的前端框架),可是 san 沒有 electron 的腳手架,考慮到效率,暫時選用了 electron-vue 來建立項目。

最初的用戶

最初的版本的走查工具,界面是這樣的:

輸入 url,點擊登陸,就是經過 puppeteer 來啓動一個瀏覽器,而且自動跳轉到登陸頁面,輸入用戶名密碼,以後點擊登陸,跳轉到輸入的 url。這裏只是 pc 的,移動端的話啓動的時候設置下 ua 就行了。

browser = await puppeteer.launch({
  executablePath: getConfig('chromePath'),
  headless: false,
  defaultViewport: {
    width: 0,
    height: 0
  },
  args: [
    '--allow-running-insecure-content', 
    '--disable-web-security',
    '--auto-open-devtools-for-tabs'
  ]
})
複製代碼

啓動瀏覽器的時候經過 headless 設置爲 false,puppeteer 支持啓動沒有界面的瀏覽器,主要是用於自動化測試,但咱們這裏須要界面。

而後經過 executablePath 指定一個本地的 chrome 的啓動路徑,能夠在設置裏面修改(通常 chrome 的路徑是固定的),這樣使用本地的 chrome 來跑,不用連 chrome 一塊兒打包進去。

defaultViewport 設置爲 width:0 和 height:0 是爲了讓內容自動適應窗口大小。

--allow-running-insecure-content--disable-web-security 能夠禁止同源策略,這樣 https 網站加載 http 的跨域資源也不會報錯。

--auto-open-devtools-for-tabs 能夠打開新 tab 自動打開 dev tools(這個後續能夠加到設置中去讓用戶本身設置)。

以後又順手作了一個屏幕取色的功能,考慮到 ue 走查時可能會用到,實現是經過 ox-mouse 來監聽系統鼠標事件,而後經過 robotjs 來獲取鼠標所在位置的顏色,以後發送到 colorpicker 窗口作顯示。

import mouseEvent from 'osx-mouse'
import robot from 'robotjs'

 const mouseTrack = mouseEvent()
 mouseTrack.on('move', (x, y) => {
    let color = '#' + robot.getPixelColor(parseInt(x), parseInt(y))
    const colorPickerWin = BrowserWindow.getAllWindows().filter(item => item.name === 'colorPickerWin')[0]
    if (colorPickerWin) {
      colorPickerWin.webContents.send('color', color)
    }
})
複製代碼

最初的兩個用戶(PM 和 UE)都給了一致的確定,這讓我很開心。

擴展更多邊界

由於有了最初的一個場景的成功實踐,後面也就更有熱情去作了。最初的目標更多仍是針對開發者,因此開發者版本獨立作了一個工具。這方面能夠應用的場景就多了。

最開始作的事自動登陸跳板機和自動切環境的功能,真實的流程是打開終端,輸入ssh連接跳板機的命令,而後輸入密碼而且手機認證,手機認證這部分暫時沒有作自動化,也最好不要去作自動化,把以前的那些都作了自動化。最終效果是一點登陸跳板機,就能夠在如流手勢認證登錄了。實現仍是經過robotjs,先輸入command + space打開spotlight,而後輸入terminal.app,以後輸入命令和密碼。過程比較傻瓜式。

async function spolightOpen(appName) {
  robot.keyTap('space', ['command'])
  await delayPromise(500)
  robot.keyTap('delete')
  robot.typeString(appName)
  await delayPromise(2000)
  robot.keyTap('enter')
  await delayPromise(1000)
}

async function sshLogin(params) {
  await spolightOpen('terminal.app')

  robot.typeString('ssh xxx@baiduxxx.com')
  robot.keyTap('enter')
  await delayPromise(1000)
  robot.typeString('xxxxxx')
  robot.keyTap('enter')
}
複製代碼

自動跑 checklist 是自動化測試的範疇,puppeteer 很拿手,只要把操做步驟寫成腳本,而後在一些狀態下作效果的驗證就能夠了。

作完這些功能後,又會想到自動建立 icafe(百度內部的項目管理平臺)卡片(把 mrd(需求描述文檔) 的內容拿過來自動粘貼,自動輸入一些信息以後建立卡片,而且把關聯 cr 的代碼複製下來),自動建立提測單,自動建立上線單,自動發排期郵件,自動發週報等等。

不少平時手動的作的事情均可以自動來完成,包括瀏覽器裏的和系統級別的。

慢慢想到這一個個的功能都是圍繞代碼庫的,那是否是應該作一個代碼庫的管理,而後圍繞代碼庫的開發週期來作工具鏈的集成。

開發工具基本成型

這個階段我對開發工具的定義是作代碼庫的管理,(好比首頁分了好多模塊,能夠經過分類把一些模塊歸到一塊兒管理),而且圍繞代碼庫的開發流程提供一系列提效工具。能夠經過插件來擴展工具鏈。

大概設計的界面是這樣的

image.png

每一個代碼庫均可以在建立時輸入本地路徑和 icode(百度內部的代碼託管平臺) 路徑還有相關的開發和 pm 等信息,這樣能夠一鍵用 ide 打開本地代碼庫,在詳情裏能夠看到相關的人員的信息,而且點擊名字能夠一鍵打開如流中對應人員的對話框(基於 robotjs)。

而後會掃描代碼庫下的 package.json 中的 npm scripts,能夠在界面上執行,也能夠選擇在系統的 terminal 或者 ide 的 terminal 中執行。

選擇開發流程會看到每一個階段的tab,每一個tab下有這個階段可能用到的工具,好比開發時的一鍵登陸跳板機和切環境,排期階段的自動發排期郵件,自動建立icafe卡片,自測階段的自動登陸退出,上線階段的自動建立提測單等功能,實現方式同樣,就是模擬用戶的操做,經過瀏覽器自動化和系統的自動化來代替人來完成一些工做。

image.png

由於開發流程的入口藏得比較深卻很經常使用,又單獨提到了左側。此外一些其餘的工具也很經常使用,能夠放到工具箱裏面,好比可視化刪除本地 node_modules,屏幕取色,屏幕尺子等等。

工具箱中工具備兩種觸發方式,一鍵觸發和定時任務觸發,好比每兩週都自動列一下可用的會議室,而後準備好郵件,只須要確認下信息,而後點發送就能夠自動訂會議室,有的工具不須要定時功能。定時功能的實現是經過 node-schedule,它的api風格是這樣的:

const schedule = require('node-schedule');

const  scheduleCronstyle = ()=>{
  //每分鐘的第30秒定時執行一次:
    schedule.scheduleJob('30 * * * * *',()=>{
        console.log('scheduleCronstyle:' + new Date());
    }); 
}

scheduleCronstyle();
複製代碼

經過 * * * * * * 來指定時間間隔

*  *  *  *  *  *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │  |
│ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
│ │ │ │ └───── month (1 - 12)
│ │ │ └────────── day of month (1 - 31)
│ │ └─────────────── hour (0 - 23)
│ └──────────────────── minute (0 - 59)
└───────────────────────── second (0 - 59, OPTIONAL)
複製代碼

整個工具的思路是圍繞代碼庫的開發流程的一些自動化工具,基於 puppeteer 和 robotjs,不一樣的場景下須要的工具不一樣,因此插件功能是頗有必要的,若是插件足夠豐富之後,咱們能夠在開發時選擇適合本身場景的插件來安裝,會自動添加一些階段的工具。固然,這個尚未實現。

設置裏面是設置各類帳號信息,和一些功能的開啓關閉等。

鎖屏就是利用了系統的鎖屏,中午出去吃飯前點一下就能夠了。

開發到這裏時,距離剛開始的想法已通過去半個月了,雖然尚未開發完成,可是這個工具的定義有了比較清晰的認知。

回顧

雪中送炭和錦上添花

把一個小工具作的比較大之後,會有些懷疑這個工具的必要性,但最終仍是以爲它是有意義的。首先,他解決了我在pc場景下的痛點問題,自動登陸退出、自動跑checklist、一鍵登陸跳板機和切環境等,這是這個工具解決的比較痛點的問題,屬於「雪中送炭」的功能。後面有些功能有更好,沒有也不會影響很大,屬於「錦上添花」的功能。

但提供插件機制以後,能夠針對不一樣場景的痛點問題作更多的擴展,集成更多「雪中送炭」的功能。因此提供了代碼庫管理和劃分開發流程還有提供插件機制會使得這個工具更有想象空間。

那天羣裏開玩笑說你可能須要這個工具的20個理由,其實沒有達到,如今也就三、4個用這個工具的理由,但隨着不斷地完善,可能他會成爲開發時很重要的一個輔助工具呢。

過程當中的一些坑

不得不說,electron 的坑是真的多,我簡單列一下幾個重要的。

  1. electron 提供的 node 環境中 node 版本和本地的 node 版本要分開,運行時若是報版本不兼容,你再怎麼更新本地 node 版本也沒用,要去更新 electron 版本,electon 版本和內置 node 版本的關係能夠去官網查。由於包依賴的是 electron 版本,因此一些二進制包用 npm rebuild xxx 也是沒用的,要用 electron-rebuild xxx。

  2. electron 默認沒有提供任何快捷鍵,因此打包後,你發如今輸入框中 command + v 都無論用,這須要本身去設置。但不能觸發別的應用的快捷鍵這一點對以前實現的系統自動化的功能有毀滅性的打擊,由於實現系統自動化時時大量用到了別的應用的快捷鍵,但打包後發現不支持!絞盡腦汁思考後想出了一種方案,mac 應用內不支持觸發別的系統的快捷鍵,父子進程都不行,那麼兩個獨立的進程不久能夠了,因此在本地起了一個單獨的服務器,經過請求的參數來觸發不一樣的自動化功能。可是多了一個應用外的本地服務器的依賴,還沒想好應用應該如何去分發和管理。但至少是可行的。

最後

最初只是爲了作個自動化的登陸的工具,但作着作着發現能夠作更多,不少場景下是須要一些自動化工具的。他能把咱們工做中一些耗費時間卻沒有多大必要去手動作的事情給自動完成,釋放咱們的時間作一些更有意義的事情。插件機制讓它變得更有想象空間,也許能夠圍繞這個工具造成生態。

相關文章
相關標籤/搜索