地上波放送される映画の情報を取得する「TV Films」を作った

地上波放送される映画の情報を取得したく、「TV Films」という npm パッケージ、ウェブページ、API を作ってみた。

「映画の時間」というサイトが地上波の映画放送スケジュールを公開しているので、このページを axios で取得し、cheerio で DOM 操作しスクレイピングしているだけ。根幹の実装はリポジトリ内の lib/index.js にある。

npm コマンド

当初は npm でインストールできる CLI ツールとして考えていて、@neos21/tv-films というパッケージで公開している。コマンドとしての呼び出しは bin/tv-films ファイルで実装している。

$ npm install -g @neos21/tv-films
$ tv-films

# もしくは
$ npx @neos21/tv-films

GitHub Pages でウェブアプリ化

ところで、axios と cheerio は、Node.js 上だけでなくブラウザ上でも動くので、GitHub Pages で動くウェブページを作ってみた。リポジトリ内の gh-pages/ 配下の実装がそれ。Browserify で雑に require() をまとめてやり、CORS Anywhere を噛ませてやることで、GitHub Pages 上から axios による AJAX GET が動くようにした。

Netlify と Vercel で API 公開

CORS Anywhere を噛ませているのは微妙かな、というのと、ウェブページとして見るのではなく JSON を直接取得したいこともあるかな、と思って、NetlifyVercel の Serverless Functions 機能を使って、それぞれに Web API をデプロイしてみた。

Vercel の方が融通が利かないので先に紹介すると、api/tv-films.js で API を定義。public/index.html はこの API をコールする、一応のウェブページ。GitHub Pages 用の HTML とほぼ同じだが、axios によるリクエストが発生するのは Functions 側、つまり Vercel のサーバサイドなので、CORS Anywhere は噛ませていない。

Vercel API を curl でコールして jq 芸をしてやると、直近に放送される映画の情報だけが取得できる。

$ curl -sS https://tv-films.vercel.app/api/tv-films | jq '.films[0]'

Netlify の方は netlify.toml という設定ファイルを書けばもう少し融通が利く。

  1. netlify-lambdanpm install しておく
  2. netlify.toml 設定ファイルで [build] command = "npm run netlify-build" と記述し、ビルドコマンド名を指定する
  3. npm-scripts で "netlify-build": "netlify-lambda build ./src/netlify" と記述し、./src/netlify/ ディレクトリ配下の JS ファイルが Functions としてビルドされるようにする
  4. ビルドされたファイルがどこに置かれるか、という指定は、netlify.tomlfunctions = "netlify-functions" と書いておくことで、./netlify-functions/ ディレクトリに配備されるようになる (ココで axios 等の require しているモノがうまくバンドルされている)

ついでに、./netlify-public/index.html という一応のウェブページを用意しておき、コレも netlify.tomlpublish = "netlify-public" という指定で紐付けておく。

そんなワケで、上のようなウェブページと API ができた。Vercel と同様、curljq で API コールを調整したりもできる。

$ curl -sS https://tv-films.netlify.app/.netlify/functions/tv-films | jq '.films[0]'

Vercel と Netlify とでは、Lambda Functions の書き方の指定が若干異なる。

Netlify の方が素の AWS Lambda と同じ構成で、Vercel は Express の API に相当するようだ。


以上。Vercel と Netlify の使い方の違いを両方整理できたので良かった。