国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Puppeteer 初探

appetizerio / 3165人閱讀

摘要:獲取獲取上下文句柄執(zhí)行計(jì)算銷毀句柄除此之外,還可以使用意為在瀏覽器環(huán)境執(zhí)行腳本,可傳入第二個(gè)參數(shù)作為句柄,而則針對(duì)選中的一個(gè)元素執(zhí)行操作。

我們?nèi)粘J褂脼g覽器或者說(shuō)是有頭瀏覽器時(shí)的步驟為:?jiǎn)?dòng)瀏覽器、打開(kāi)一個(gè)網(wǎng)頁(yè)、進(jìn)行交互。

無(wú)頭瀏覽器指的是我們使用腳本來(lái)執(zhí)行以上過(guò)程的瀏覽器,能模擬真實(shí)的瀏覽器使用場(chǎng)景。

有了無(wú)頭瀏覽器,我們就能做包括但不限于以下事情:

對(duì)網(wǎng)頁(yè)進(jìn)行截圖保存為圖片或 pdf

抓取單頁(yè)應(yīng)用(SPA)執(zhí)行并渲染(解決傳統(tǒng) HTTP 爬蟲(chóng)抓取單頁(yè)應(yīng)用難以處理異步請(qǐng)求的問(wèn)題)

做表單的自動(dòng)提交、UI的自動(dòng)化測(cè)試、模擬鍵盤輸入等

用瀏覽器自帶的一些調(diào)試工具和性能分析工具幫助我們分析問(wèn)題

在最新的無(wú)頭瀏覽器環(huán)境里做測(cè)試、使用最新瀏覽器特性

寫爬蟲(chóng)做你想做的事情(奸笑

無(wú)頭瀏覽器很多,包括但不限于:

PhantomJS, 基于 Webkit

SlimerJS, 基于 Gecko

HtmlUnit, 基于 Rhnio

TrifleJS, 基于 Trident

Splash, 基于 Webkit

這里主要介紹 Google 提供的無(wú)頭瀏覽器(headless Chrome), 他基于 Chrome DevTools protocol 提供了不少高度封裝的接口方便我們控制瀏覽器。

簡(jiǎn)單的代碼示例

為了能使用 async/await 等新特性,需要使用 v7.6.0 或更高版本的 Node.

啟動(dòng)/關(guān)閉瀏覽器、打開(kāi)頁(yè)面
    // 啟動(dòng)瀏覽器
    const browser = await puppeteer.launch({
        // 關(guān)閉無(wú)頭模式,方便我們看到這個(gè)無(wú)頭瀏覽器執(zhí)行的過(guò)程
        // headless: false,
        timeout: 30000, // 默認(rèn)超時(shí)為30秒,設(shè)置為0則表示不設(shè)置超時(shí)
    });

    // 打開(kāi)空白頁(yè)面
    const page = await browser.newPage();

    // 進(jìn)行交互
    // ...

    // 關(guān)閉瀏覽器
    // await browser.close();
設(shè)置頁(yè)面視窗大小
    // 設(shè)置瀏覽器視窗
    page.setViewport({
        width: 1376,
        height: 768,
    });
輸入網(wǎng)址
    // 地址欄輸入網(wǎng)頁(yè)地址
    await page.goto("https://google.com/", {
        // 配置項(xiàng)
        // waitUntil: "networkidle", // 等待網(wǎng)絡(luò)狀態(tài)為空閑的時(shí)候才繼續(xù)執(zhí)行
    });
保存網(wǎng)頁(yè)為圖片

打開(kāi)一個(gè)網(wǎng)頁(yè),然后截圖保存到本地:

await page.screenshot({
    path: "path/to/saved.png",
});

完整示例代碼

保存網(wǎng)頁(yè)為 pdf

打開(kāi)一個(gè)網(wǎng)頁(yè),然后保存 pdf 到本地:

await page.pdf({
     path: "path/to/saved.pdf",
    format: "A4", // 保存尺寸
});

完整示例代碼

執(zhí)行腳本

要獲取打開(kāi)的網(wǎng)頁(yè)中的宿主環(huán)境,我們可以使用 Page.evaluate 方法:

// 獲取視窗信息
const dimensions = await page.evaluate(() => {
    return {
        width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight,
        deviceScaleFactor: window.devicePixelRatio
    };
});
console.log("視窗信息:", dimensions);

// 獲取 html
// 獲取上下文句柄
const htmlHandle = await page.$("html");

// 執(zhí)行計(jì)算
const html = await page.evaluate(body => body.outerHTML, htmlHandle);

// 銷毀句柄
await htmlHandle.dispose();

console.log("html:", html);

Page.$ 可以理解為我們常用的 document.querySelector, 而 Page.$$ 則對(duì)應(yīng) document.querySelectorAll。

完整示例代碼

自動(dòng)提交表單

打開(kāi)谷歌首頁(yè),輸入關(guān)鍵字,回車進(jìn)行搜索:

// 地址欄輸入網(wǎng)頁(yè)地址
await page.goto("https://google.com/", {
    waitUntil: "networkidle", // 等待網(wǎng)絡(luò)狀態(tài)為空閑的時(shí)候才繼續(xù)執(zhí)行
});

// 聚焦搜索框
// await page.click("#lst-ib");
await page.focus("#lst-ib");

// 輸入搜索關(guān)鍵字
await page.type("辣子雞", {
   delay: 1000, // 控制 keypress 也就是每個(gè)字母輸入的間隔
});

// 回車
await page.press("Enter");

完整示例代碼

復(fù)雜點(diǎn)的代碼示例

每一個(gè)簡(jiǎn)單的動(dòng)作連接起來(lái),就是一連串復(fù)雜的交互,接下來(lái)我們看兩個(gè)更具體的示例。

抓取單頁(yè)應(yīng)用: 模擬餓了么外賣下單

傳統(tǒng)的爬蟲(chóng)是基于 HTTP 協(xié)議,模擬 UserAgent 發(fā)送 http 請(qǐng)求,獲取到 html 內(nèi)容后使用正則解析出需要抓取的內(nèi)容,這種方式面對(duì)服務(wù)端渲染直出 html 的網(wǎng)頁(yè)時(shí)非常便捷。

但遇到單頁(yè)應(yīng)用(SPA)時(shí),或遇到登錄校驗(yàn)時(shí),這種爬蟲(chóng)就顯得比較無(wú)力。

而使用無(wú)頭瀏覽器,抓取網(wǎng)頁(yè)時(shí)完全使用了人機(jī)交互時(shí)的操作,所以頁(yè)面的初始化完全能使用宿主瀏覽器環(huán)境渲染完備,不再需要關(guān)心這個(gè)單頁(yè)應(yīng)用在前端初始化時(shí)需要涉及哪些 HTTP 請(qǐng)求。

無(wú)頭瀏覽器提供的各種點(diǎn)擊、輸入等指令,完全模擬人的點(diǎn)擊、輸入等指令,也就再也不用擔(dān)心正則寫不出來(lái)了啊哈哈哈

當(dāng)然,有些場(chǎng)景下,使用傳統(tǒng)的 HTTP 爬蟲(chóng)(寫正則匹配) 還是比較高效的。

在這里就不再詳細(xì)對(duì)比這些差異了,以下這個(gè)例子僅作為展示模擬一個(gè)完整的人機(jī)交互:使用移動(dòng)版餓了么點(diǎn)外賣。

先看下效果:

代碼比較長(zhǎng)就不全貼了,關(guān)鍵是幾行:

const puppeteer = require("puppeteer");
const devices = require("puppeteer/DeviceDescriptors");
const iPhone6 = devices["iPhone 6"];

console.log("啟動(dòng)瀏覽器");
const browser = await puppeteer.launch();

console.log("打開(kāi)頁(yè)面");
const page = await browser.newPage();

// 模擬移動(dòng)端設(shè)備
await page.emulate(iPhone6);

console.log("地址欄輸入網(wǎng)頁(yè)地址");
await page.goto(url);

console.log("等待頁(yè)面準(zhǔn)備好");
await page.waitForSelector(".search-wrapper .search");

console.log("點(diǎn)擊搜索框");
await page.tap(".search-wrapper .search");

await page.type("麥當(dāng)勞", {
    delay: 200, // 每個(gè)字母之間輸入的間隔
});

console.log("回車開(kāi)始搜索");
await page.tap("button");

console.log("等待搜素結(jié)果渲染出來(lái)");
await page.waitForSelector("[class^="index-container"]");

console.log("找到搜索到的第一家外賣店!");
await page.tap("[class^="index-container"]");


console.log("等待菜單渲染出來(lái)");
await page.waitForSelector("[class^="fooddetails-food-panel"]");


console.log("直接選一個(gè)菜品吧");
await page.tap("[class^="fooddetails-cart-button"]");

// console.log("===為了看清楚,傲嬌地等兩秒===");
await page.waitFor(2000);
await page.tap("[class^=submit-btn-submitbutton]");

// 關(guān)閉瀏覽器
await browser.close();

關(guān)鍵步驟是:

加載頁(yè)面

等待需要點(diǎn)擊的 DOM 渲染出來(lái)后點(diǎn)擊

繼續(xù)等待下一步需要點(diǎn)擊的 DOM 渲染出來(lái)再點(diǎn)擊

關(guān)鍵的幾個(gè)指令:

page.tap(或 page.click) 為點(diǎn)擊

page.waitForSelector 意思是等待指定元素出現(xiàn)在網(wǎng)頁(yè)中,如果已經(jīng)出現(xiàn)了,則立即繼續(xù)執(zhí)行下去, 后面跟的參數(shù)為 selector 選擇器,與我們常用的 document.querySelector 接收的參數(shù)一致

page.waitFor 后面可以傳入 selector 選擇器、function 函數(shù)或 timeout 毫秒時(shí)間,如 page.waitFor(2000) 指等待2秒再繼續(xù)執(zhí)行,例子中用這個(gè)函數(shù)暫停操作主要是為了演示

以上幾個(gè)指令都可接受一個(gè) selector 選擇器作為參數(shù),這里額外介紹幾個(gè)方法:

page.$(selector) 與我們常用的 document.querySelector(selector) 一致,返回的是一個(gè) ElementHandle 元素句柄

page.$$(selector) 與我們常用的 document.querySelectorAll(selector) 一致,返回的是一個(gè)數(shù)組

在有頭瀏覽器上下文中,我們選擇一個(gè)元素的方法是:

const body = document.querySelector("body");
const bodyInnerHTML = body.innerHTML;
console.log("bodyInnerHTML: ", bodyInnerHTML);

而在無(wú)頭瀏覽器里,我們首先需要獲取一個(gè)句柄,通過(guò)句柄獲取到環(huán)境中的信息后,銷毀這個(gè)句柄。

// 獲取 html
// 獲取上下文句柄
const bodyHandle = await page.$("body");
// 執(zhí)行計(jì)算
const bodyInnerHTML = await page.evaluate(dom => dom.innerHTML, bodyHandle);
// 銷毀句柄
await bodyHandle.dispose();
console.log("bodyInnerHTML:", bodyInnerHTML);

除此之外,還可以使用 page.$eval:

const bodyInnerHTML = await page.$eval("body", dom => dom.innerHTML);
console.log("bodyInnerHTML: ", bodyInnerHTML);

page.evaluate 意為在瀏覽器環(huán)境執(zhí)行腳本,可傳入第二個(gè)參數(shù)作為句柄,而 page.$eval 則針對(duì)選中的一個(gè) DOM 元素執(zhí)行操作。

完整示例代碼

導(dǎo)出批量網(wǎng)頁(yè):下載圖靈圖書

我在 圖靈社區(qū) 上買了不少電子書,以前支持推送到 mobi 格式到 kindle 或推送 pdf 格式到郵箱進(jìn)行閱讀,不過(guò)經(jīng)常會(huì)關(guān)閉這些推送渠道,只能留在網(wǎng)頁(yè)上看書。

對(duì)我來(lái)說(shuō)不是很方便,而這些書籍的在線閱讀效果是服務(wù)器渲染出來(lái)的(帶了大量標(biāo)簽,無(wú)法簡(jiǎn)單抽取出好的排版),最好的方式當(dāng)然是直接在線閱讀并保存為 pdf 或圖片了。

借助瀏覽器的無(wú)頭模式,我寫了個(gè)簡(jiǎn)單的下載已購(gòu)買書籍為 pdf 到本地的腳本,支持批量下載已購(gòu)買的書籍。

使用方法,傳入帳號(hào)密碼和保存路徑,如:

$ node ./demo/download-ituring-books.js "用戶名" "密碼" "./books"

注意:puppeteerPage.pdf() 目前僅支持在無(wú)頭模式中使用,所以要想看有頭狀態(tài)的抓取過(guò)程的話,執(zhí)行到 Page.pdf() 這步會(huì)先報(bào)錯(cuò):

所以啟動(dòng)這個(gè)腳本時(shí),需要保持無(wú)頭模式:

const browser = await puppeteer.launch({
    // 關(guān)閉無(wú)頭模式,方便我們看到這個(gè)無(wú)頭瀏覽器執(zhí)行的過(guò)程
    // 注意若調(diào)用了 Page.pdf 即保存為 pdf,則需要保持為無(wú)頭模式
    // headless: false,
});

看下執(zhí)行效果:

我的書架里有20多本書,下載完后是這樣子:

完整示例代碼

無(wú)頭瀏覽器還能做什么?

無(wú)頭瀏覽器說(shuō)白了就是能模擬人工在有頭瀏覽器中的各種操作,那自然很多人力活,都能使用無(wú)頭瀏覽器來(lái)做(比如上面這個(gè)下載 pdf 的過(guò)程,其實(shí)是人力打開(kāi)每一個(gè)文章頁(yè)面,然后按 ctrl+pcommand+p 保存到本地的自動(dòng)化過(guò)程)。

那既然用自動(dòng)化工具能解決的事情,就不應(yīng)該浪費(fèi)重復(fù)的人力勞動(dòng)了,所以我們還可以做:

自動(dòng)化工具
如自動(dòng)提交表單,自動(dòng)下載

自動(dòng)化 UI 測(cè)試
如記錄下正確 DOM 結(jié)構(gòu)或截圖,然后自動(dòng)執(zhí)行指定操作后,檢查 DOM 結(jié)構(gòu)或截圖是否匹配(UI 斷言)

定時(shí)監(jiān)控工具
如定時(shí)截圖發(fā)周報(bào),或定時(shí)巡查重要業(yè)務(wù)路徑下的頁(yè)面是否處于可用狀態(tài),配合郵件告警

爬蟲(chóng)
如傳統(tǒng) HTTP 爬蟲(chóng)怕不到的地方,就可配合無(wú)頭瀏覽器渲染能力來(lái)做

etc

感謝閱讀!
(全文完)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/89179.html

相關(guān)文章

  • Puppeteer 初探

    摘要:抓取并生成預(yù)先呈現(xiàn)的內(nèi)容即。自動(dòng)表單提交,測(cè)試,鍵盤輸入等。創(chuàng)建一個(gè)最新的自動(dòng)化測(cè)試環(huán)境。使用最新的的和瀏覽器功能,直接在最新版本的瀏覽器中運(yùn)行測(cè)試。捕獲您網(wǎng)站的時(shí)間線跟蹤,以幫助診斷性能問(wèn)題。 木偶 Puppeteer 更友好的 Headless Chrome Node API木偶也是有心的 (=?ω?=) showImg(https://segmentfault.com/img/b...

    oysun 評(píng)論0 收藏0
  • Puppeteer初探--爬取并生成《ES6標(biāo)準(zhǔn)入門》PDF

    摘要:首先介紹是一個(gè)庫(kù),他提供了一組用來(lái)操縱的默認(rèn)也就是無(wú)的,也可以配置為有有點(diǎn)類似于,但是官方團(tuán)隊(duì)進(jìn)行維護(hù)的,前景更好。使用,相當(dāng)于同時(shí)具有和的能力,應(yīng)用場(chǎng)景會(huì)非常多。 首先介紹Puppeteer Puppeteer是一個(gè)node庫(kù),他提供了一組用來(lái)操縱Chrome的API(默認(rèn)headless也就是無(wú)UI的chrome,也可以配置為有UI) 有點(diǎn)類似于PhantomJS,但Puppet...

    JerryWangSAP 評(píng)論0 收藏0
  • 小程序測(cè)試方案初探

    摘要:前言年月號(hào)微信小程序正式上線,小程序不需要安裝就能使用,依托微信強(qiáng)大的生態(tài)環(huán)境,能做到很多所不能做的事情。當(dāng)然更希望的是小程序官方能給出相應(yīng)的單元測(cè)試方案吧。 前言 2017年1月9號(hào)微信小程序正式上線,小程序不需要安裝就能使用,依托微信強(qiáng)大的生態(tài)環(huán)境,能做到很多H5所不能做的事情。從微信小程序發(fā)布這段時(shí)間,陸陸續(xù)續(xù)開(kāi)發(fā)了不少小程序相關(guān)的項(xiàng)目,總結(jié)了一些通用性的組件,但是對(duì)于小程序如何...

    church 評(píng)論0 收藏0
  • ELSE 技術(shù)周刊(2017.10.30期)

    摘要:技術(shù)縱橫調(diào)試指南協(xié)議是新加入的調(diào)試協(xié)議,通過(guò)與交互,同時(shí)基于瀏覽器的提供了圖形化的調(diào)試界面。使得多業(yè)務(wù)線在復(fù)雜架構(gòu)情況下能夠獨(dú)立開(kāi)發(fā)測(cè)試,互不干擾,并統(tǒng)一調(diào)用接口。技術(shù)周刊由小組出品,匯聚一周好文章,周刊原文。 本期推薦 寫在 2017 的前端數(shù)據(jù)層不完全指北 在前端技術(shù)的發(fā)展中,各個(gè)層面演進(jìn)出不同的技術(shù)方案,如數(shù)據(jù)類型層面的 TypeScript,F(xiàn)low,PropTypes,應(yīng)用架...

    AprilJ 評(píng)論0 收藏0
  • 2017-10-18 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選無(wú)頭瀏覽器初探鼠標(biāo)無(wú)限移動(dòng)簡(jiǎn)介譯深入分析變更檢測(cè)發(fā)布前必須排查的安全如何開(kāi)發(fā)中文第期關(guān)鍵和減少阻塞渲染的的自動(dòng)化解決方案譯網(wǎng)頁(yè)設(shè)計(jì)掘金年最受歡迎的個(gè)編程挑戰(zhàn)網(wǎng)站簡(jiǎn)書系列和深入理解掘金發(fā)布后臺(tái)管理系統(tǒng),沒(méi)錯(cuò),它就是你想 2017-10-18 前端日?qǐng)?bào) 精選 無(wú)頭瀏覽器 Puppeteer 初探鼠標(biāo)無(wú)限移動(dòng) JS API Pointer Lock簡(jiǎn)介[譯] 深入分析 Angul...

    cyrils 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<