LoginSignup
39
41

More than 5 years have passed since last update.

Puppeteer + GCP Functionsでサーバレスなスクレイピング

Last updated at Posted at 2019-01-02

サーバレスなScraperを運用したい人向け。

GCP FunctionsでPuppeteerが動くぞ!

2018年の8月から、GCPのGoogle App EngineとGoogle Functionsで Puppeteerサポートされました。
Puppeteerは、nodejsで動くHeadless Chrome(Chromium) Driverです。

準備

インストール

$ npm init
$ npm install -S puppeteer

コード

まず、エントリーポイントになるindex.jsはこんな感じ。

index.js
const scraper = require('./functions/scraper');
exports.scraper = scraper;

あとはfunctionsディレクトリの下にscraper.jsを作り、そこにコードを作成していきます。
今回はasyncを使いたいのでnode8系で書きます。

scraper.js
module.exports = async (req, res) => {
    const USERNAME = process.env['USERNAME'];
    const PASSWORD = process.env['PASSWORD'];
    const LOGIN_URL = 'https://example.com';

    // Chromiumを起動し、ページをつくる
    const browser = await puppeteer.launch({ args: ['--no-sandbox'] });
    const page = await browser.newPage();
    page.setViewport({ width: 1280, height: 1024 });

    // ログインページに移動し、ログインする
    await page.goto(`${LOGIN_URL}/login`, { waitUntil: 'domcontentloaded', timeout: 20000 });
    await page.type('input#email', USERNAME);
    await page.type('input#password', PASSWORD);
    await page.click('#login-btn-sumit');
    await page.waitForNavigation();
    await page.goto('`${LOGIN_URL}/users`', { waitUntil: 'domcontentloaded', timeout: 20000 });

    // スクレイピングの一例
    // user_info_fieldsクラスのtrタグをパースします
    const elements = await page.$$('tr.user_info_fields');
    const users = [];
    for (let i = 0; i < elements.length; i++) {
        const element = elements[i];
        const userid= await element.$eval('th', e => e.innerText);
        const username = await element.$eval('td.username span', e => e.innerText);
        const email = await element.$eval('td.email', e => e.innerText);
        users.push({
            userid: userid,
            username: username,
            email: email
        });
    }
    res.send(users);
}

環境変数

Functionsでは.env.yamlに記述しておけば、デプロイ時に環境変数に設定できます。

.env.yaml
USERNAME : 'me@example.com'
PASSWORD : 'passwd1234!'

デプロイ

GCP SDKとFunctionsエミュレータをインストールしておいてください。
Functionsエミュレータは次の通り。

$ npm install -g @google-cloud/functions-emulator
$ functions start

ローカルでの実行とデプロイは次の通り。

// ローカルデプロイ
$ functions deploy scraper --trigger-http"
// ローカル実行
$ functions call scraper

// 本番デプロイ
$ gcloud beta functions deploy scraper --trigger-http

Functions側をnode v8に設定しないとデプロイがコケます。
詳しいオプションは、こちらとかを見てください。

まとめ

お疲れ様でした。
Functions特有の癖もありますが、サーバレスでHeadless Chromiumを動かせるのはいろいろ応用が広がりそうです。FunctionsからGCSやCloud Store, BigQueryなどにも入れられるので、大規模な運用もできるかもしれません。

参考

39
41
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
41