Puppeteer!

什麼是Puppeteer

Puppeteer 是一個由 Google 開發的 Node.js 庫,它提供了一組用於控制 Headless Chrome 的 API。

Headless Chrome 是 Chrome 瀏覽器的無界面版本,可以用於模擬用戶行爲、測試網站、爬取數據等多種用途。

Puppeteer 提供了一系列的 API,可以讓我們控制 Chrome 瀏覽器的各種行爲,例如打開網頁、模擬用戶操作、獲取網頁內容等。

總之,Puppeteer 是一個非常強大且易於使用的工具,可以幫助我們輕鬆地完成各種 Web 自動化和爬蟲任務。

Puppeteer的優勢

  1. 完全支持最新的 Web 標準和技術:Puppeteer 支持最新的 Web 標準和技術,例如 ES6、Promise、async/await 等。這樣,我們可以使用最新的 JavaScript 特性來編寫爬蟲代碼,使代碼更加簡潔、易讀、易維護。
  2. 支持動態網站的爬取:Puppeteer 可以處理 JavaScript 渲染的頁面,也就是說它可以爬取動態網站,這是其他爬蟲框架所不具備的優勢。
  3. 可以模擬真實的用戶行爲:Puppeteer 可以模擬真實的用戶行爲,例如點擊按鈕、填寫表單、滾動頁面等。
  4. 可以生成 PDF 和截屏等多種格式的輸出:Puppeteer 可以生成 PDF 和截屏等多種格式的輸出,這對於需要對網站進行分析或者展示結果的情況非常有用。
  5. 可以與其他 Node.js 庫和框架無縫集成:Puppeteer 可以與其他 Node.js 庫和框架無縫集成,例如 Express、Koa、Mocha、Jest 等。這樣,我們可以將 Puppeteer 用於自動化測試、Web 開發等領域。

Puppeteer基本用法

安裝配置

使用 npm 安裝 Puppeteer:

npm install puppeteer

Puppeteer 默認會從 Google 的服務器下載 Chrome 瀏覽器二進制文件,如果您的網絡環境無法訪問 Google 的服務器,可以通過以下方式配置 Puppeteer:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: true, // 是否啓用無頭模式
    executablePath: '/path/to/Chrome', // Chrome 瀏覽器可執行文件路徑
    args: ['--no-sandbox'], // Chrome 啓動參數
  });
  const page = await browser.newPage();
  await page.goto('https://example.com');
  // ...
  await browser.close();
})();

我們通過 executablePath 和 args 選項來指定 Chrome 瀏覽器的可執行文件路徑和啓動參數

這樣,我們就可以在沒有網絡的情況下使用 Puppeteer

打開網頁

使用 puppeteer.launch() 方法啓動 Chrome 瀏覽器,並創建一個新的頁面對象:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch(); // 啓動 Chrome 瀏覽器
  const page = await browser.newPage(); // 創建一個新的頁面對象
  await page.goto('https://example.com'); // 打開一個網頁
  // ...
  await browser.close();
})();

在上面的代碼中,我們使用 puppeteer.launch() 方法啓動 Chrome 瀏覽器,並使用 browser.newPage() 方法創建一個新的頁面對象,然後,我們使用 page.goto() 方法打開一個網頁。

launch配置

在使用 puppeteer.launch() 方法啓動 Chrome 瀏覽器時,可以通過傳遞一些配置選項來控制 Chrome 瀏覽器的啓動行爲。下面是常用的配置選項:

  • headless:是否啓用無頭模式,默認爲 true
  • executablePath:Chrome 瀏覽器可執行文件路徑。
  • args:Chrome 啓動參數。
  • defaultViewport:默認的瀏覽器窗口大小。
  • timeout:超時時間,單位爲毫秒。

下面是一個使用 puppeteer.launch() 方法的示例:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: true,
    executablePath: '/path/to/Chrome',
    args: ['--no-sandbox'],
    defaultViewport: {
      width: 1280,
      height: 800,
    },
    timeout: 30000,
  });
  const page = await browser.newPage();
  await page.goto('https://example.com');
  // ...
  await browser.close();
})();

在上面的代碼中,我們使用了常用的配置選項:

  • headless 選項設置爲 true,啓用無頭模式。
  • executablePath 選項指定 Chrome 瀏覽器的可執行文件路徑。
  • args 選項指定 Chrome 啓動參數,例如 --no-sandbox 表示禁用沙盒模式。
  • defaultViewport 選項指定默認的瀏覽器窗口大小。
  • timeout 選項指定超時時間爲 30 秒。

下面是更詳細的配置列表:

puppeteer.launch({
  headless: true, // 是否以無頭模式運行瀏覽器,默認爲true
  executablePath: '', // 可執行文件路徑,如果不指定則自動下載
  args: [], // 命令行參數數組
  ignoreDefaultArgs: false, // 是否忽略默認的命令行參數
  defaultViewport: null, // 默認視窗大小,null表示自動設置
  slowMo: 0, // 延遲毫秒數,用於調試
  timeout: 30000, // 超時時間,單位爲毫秒
  devtools: false, // 是否打開DevTools面板,默認爲false
  pipe: false, // 是否將瀏覽器啓動的I/O連接通過管道傳遞,默認爲false
  handleSIGINT: true, // 是否在收到SIGINT信號時關閉瀏覽器,默認爲true
  handleSIGTERM: true, // 是否在收到SIGTERM信號時關閉瀏覽器,默認爲true
  handleSIGHUP: true, // 是否在收到SIGHUP信號時關閉瀏覽器,默認爲true
  env: {}, // 環境變量對象
  userDataDir: '', // 用戶數據目錄路徑
  dumpio: false, // 是否將瀏覽器I/O輸出到進程的stdout和stderr中,默認爲false
  executablePath: '', // 可執行文件路徑,如果不指定則自動下載
  ignoreHTTPSErrors: false, // 是否忽略HTTPS錯誤,默認爲false
  ignoreCertificateErrors: false // 是否忽略SSL證書錯誤,默認爲false
});

獲取元素

使用 page.$() 方法獲取一個元素:

const element = await page.$('selector');

在上面的代碼中,我們使用 page.$() 方法獲取一個元素。

其中,selector 參數可以是 CSS 選擇器、XPath 表達式或者其他選擇器。

點擊按鈕

使用 element.click() 方法點擊一個按鈕:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await element.click();
  await browser.close();
})();

在上面的代碼中,我們使用 element.click() 方法點擊一個按鈕。

填寫表單

使用 element.type() 方法填寫表單:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await element.type('text');
  await browser.close();
})();

在上面的代碼中,我們使用 element.type() 方法填寫表單。其中,text 參數是要填寫的文本內容。

截屏

使用 page.screenshot() 方法截屏:

const puppeteer = require('puppeteer');

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

在上面的代碼中,我們使用 page.screenshot() 方法截屏,並將截屏保存爲 PNG 格式的文件。

還有很多常見的puppeteer基本用法,這裏不一一介紹,用到的時候去官方文檔查看對應的API即可

Puppeteer進階用法

模擬用戶行爲

點擊元素

使用 element.click() 方法模擬點擊元素:

await element.click();

在上面的代碼中,我們使用 element.click() 方法模擬點擊元素。

輸入文本

使用 element.type() 方法輸入文本:

await element.type('text');

在上面的代碼中,我們使用 element.type() 方法輸入文本。其中,text 參數是要輸入的文本。

選擇選項

使用 element.select() 方法選擇選項:

await element.select('value');

在上面的代碼中,我們使用 element.select() 方法選擇選項。其中,value 參數是要選擇的選項值。

滾動頁面

使用 page.evaluate() 方法執行 JavaScript 代碼來滾動頁面:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');

  let previousHeight;
  while (true) {
    const currentHeight = await page.evaluate(() => {
      return document.documentElement.scrollHeight;
    });
    if (currentHeight === previousHeight) {
      break;
    }
    previousHeight = currentHeight;
    await page.evaluate(() => {
      window.scrollBy(0, window.innerHeight);
    });
    await page.waitForTimeout(1000);
  }

  const content = await page.$('#content');
  console.log(await content.textContent());

  await browser.close();
})();

在上面的代碼中,我們使用 Puppeteer 打開一個需要滾動的網頁,並模擬滾動操作,直到頁面滾動到底部,然後獲取頁面中的內容。

處理動態內容

等待元素出現

使用 page.waitForSelector() 方法等待元素出現:

await page.waitForSelector('selector');

在上面的代碼中,我們使用 page.waitForSelector() 方法等待元素出現。

其中,selector 參數可以是 CSS 選擇器、XPath 表達式或者其他選擇器。

等待頁面加載完成

使用 page.waitForNavigation() 方法等待頁面加載完成:

await page.goto('https://example.com');
await page.waitForNavigation();

在上面的代碼中,我們使用 page.goto() 方法打開一個網頁,並使用 page.waitForNavigation() 方法等待頁面加載完成。

處理驗證碼

Puppeteer 可以通過打碼平臺來識別驗證碼。以下是一個使用打碼平臺的示例:

const antiCaptcha = require('anticaptcha');
const client = new antiCaptcha('API_KEY');

const image = await page.screenshot({ encoding: 'base64' });
const taskId = await client.createTask({
  type: 'ImageToTextTask',
  body: image,
});

const solution = await client.getTaskSolution(taskId);
await page.type('#captcha', solution.text);

在上面的代碼中,我們使用 page.screenshot() 方法獲取驗證碼圖片,並使用打碼平臺識別驗證碼,最後將識別結果輸入到驗證碼輸入框中。

處理登錄

以下是一個使用 Puppeteer 處理登錄的示例:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com/login');

  await page.type('#username', 'your-username');
  await page.type('#password', 'your-password');
  await page.click('#login-button');

  await page.waitForNavigation();

  const content = await page.$('#content');
  console.log(await content.textContent());

  await browser.close();
})();

在上面的代碼中,我們使用 page.goto() 方法打開登錄頁面,並使用 page.type() 方法輸入用戶名和密碼,最後使用 page.click() 方法提交登錄表單,然後獲取頁面中的內容。

定時爬取

puppeteer可以實現定時爬取數據,以下是一個使用 Puppeteer 配合 node-schedule 實現定時爬取的示例:

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

// 每隔一段時間執行一次爬取數據函數
const job = schedule.scheduleJob('自動爬蟲任務', '30 20 * * * *', async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  await page.goto('https://example.com');
  
  // 模擬滾動到頁面底部
  await page.evaluate(async () => {
    await new Promise(resolve => {
      let totalHeight = 0;
      const distance = 100;
      const timer = setInterval(() => {
        const scrollHeight = document.body.scrollHeight;
        window.scrollBy(0, distance);
        totalHeight += distance;

        if (totalHeight >= scrollHeight) {
          clearInterval(timer);
          resolve();
        }
      }, 100);
    });
  });
  
  // 等待列表加載完成
  await page.waitForSelector('.list-item');
  
  // 獲取列表數據
  const listItems = await page.$$('.list-item');
  const data = await Promise.all(listItems.map(async listItem => {
    const title = await listItem.$eval('.title', el => el.textContent);
    const description = await listItem.$eval('.description', el => el.textContent);
    return { title, description };
  }));
  
  console.log(data);
  
  await browser.close();
});

// 取消定時任務
// job.cancel();

在這個示例中,我們使用node-schedule庫創建了一個定時任務,每小時的0分執行一次。在任務中包含了獲取數據的代碼,與前面的示例類似。如果需要取消定時任務,可以使用job.cancel()方法。

自動化測試

Puppeteer 可以用於自動化測試,以下是一個使用 Puppeteer 進行自動化測試的示例:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');

  const title = await page.title();
  if (title !== 'Example Domain') {
    console.error('Title is not correct');
  }

  const url = await page.url();
  if (url !== 'https://example.com/') {
    console.error('URL is not correct');
  }

  await browser.close();
})();

在上面的代碼中,我們使用 Puppeteer 打開一個網頁,並檢查頁面標題和 URL 是否正確。

實戰案例

CSDN作者榜

我們打開網址https://blog.csdn.net/rank/list/total來看看CSDN作者總榜
在這裏插入圖片描述

還是和靜態頁面一樣,我們來分析一下頁面結構,找到我們想要拿到的數據:

在這裏插入圖片描述

下面我們來用puppeteer來實現爬取這個作者榜:

// 無頭瀏覽器模塊
const puppeteer = require("puppeteer");
const fs = require('fs');

// 目標頁面
const crawlPage = "https://blog.csdn.net/rank/list/total";

// 網頁爬蟲
(async function crawler() {
    //創建實例
    const browser = await puppeteer.launch({
        //無瀏覽器界面啓動
        headless: "new",
        //放慢瀏覽器執行速度,方便測試觀察
        slowMo: 100,
        // 設置打開的瀏覽器窗口尺寸
        defaultViewport: { width: 960, height: 540 },
    });

    // 新開一個tab頁面
    const page = await browser.newPage();
    // 加載目標頁,在 500ms 內沒有任何網絡請求才算加載完
    await page.goto(crawlPage, { waitUntil: "networkidle0" });

    // 在無頭瀏覽器頁面dom環境,獲取頁面數據
    const authorList = await page.evaluate(() => {
        const list = [];
        document.querySelectorAll(".floor-rank-total .floor-rank-total-item").forEach((ele) => {
            const rank = ele.querySelector(".total-content .number").innerText;
            const title = ele.querySelector(".total-box dd a").innerText;
            const fans = ele.querySelector(".total-box dt span:nth-child(1)").innerText;
            list.push({
                '排名': rank,
                '作者': title,
                '粉絲': fans,
            });
        });
        return list;
    });

    // console.log(authorList);
    // 將數據寫入文件中
    fs.writeFile('./csdnAuthor.json', JSON.stringify(authorList), function (err, data) {
        if (err) {
            throw err
        }
        console.log('文件保存成功');
    })

    // 關閉tab頁
    await page.close();
    // 關閉實例
    await browser.close();
})();

看看json文件裏有什麼吧:

在這裏插入圖片描述

沒有問題,成功拿到了我們想要的CSDN作者總榜頁面的排名、作者和粉絲數量!

掘金小冊

掘金小冊的內容質量非常高,推薦大家可以去看一看,接下來我們來爬取一下目前發佈所有的掘金小冊

我們來分析一下掘金小冊的頁面結構,我們想要拿到的數據有:小冊名稱、小冊簡介、小冊作者、小冊價格

在這裏插入圖片描述

我們來用puppeteer來實現爬取,要注意的是掘金小冊頁面不會全部加載所有小冊,因此我們需要用puppeteer模擬用戶行爲,將頁面列表滾動到最底部,加載完所有的小冊列表數據後再進行爬取:

// 無頭瀏覽器模塊
const puppeteer = require("puppeteer");
const fs = require('fs')

// 目標頁面
const crawlPage = "https://juejin.cn/course";

// 網頁爬蟲
(async function crawler() {
    //創建實例
    const browser = await puppeteer.launch({
        //無瀏覽器界面啓動
        headless: "new",
        //放慢瀏覽器執行速度,方便測試觀察
        // slowMo: 100,
        // 設置打開的瀏覽器窗口尺寸
        defaultViewport: { width: 960, height: 540 },
    });

    // 新開一個tab頁面
    const page = await browser.newPage();
    // 加載目標頁,在 500ms 內沒有任何網絡請求才算加載完
    await page.goto(crawlPage, { waitUntil: "networkidle0" });

    // 模擬滾動到頁面底部
    await page.evaluate(async () => {
        await new Promise((resolve) => {
          let totalHeight = 0;
          const distance = 200;
          const timer = setInterval(() => {
            const scrollHeight = document.body.scrollHeight;
            window.scrollBy(0, distance);
            totalHeight += distance;
    
            if (totalHeight >= scrollHeight) {
              clearInterval(timer);
              resolve();
            }
          }, 200);
        });
    });

    // 等待列表加載完成
    await page.waitForSelector('.books-view');

    // 在無頭瀏覽器頁面dom環境,獲取頁面數據
    const articleList = await page.evaluate(() => {
        const list = [];
        const itemSelector = ".books-view > div:last-child > div > div > a";
        document.querySelectorAll(itemSelector).forEach(async(ele) => {
            const title = await ele.querySelector(".book-info .text-highlight").innerText;
            const desc = await ele.querySelector(".book-info .text-highlight.desc").innerText;
            const author = await ele.querySelector(".book-info .author .name").innerText;
            const price = await ele.querySelector(".book-info .other .origin-price").innerText;
            list.push({
                '小冊名稱': title,
                '小冊簡介': desc,
                '小冊作者': author,
                '小冊價格': price,
            });
        });
        return list;
    });

    // console.log(articleList);
    // 將數據寫入文件中
    fs.writeFile('./xiaoce.json', JSON.stringify(articleList), function (err, data) {
        if (err) {
            throw err
        }
        console.log('文件保存成功');
    })

    // 關閉tab頁
    await page.close();
    // 關閉實例
    await browser.close();
})();

保存的JSON文件數據如下,可以看到成功獲取了所有小冊數據:

在這裏插入圖片描述

模擬登錄

我們通過 cookie 模擬登錄環境,我們去谷歌應用商店下載一個插件 “Export cookie JSON file for Puppeteer”

這個 chrome 插件直接獲取 cookie 信息

在這裏插入圖片描述

然後運行這個插件,下載CSDN cookie的json文件,代碼很簡單:

const puppeteer = require("puppeteer");
// 通過 插件 獲取的 JSON化 cookie
const cookieObjects = require("./csdn.net.cookies.json");

(async () => {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();
  await page.setViewport({ width: 1400, height: 1080 });

  cookieObjects.forEach((cookie) => {
    page.setCookie(cookie);
  });
  await page.goto("https://www.csdn.net/");
})()

運行程序,自動打開瀏覽器,模擬登錄成功:

在這裏插入圖片描述

總結

Puppeteer 是一個功能強大的 Node.js 庫,可以用於控制 Chrome 或者 Chromium 瀏覽器,實現自動化測試、爬蟲、網頁截圖等功能。以下是 Puppeteer 的一些優點和缺點:

優點

  • 功能強大:Puppeteer 支持大部分 Chrome DevTools 協議中的功能,包括頁面截圖、模擬用戶操作、處理動態內容等。
  • 易於使用:Puppeteer 的 API 設計簡單易用,上手容易。
  • 可擴展性強:Puppeteer 可以與其他 Node.js 庫和工具集成,擴展其功能。
  • 社區活躍:Puppeteer 有一個活躍的社區,可以獲取到大量的文檔、教程和示例。

缺點

  • 依賴 Chrome 或者 Chromium 瀏覽器:Puppeteer 需要依賴 Chrome 或者 Chromium 瀏覽器才能運行,這會導致一定的資源佔用。
  • 不支持其他瀏覽器:Puppeteer 只支持 Chrome 和 Chromium 瀏覽器,不支持其他瀏覽器。
  • 可能被網站檢測到:由於 Puppeteer 可以模擬用戶行爲,因此有些網站可能會檢測到 Puppeteer 的使用並阻止其訪問。

總的來說,Puppeteer 是一個非常有用的工具,可以幫助開發人員和測試人員提高工作效率。

如果需要進行自動化測試、爬蟲或者網頁截圖等操作,Puppeteer 是一個值得嘗試的工具。

未來發展

隨着互聯網技術的發展和應用場景的不斷擴大,爬蟲技術將會得到更廣泛的應用和更深入的研究。

以下是爬蟲技術未來的一些發展方向:

  • 智能化:隨着人工智能技術的發展,我們可以將人工智能技術應用到爬蟲技術中,使得爬蟲可以自主學習和適應不同的網站結構。
  • 安全性:隨着網站安全性的提升,一些網站可能會採取更加複雜和嚴格的反爬蟲機制。因此,未來的爬蟲技術需要更加註重安全性和隱私保護。
  • 大數據:隨着大數據技術的發展,我們可以將爬蟲技術與大數據技術相結合,用於數據分析和挖掘。
  • 分佈式:隨着雲計算技術的發展,分佈式爬蟲將會成爲未來的趨勢,可以更加高效地抓取大量數據。

總之,爬蟲技術在未來將會得到更廣泛和深入的應用,並且將會不斷地發展和完善。

Node.js爬蟲只會Cheerio?來試試Puppeteer!_node爬蟲框架puppeteer-CSDN博客

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章