Cloudflare Workers / Cron Triggers で定期的にスクレイピング (GitHub Actions デプロイ)

2024/09/06に公開

なんだかんだたまにやるスクレイピングを Cloudflare Workers で定期実行する方法で実装してみました。

なお、Google Apps Script (GAS) でも同様のことができます(実際、最初は GAS でやろうとしていました)。
GAS での実装方法については以下の記事も参考にしていただけると嬉しいです!

定額給付金の案内ページを監視して更新があれば Slack に通知するボット #GoogleAppsScript - Qiita
https://qiita.com/y_k/items/39be3f144bbdd7d4ca89

概要

Cloudflare Workersを使用して、簡単にウェブサイトから情報を取得し、定期的に自動実行できるシステムの構築をします。
この記事ではプロジェクトの作成から、スクリプトの作成、定期実行の設定方法を紹介します。
また、GitHub Actionsによる自動デプロイの設定方法も合わせて紹介します。

注意

スクレイピングはウェブサイトの利用規約で禁止されている場合があります。
また、スクレイピングを行う際は、ウェブサイトの負荷に配慮し、適切な間隔で実行するようにしましょう。

なお、この記事の内容を実行したことによるいかなる損害についても責任を負いません。

特徴

この構成の特徴は以下の通りです。

  • メリット: 100,000 回/日まで無料
  • 注意点: 呼び出しごとに CPU 時間は 10 ミリ秒まで

ほとんどのユースケースは無料で実行できるかと思います!

前提

  • Cloudflare のアカウントがあること
  • GitHub のアカウントがあること
  • Node.js がインストールされていること
  • この記事では pnpm を使用します
    もちろん npm や yarn 等でも問題ありません。適宜読み替えてください。

手順

1. プロジェクトの作成

新たなプロジェクトの作成から始めます。
プロジェクト名は test-project は適宜変更してください。

$ pnpm create cloudflare@latest test-project
.../191bc87c97e-1615b                    |   +1 +
.../191bc87c97e-1615b                    | Progress: resolved 1, reused 1, downloaded 0, added 1, done

 ╭──────────────────────────────────────────────────────────────╮
 │ 👋 Welcome to create-cloudflare v2.26.0!                     │
 │ 🧡 Let's get started.                                        │
 ╰──────────────────────────────────────────────────────────────╯
╭ Create an application with Cloudflare Step 1 of 3
│
├ In which directory do you want to create your application?
│ dir ./test-project
│
├ What would you like to start with?
│ category Hello World example
│
├ Which template would you like to use?
│ type Hello World Worker
│
├ Which language do you want to use?
│ lang TypeScript
│
├ Copying template files
│ files copied to project directory
│
├ Updating name in `package.json`
│ updated `package.json`
│
├ Installing dependencies
│ installed via `pnpm install`
│
╰ Application created

╭ Configuring your application for Cloudflare Step 2 of 3
│
├ Installing @cloudflare/workers-types
│ installed via pnpm
│
├ Adding latest types to `tsconfig.json`
│ added @cloudflare/workers-types/2023-07-01
│
├ Retrieving current workerd compatibility date
│ compatibility date 2024-09-03
│
├ Do you want to use git for version control?
│ yes git
│
├ Must configure `user.name` and user.email` to use git. Continuing without git.
│
╰ Application configured

╭ Deploy with Cloudflare Step 3 of 3
│
├ Do you want to deploy your application?
│ no deploy via `pnpm run deploy`
│
╰ Done

 ╭────────────────────────────────────────────────────────────────╮
 │ 🎉  SUCCESS  Application created successfully!                 │
 │                                                                │
 │ 💻 Continue Developing                                         │
 │    Change directories: cd test-project                         │
 │    Start dev server: pnpm run start                            │
 │    Deploy: pnpm run deploy                                     │
 │                                                                │
 │ 📖 Explore Documentation                                       │
 │    https://developers.cloudflare.com/workers                   │
 │                                                                │
 │ 💬 Join our Community                                          │
 │    https://discord.cloudflare.com                              │
 ╰────────────────────────────────────────────────────────────────╯

$ cd test-project

以降は test-project (プロジェクト名) ディレクトリで作業を行います。

2. スクリプトの作成

実行するスクリプトを作成します。

2.1. ライブラリの追加

スクレイピング用のライブラリを追加します。
ここでは、軽量かつ高速なスクレイピングライブラリである cheerio を使用します。

$ pnpm add -D -E cheerio                                            
 WARN  2 deprecated subdependencies found: rollup-plugin-inject@3.0.2, sourcemap-codec@1.4.8
Packages: +21
+++++++++++++++++++++
Progress: resolved 236, reused 169, downloaded 5, added 21, done

devDependencies:
+ cheerio 1.0.0

Done in 1.7s

2.2. src/index.ts を編集

指定した URL にアクセスしてレスポンスを解析します。
今回は https://www.yk-lab.net の h1 タグの中身を取得するスクリプトを作成します。

src/index.ts
import * as cheerio from "cheerio";

export default {
 async scheduled(event, env, ctx) {
  const $ = cheerio.load(
   await fetch('https://www.yk-lab.net', {
    headers: {
     "user-agent": "bot",
    },
   }).then((res) => res.text())
  );
  const h1Text = $('h1').text();
  console.log(h1Text);
 },
} satisfies ExportedHandler<Env>;

2.3. 動作確認

ローカルで動作確認します。

サーバー起動
$ pnpm dev --test-scheduled

> test-project@0.0.0 dev /Users/yk/works/test-project
> wrangler dev "--test-scheduled"


 ⛅️ wrangler 3.74.0
-------------------

[wrangler:inf] Ready on http://localhost:8787
⎔ Starting local server...
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ [b] open a browser, [d] open Devtools, [l] turn off local mode, [c] clear console, [x] to exit                                                                                     │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

別のターミナルで curl でアクセス

アクセス
$ curl "http://localhost:8787/__scheduled?cron=*+*+*+*+*"
Ran scheduled event

すると元々のサーバーを起動したターミナルに h1 タグの中身が表示されます。

yk-Lab…
[wrangler:inf] GET /__scheduled 200 OK (787ms)

3. 定期実行の設定

wrangler.toml を編集して定期実行の設定を追加します。

wrangler.toml
[triggers]
crons = [ "*/5 * * * *" ]

この設定は 5 分ごとに実行する設定です。

4. GitHub Actions でデプロイ

プルリクのマージ等で main ブランチに push すると自動でデプロイするように設定します。

.github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    name: Deploy
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        name: Install pnpm
        with:
          run_install: false
      - uses: actions/setup-node@v4
        with:
          node-version-file: '.node-version'
          cache: 'pnpm'
      - name: Deploy
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}

CLOUDFLARE_API_TOKEN は Cloudflare から取得して GitHub の Secrets に登録する必要があります。
トークンの取得方法は以下の記事を参考にしてください。

https://developers.cloudflare.com/fundamentals/api/get-started/create-token/

まとめ

Cloudflare Workers で定期実行する方法を試してみました。
GitHub Actions でデプロイを自動化することで、手動でデプロイする手間を省くことができます。
それにより dependabot などの自動化も組み合わせることで、より効率的に運用することができます。

また、Cloudflare Workers は無料で 100,000 回/日まで利用できるため、小規模なスクレイピングなどにも利用できると思います。

参考

https://qiita.com/RuruCun/items/7b4c03c743fe1de37920
https://developers.cloudflare.com/workers/runtime-apis/handlers/scheduled/
https://developers.cloudflare.com/workers/configuration/cron-triggers/

Discussion