萬物皆可爬-puppeteer實戰

puppeteer 是一個Chrome官方出品的headless Chrome node庫。它提供了一系列的API, 能夠在無UI的狀況下調用Chrome的功能, 適用於爬蟲、自動化處理等各類場景javascript

puppteer

puppeteer 是一個Chrome官方出品的headless Chrome node庫(沒有圖形用戶界面的的web瀏覽器)。它提供了一系列的API, 能夠在無UI的狀況下調用Chrome的功能, 適用於爬蟲、自動化處理等各類場景html

能夠用它來幹什麼?java

  • 生成頁面截圖和PDF
  • 自動化表單提交、UI 測試、鍵盤輸入等
  • 建立一個最新的自動化測試環境。使用最新的 JavaScript 和瀏覽器功能,能夠直接在最新版本的 Chrome 中運行測試。
  • 爬取 SPA 頁面並進行預渲染(即'SSR')
  • ...

和cheerio的區別

  • cheerio - 這貨說白了就是累死jq語法操做的html文檔庫,只能爬取靜態的html,沒法獲取ajax數據,通常都axios+cherrio結合使用
  • puppteer - 可以模擬瀏覽器運行環境,可以請求網站信息。可以進行模擬操做(點擊/滑動/hover等),甚至能注入node腳本到瀏覽器內部環境運行

puppteer架構圖

  • Puppeteer - 經過 devTools 與 browser 通訊
  • Browser - 一個能夠擁有多個頁面的瀏覽器(chroium)實例
  • Page - 至少含有一個 Frame 的頁面
  • Frame - 至少還有一個用於執行 javascript 的執行環境,也能夠拓展多個執行環境

輕鬆入門

const puppeteer = require('puppeteer');
(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(targetUrl);
  await page.screenshot({path: 'example.png'});
  await browser.close();
})();

複製代碼

分析代碼

1.引入puppeteernode

const puppeteer = require('puppeteer');
 
複製代碼

2.生成實例ios

也就是經過Puppeteer啓動一個瀏覽器環境git

const browser = await puppeteer.launch(options);
複製代碼

options:github

  • executablePath: puppeteer.executablePath() - 獲取默承認執行的chrome位置
  • headless: false - 是否開啓headless模式
  • slowMo: 250 - 該選項會是puppeteer操做減慢指定的毫秒數
  • devtools: true - 在應用程序代碼瀏覽器中使用調試器
  • defaultViewport - 默認800 x 600
    • width
    • height
    • deviceScaleFactor - 比例因子
    • isMobile - 是否考慮meta viewport 標籤, 默認爲false
    • hasTouch - 指定viewport是否支持觸摸事件,默認爲false
    • isLandscape - 指定之口是否處於橫向模式
  • 更多參數請參照Puppeteer.launch()
  • 3.打開一個新頁面web

    const page = await browser.newPage();
    
    複製代碼

    4.前往目標頁面ajax

    await page.goto(targetUrl);
    
    複製代碼

    注意: 這裏可接受第二個參數,是個對象,用來進行一些簡單的配置,帶選項有chrome

    waitUntil:

    • load - 請求到數據後當即返回
    • domcontentloaded - dom加載完成後返回
    • networkidle0 - 沒有超過0個網絡鏈接500ms後返回
    • networkidle2 - 沒有超過2個網絡鏈接500ms後返回

    timeout: 跳轉等待時間,單位是毫秒, 默認是30秒, 傳 0 表示無限等待,能夠經過page.setDefaultNavigationTimeout(timeout)方法修改默認值

    referer(不經常使用): 引用頁頭的值。若是提供,它將優先於page.setExtraHTTPHeaders()設置的referer頭值(Referer header value. If provided it will take preference over the referer header value set by page.setExtraHTTPHeaders().)

    5.關閉瀏覽器

    browser.close();
    複製代碼

    花裏胡哨

    其實輕鬆入門節已經將咱們經常使用的功能進行了相對完善的描述,總結一下,爬一個網頁須要幾步

    1. 打開瀏覽器
    2. 關閉瀏覽器

    是否是很簡單?問題來了?怎麼爬?會不會用jq?

    會用jq你就會用爬蟲!

    找到一個本身喜歡的視頻網站,(如下內容僅供教學!)

    const demo = async () => {
      const browser = await (puppeteer.launch({
        executablePath: puppeteer.executablePath(),
        headless: false
      }))
      var arr = []
      for (let i = 1; i <= 40; i++) {
        console.log('正在抓取全職高手第' + i + '集')
        const targetUrl = `https://goudaitv1.com/play/78727-4-${i}.html`
        console.log(targetUrl)
        const page = await browser.newPage()
        await page.goto(targetUrl, {
          timeout: 0,
          waitUntil: 'domcontentloaded'
        })
        const baseNode = '.row'
        const movieList = await page.evaluate((sel) => {
          var stream = Array.from($(sel).find('iframe#Player').attr('src'))
          stream && (stream = stream.join(''))
          return stream
        }, baseNode)
        arr.push(movieList)
        page.close()
      }
      console.log(arr)
      browser.close()
    }
    複製代碼

    page.evaluate(pageFunction[, ...args])

    • pageFunction <function|string> 要在頁面實例上下文中執行的方法
    • ...args 要傳給 pageFunction 的參數
    • 返回: pageFunction執行的結果

    若是pageFunction返回的是Promise,page.evaluate將等待promise完成,並返回其返回值。

    若是pageFunction返回的是不能序列化的值,將返回undefined

    給pageFunction傳參數示例:

    const result = await page.evaluate(x => {
      return Promise.resolve(8 * x);
    }, 7); // (注: 7 能夠是你本身代碼裏任意方式獲得的值)
    console.log(result); // 輸出 "56"
    複製代碼

    也能夠傳入一個字符串

    console.log(await page.evaluate('1 + 2')); // 輸出 "3"
    const x = 10;
    console.log(await page.evaluate(`1 + ${x}`)); // 輸出 "11"
    複製代碼

    存入數據庫

    搞定!你能夠用這些數據作本身想作的一切,好比

    最後

    固然,'爬'只是它的冰山一角,上述demo比較偷懶的直接獲取了a標籤的地址進行跳轉,咱們還可使用點擊事件進行頁面跳轉,感興趣的能夠試試。

    page.click(selector[, options])

    • selector 要點擊的元素的選擇器。 若是有多個匹配的元素, 點擊第一個。
    • options
      • button left, right, 或者 middle, 默認是 left。
      • clickCount 默認是 1. 查看 UIEvent.detail。
      • delay mousedown 和 mouseup 之間停留的時間,單位是毫秒。默認是0
    • 返回: Promise對象,匹配的元素被點擊。 若是沒有元素被點擊,Promise對象將被rejected。
    • 此方法找到一個匹配 selector 選擇器的元素,若是須要會把此元素滾動到可視,而後經過 page.mouse 點擊它。 若是選擇器沒有匹配任何元素,此方法將會報錯。

      要注意若是 click() 觸發了一個跳轉,會有一個獨立的 page.waitForNavigation() Promise對象須要等待。 正確的等待點擊後的跳轉是這樣的:

      const [response] = await Promise.all([
        page.waitForNavigation(waitOptions),
        page.click(selector, clickOptions),
      ]);
      
      複製代碼
      • page.waitForNavigation([options])

      此方法在頁面跳轉到一個新地址或從新加載時解析,若是你的代碼會間接引發頁面跳轉,這個方法比較有用。

      更多參照page.waitForNavigation([options])

      參考

      Puppeteer 中文網

      Puppeteer npm

相關文章
相關標籤/搜索