上篇文章咱們談了一下puppeteer是什麼,以及具體能作什麼,但文中談到的在咱們平常開發中並不經常使用到,截圖咱們有截圖工具、前端自動化測試有phantomjs、selenium。不只如此,爲了SEO,前端基本都會作SSR,爬取這樣的頁面的話python得益於強大的模塊,具備得天獨道的優點。也許有人會問,那對於某些後臺管理系統,是沒有作SSR的,此時puppeteer的優點不就體現出來了嗎?對於此種狀況,首先,爬管理系統的數據的話須要有帳號密碼,咱們沒有。那若是是咱們本身的系統的話,數據都是本身的,我還須要爬嗎?
前端
額。。。。node
pupueteer看來彷佛並無想象中的那麼強大。但實際狀況下並不是如此,雖然有些功能以前存在的一些框架也能作到,但畢竟對於咱們前端開發來講,要想掌握新的技術就須要去學習新的語言,這樣的話成本就很大了。python
pupueteer提供了簡潔的API和豐富的接口,並且其是一個nodejs庫,因此從學習角度來說對前端很友好,上手快。接下來就來具體描述一個在實際開發過程當中使用puppeteer的場景。react
在咱們公司前端開發的過程當中,大部分項目要去接CAS,什麼是CAS呢,走你,其目的是爲了獲取COOKIE,以便於與後端進行交互。我司目前常見的場景存在三種形式。git
1.前端網關nodejs,主要用於轉換dubbo協議,獲取數據,其項目中會用nodejs去接casgithub
2.有些應用,服務端接口須要登陸cas後拿到回調的cookie去請求數據,而此時前端要配置代理,模擬cas登陸,拿到cookie後寫在header裏後端
3.有些應用,直接登陸相關應用的開發環境,而後把cookie拿過來經過document.cookie寫到本地環境進行開發跨域
第一種狀況由於線上須要cas登陸,暫且不表。bash
但對於後面兩種狀況,這裏能夠簡單分析下,其實2和3都是在本地開發的時候拿到登陸cas後的cookie,而後在請求數據的時候把cookie帶回去拿到數據。但要放到服務器的時候其實是前端把靜態資源所有打包成某一個或若干個js文件(通常不會超過3個)。因此問題就變成了咱們怎麼在開發環境方便的拿到登陸cas成功後的cookie。若是對於一個熟悉cas sso原理的話,其對接一下cas可能會很快,但弊端就是要新搭一個node服務,寫一些登陸cas,拿cookie的流程,並且若是針對不一樣權限角色的話,每次登陸新的角色,都要從新用不一樣角色去登陸系統,去拿cookie(咱們在開發運維發佈平臺便是如此,涉及admin,運維,開發,測試,測試經理等不一樣角色,每次功能有摻和都是一個痛苦的切換cas登陸拿cookie的過程); 若是對於一個不明其理的開發來講,這無異於一枚張榜炸彈,你接口跨域我能夠很簡單的作下代理,cas, w**fk, 告辭.......服務器
那如何在開發環境用puppeteer作到拿cookie的過程呢?
(敲黑板) 劃重點啦。
以我負責開發的運維發佈平臺爲例, 其實現思路以下
代碼以下:
const puppeteer = require("puppeteer");
let cookie = {
name: "JSESSIONID",
value: "",
domain: "localhost",
url: "http://localhost:3000/",
path: "/",
httpOnly: true,
secure: false
};
const role = process.argv.pop();
const getRole = role => {
return {
a: { //系統管理員
username: "admin",
password: "123456"
},
qa1: { //測試經理
username: "04688",
password: "123456"
},
qa: { //測試
username: "01522",
password: "123456"
},
dev: { //開發
username: "04588",
password: "123456"
},
ops: { //運維
username: "04141",
password: "123456"
}
}[role];
};
class Launch {
constructor(username, password) {
this.username = username;
this.password = password;
this.flag = true; //用來判斷攔截第一次302
}
async init(page, browser) {
// <!-- 模擬cas登陸 -->
const casBrowser = await puppeteer.launch();
const loginPage = await casBrowser.newPage();
await loginPage.goto("CAS開發環境地址");
await loginPage.type("#username", this.username);
await loginPage.type("#password", this.password);
await loginPage.click("input[type=submit]");
await loginPage.waitFor(1000);
const cookies = await loginPage.cookies();
cookies.map(v => {
if (v.name === cookie.name) {
cookie.value = v.value;
}
});
await casBrowser.close();
// <!-- 拿到cookie後,關閉該實例 -->
// <!-- 打開本地環境流程 -->
let appBrowser = browser, appPage = page;
if (appPage) { // 若是cookie過時,直接在該實例上setCookie,無需新開實例
await appPage.setCookie(cookie);
await appPage.reload()
this.flag = true;
} else {
appBrowser = await puppeteer.launch({
headless: false,
});
appPage = (await appBrowser.pages())[0];
await appPage.setCookie(cookie); //設置cookie
const {
width,
height
} = await appPage.evaluate(() => {
return {
width: window.outerWidth,
height: window.outerHeight
};
});
await appPage.setViewport({
width,
height
});
await appPage.goto("http://localhost:3000/");
}
// <!-- 本地流程結束 -->
//監聽請求
await appPage.on("response", async (res) => {
const status = res.status();
if (status === 302 && this.flag) { //cookie過時後,服務接口會重定向到cas登陸頁,因此只需攔截302便可知道cookie是否過時,固然也可和後端約定一個狀態,如401
this.flag = false;
this.init(appPage, appBrowser); //cookie過時,從新模擬登陸cas獲取新的cookie
}
})
}
}
const {
username = "admin", password = "123456"
} = getRole(role) || {} //默認登陸admin帳號
const launch = new Launch(username, password);
launch.init()
複製代碼
上述setCookie是根據我司統一cookie而寫,具體狀況具體分析
簡單明瞭的完成了拿cookie的過程,省去了繁瑣的設置代理去登陸cas的過程, 。至此,咱們完成了puppeteer在實際開發中的應用,大大減小了登陸,切換帳號的過程。
其實我用QuickTime錄製了一段小視頻,可是轉換gif的時候轉不了,不知道爲啥,因此gif圖就不傳了,自行腦補哈。
大家有沒有發現我在告辭
後面用了7個.
, 皮一下確實很開心,哈哈哈 點我點我 .......
關於puppeteer ssr的場景就很少說了,通常都會在服務端作掉,關於react ssr的例子,詳見 嘿嘿嘿