我被分配了一個繁瑣的任務,就是要給100個相同的站點作一樣的配置。曾經就有作過相同的事,那時還不會寫腳本,全靠手動配置。機械的配置了兩天的時間,身體感受被掏空。因此此次我決定仍是寫一個腳本自動的進行配置。node
中文版資料:https://juejin.im/entry/59ad6c4f5188250f4850dccclinux
官方文檔(英文):https://github.com/GoogleChrome/puppeteergit
Puppeteer的API(英文):https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#github
只安裝了node環境chrome
引用了https://juejin.im/entry/59ad6c4f5188250f4850dcccnpm
項目都是以建立文件夾開始。windows
$ mkdir thal $ cd thal
$ mkdir thal $ cd thal
初始化 NPM,填入一些必要的信息。api
$ npm init
$ npm init
安裝 Puppeteer
。因爲 Puppeteer
並非穩定的版本並且天天都在更新,因此若是你想要最新的功能能夠直接經過 GitHub 的倉庫安裝。ruby
$ npm i --save puppeteer
$ npm i --save puppeteer
Puppeteer 包含了本身的 chrome / chromium 用以確保能夠無界面地工做。所以每當你安裝/更新 puppeteer 的時候,他都會下載指定的 chrome 版本。async
3.2.1 工程的目錄結構
node_modeles中的內容是從git上拉下來的,src文件夾寫得是我本身的代碼,我執行的是addConfig裏面的文件,common中是一些基礎性配置,contentHub配置內容較多,因此我另建了一個contentHub文件夾。
3.2.2 common.js文件寫的是經常使用的功能函數,這個是能夠通用的。以前我不是說實現不了全選的功能嗎,其實能夠調用common中的setOption函數實現全選的功能
1 const config = require('./config'); 2 3 //根據選擇器sel選擇id爲val的子項 4 async function setOption(page, sel, val) { 5 await page.evaluate((sel, val) => { 6 document.querySelector(`${sel} > option[value="${val}"]`).selected = true; 7 element = document.querySelector(sel); 8 var event = new Event('change', { bubbles: true }); 9 event.simulated = true; 10 element.dispatchEvent(event); 11 }, sel, val); 12 } 13 14 //在id爲sel的輸入框中輸入val 15 async function setTextVal(page, sel, val) { 16 await page.evaluate((sel, val) => { 17 document.querySelector(sel).value = val; 18 element = document.querySelector(sel); 19 var event = new Event('change', { bubbles: true }); 20 event.simulated = true; 21 element.dispatchEvent(event); 22 }, sel, val); 23 } 24 25 //判斷選擇器是否存在 26 async function isExist(page, selector) { 27 var is = await page.evaluate((sel) => { 28 const element = document.querySelector(sel); 29 if (!element) { 30 return false; 31 } else { 32 return true; 33 } 34 }, selector); 35 36 return is; 37 } 38 39 //導入單個配置 40 async function importSingleConfiguration(page, configType, configContent) { 41 const confirmBtn = 'input[value="Confirm"]'; 42 const configTypeSel = '#edit-config-type'; 43 await setOption(page, configTypeSel, configType); 44 await page.click('#edit-import'); 45 await setTextVal(page, '#edit-import', configContent); 46 await page.click('#edit-submit'); 47 await page.waitForNavigation(); 48 49 const is = await isExist(page, confirmBtn); 50 if (is) { 51 await page.click(confirmBtn); 52 await page.waitForNavigation(); 53 await page.waitFor(3 * config.stepWait); 54 } 55 } 56 57 //設置checkbox中子項的值 58 async function setCheckBoxVal(page, sel, val) { 59 await page.evaluate((sel, val) => { 60 document.querySelector(sel).checked = val; 61 element = document.querySelector(sel); 62 var event = new Event('change', { bubbles: true }); 63 event.simulated = true; 64 element.dispatchEvent(event); 65 }, sel, val); 66 } 67 68 module.exports = { 69 setOption: setOption, 70 setTextVal: setTextVal, 71 importSingleConfiguration: importSingleConfiguration, 72 isExist: isExist, 73 selectAll: selectAll, 74 setCheckBoxVal: setCheckBoxVal, 75 76 }
3.2.3 config.js文件中申明瞭許多基礎性配置
我要跳轉的網站url,登陸的用戶名和密碼,站內頁面跳轉的路徑等信息都配置在這個文件裏面
const baseUrlArray = [ { url: '', langcode: '', }, ]; const baseUrl = baseUrlArray[0].url; const getUrl = (index) => { const baseUrl = baseUrlArray[index].url; return { hubConnection: `${baseUrl}/example`, }; } const getLangCode = (index) => { return baseUrlArray[index].langcode; } module.exports = { secondWait: 1000, stepWait: 5000, username: '', password: '', credentials: { username: '', password: '', }, baseUrl: baseUrl, baseUrlArray: baseUrlArray, urls: getUrl(0), getUrl: getUrl, getLangCode: getLangCode, }
3.2.4 login.js
1 const config = require('./config'); 2 3 async function login(page, url = null) { 4 5 //fill authenticate user name and password 6 await page.authenticate(config.credentials); 7 8 // goto login page 9 await page.goto(url ? url : config.urls.login); 10 const agreeButton = await page.$('#block-popup .btn'); 11 await agreeButton.click(); 12 13 //fill admin user name and password 14 await page.focus('#edit-name'); 15 await page.keyboard.type(config.username); 16 await page.focus('#edit-pass'); 17 await page.keyboard.type(config.password); 18 19 const inputElement = await page.$('#edit-submit'); 20 await inputElement.click(); 21 22 await page.waitForNavigation(); 23 } 24 25 module.exports = login;
3.2.5 好了,登陸成功了
1.須要被其它頁面引用的函數,常量必需要在module.exports={}中申明
2.headles: false是設置自動化操做是可視化的
3.在輸入框中輸入值並覆蓋原有的值:
4.調用其餘頁面函數的聲明:const common = require('./common');
1.關於全選的功能,puppeteer並不支持全選,雖然官方文檔上面說了linux和windows支持全選,可是個人linux系統沒有任何反應,估計並不支持。補充一下,我這裏說的是實現不了ctrl+A的全選功能。