使用Puppeteer進行數據抓取(三)——簡單的示例


本文以一個示例簡單的介紹一下puppeteer的用法,我們的目的是:獲取我博客上的文章的前十頁的所有隨筆的標題和鏈接。由於puppeteer本身是自動化chorme,因此這里我們的步驟和手動操作瀏覽器差不多:

  1. 打開chrome,跳轉到博客首頁
  2. 獲取所有博客標題信息
  3. 點擊下一頁按鈕,跳轉到下一頁
  4. 重復2、3兩步,直到所有信息采集完畢

獲取信息

采集過程中比較麻煩的一步就是信息的采集,和傳統采集html后解析的方式不同的時,由於chrome本身有完整的js引擎,因此我們采用注入一段js,利用該js采集到我們的信息,並通過puppeteer返回給應用程序的方式。由於puppete本身是采用的chrome,因此編寫采集信息函數這一過程完全可以在chrome上進行。

首先用chrome打開我的博客的首頁http://www.cnblogs.com/TianFang/,打開chrome devtool,獲取標題的css path。然后我們可以利用chrome的snippets簡單的寫一個獲取所有標題信息的函數:

  

本身就蜘蛛程序而言,編寫獲取腳本內容的這個部分是比較繁瑣的,需要不斷的反復調試。但使用snippets直接編寫函數大大簡化了這一過程,它的主要好處有:

  1. 可以直接使用各種js函數,可以直接操作各種dom對象
  2. 利用snippets編寫可以在chrome中實時調試,
  3. 可以實時查看生成結果

然后我們只需要將這個函數放到node中,利用puppeteer跳轉到相應的頁面,使用page.evaluate函數執行這個函數即可。

async function getTitles() {
    var titles = $('.postTitle>a');

    var result = titles.map((i, a) => ({
        text: a.text,
        href: a.href
    })).get();

    console.table(result);
    return result;


var titles = await page.evaluate(getTitles);
console.log(titles);

一個需要注意的地方是,這個函數實際上是在chrome中執行的,puppeteer要求在chrome中執行的函數必須是異步的,因此需要加上async關鍵字。

 

頁面跳轉

下一步需要解決的問題就是如何跳轉到下一頁了。方法也比較簡單:分析一下頁面,找到下一頁的連接,執行js模擬點擊即可:

page.evaluate(async() => $(`a:contains('下一頁')`)[0].click());

 

完整代碼如下:

const puppeteer = require('puppeteer');

const chrome_exe = String.raw`${process.env["ProgramFiles(x86)"]}\Google\Chrome\Application\chrome.exe`;
const user_data_path = String.raw`${process.env.LocalAppData}\Google\Chrome\User Data\Default`;

async function run() {
    const browser = await puppeteer.launch({
        headlessfalse,
        userDataDiruser_data_path,
        executablePathchrome_exe
    });
    const page = await browser.newPage();
    page.setViewport({ width: 1600, height: 900 });
    await page.goto('http://www.cnblogs.com/TianFang');

    for (var i = 0; i < 10; i++) {

        console.log(i);
        console.log(page.url());

        var titles = await page.evaluate(getTitles);
        console.log(titles);

        await page.evaluate(async() => $(`a:contains('
下一頁
')`)[0].click());
        await page.waitForNavigation();

        await sleep(1000);
    }
};

async function getTitles() {
    var titles = $('.postTitle>a');

    var result = titles.map((i, a) => ({
        text: a.text,
        href: a.href
    })).get();

    console.table(result);
    return result;


async function sleep(timeout) {
    return new Promise(resolve => setTimeout(resolve, timeout));
}

run();

整個過程還是非常簡單的, 執行結果如下:

  

另外值得一提的是,細心的朋友可能注意到這里我們編寫一個可以await的sleep函數。

async function sleep(timeout) {
    return new Promise(resolve => setTimeout(resolve, timeout));
}

這個函數本身不是必須的,但在編寫蜘蛛程序過程中卻經常需要等待的,使用await異步等待可以大大提高代碼的可讀性,由於node本身沒有提供可以await的sleep函數。並且這個函數非常實用,這里就自己實現了一個,記錄一下,以備以后使用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM