県のGo To Eat サイトが使いづらかったのでPlaywright + AppSheetで自分用アプリを作ってみた話
Go To Eat とてもお得な施策で良いのですが「どのお店が使えるんだろう?」ってなりますよね。そんな時に見る県の Go To Eat キャンペーンサイトが、思いのほか使いづらかったので、Playwright + AppSheet で自分用アプリを作ってみた話です。
なぜ作った?
茨城県の Go To Eat キャンペーンサイトはこちらです。
トップページは良い感じです。
が…
店舗一覧ページに遷移するといきなり古き良き業務システムのような感じになります😇
(もうちょっと頑張ってくれ..)
このページだと、
- スマホ対応してないのでスマホで見辛い
- マップ上での検索が出来ないので、現在地周辺の店舗を探すのが面倒
ということでノーコードツールの AppSheet で作り直してみました。
作ってみたもの
AppSheet で作ってみたものがこちらです。
スマホに対応し、店舗名や要素での検索や Maps からの現在地周辺での店舗検索も出来るので、個人用には必要十分です。
この作り方を次項から解説していきます。
作成方法
1. Playwrightでのスクレイピング
アプリを作るためにはデータが必要なので、それをスクレイピングで取得します。
スクレイピングには Node.js のスクレイピングライブラリのPlaywrightを利用します。
1-1. 環境構築
まず、任意のディレクトリでプロジェクトを作成します。
$ yarn init -y
そして依存モジュールを追加します。
json2csv はオブジェクトの CSV へのパースで使用します。
ts-nodeは Node.js での TypeScript の実行環境です。TypeScript を明示的なコンパイル不要で実行できます。
$ yarn add ts-node playwright typescript json2csv
ts-node の実行スクリプトをpackage.json
に追加します。
"scripts": {
"start": "ts-node index.ts"
},
これで環境構築は完了です。
1-2. スクレイピング
index.ts
を追加して以下のコードを記載します。
コードはスクレイピングの関係上ちょっと分かりにくいのですが、以下のような動きをします。
- GoTo Eat 茨城の店舗一覧ページを開く
- 店舗明細行ごとに店舗詳細ページに移動 & 情報を取得
- 全ページ終わったら結果を CSV 形式にパース
- ファイル書き込み
import { chromium } from "playwright";
import { Parser } from "json2csv";
import * as fs from "fs";
const options = {
headless: false,
};
const BASE_URL =
"https://area34.smp.ne.jp/area/table/27130/3jFZ4A/M?S=%70%69%6D%67%6E%32%6C%62%74%69%6E%64&_page_27130";
const PER_PAGE = 10;
(async () => {
const stores = [];
const browser = await chromium.launch(options);
const page = await browser.newPage();
const navigationPromise = page.waitForNavigation();
await page.goto(BASE_URL);
// 最大ページ数を取得
const maxPage = await page.evaluate(() => {
return Math.ceil(
Number(document.querySelector(".smp-count").textContent) / 10
);
});
// 最大ページ数の分だけループ
for (let pageNumber = 1; pageNumber <= maxPage; pageNumber++) {
const currentPageUrl = `${BASE_URL}=${pageNumber}`;
await page.goto(currentPageUrl);
// 5行目からが店舗データなので5始まりとする
for (let rowNumber = 5; rowNumber < PER_PAGE + 5; rowNumber++) {
// 詳細リンクを取得
const detailLinkSelector = (rowNumber: number) => { return `#smp-table-27130 > tbody > tr.smp-row-${rowNumber}.smp-row-data .smp-cell-col-2 > a` }
const detailLink = await page.$(detailLinkSelector(rowNumber));
// 詳細リンクがなければスキップ
if ( !detailLink ) { continue; }
// 詳細ページに遷移してデータを保存
await page.click(detailLinkSelector(rowNumber));
await navigationPromise;
const store = await page.evaluate(() => {
const detailContentData = (rowNumber: number) => {
return document.querySelector(`body > table > tbody > tr > td > div > div.whole > table > tbody > tr:nth-child(${rowNumber}) > td`)?.textContent?.trim() || ''
}
return {
type: detailContentData(10),
name: detailContentData(3),
"phone number": detailContentData(8),
address: detailContentData(6).replace(/\s+/g, "") + detailContentData(7),
homepage: detailContentData(9),
holiday: detailContentData(11),
"business hours": detailContentData(12)
};
});
await page.goto(currentPageUrl);
await navigationPromise;
stores.push(store)
}
}
await browser.close();
// CSVへのパース
const parser = new Parser;
const csv = parser.parse(stores);
// ファイル書き込み
fs.writeFileSync('goto-eat.csv', csv)
})();
あとは実行するだけです。
$ yarn start
Playwright の options で headless を false にしているので、こんな感じに chromium が立ち上がって動くと思います。
完了するとgoto-eat.csv
が出来上がります。
(260 ページあるのでかなり時間かかります)
2. AppSheetでのアプリ作成
店舗データが出来上がったので、これを AppSheet でアプリ化していきます。
2-1. Google スプレッドシートの作成
まず、CSV を Google スプレッドシートで import します。
スプレッドシートを開いて ファイル > インポート > アップロード
で先ほどのgoto-eat.csv
をアップロードすれば OK です。
2-2. AppSheetでのインポート
AppSheet にアクセスします。
Start for free
をクリックして、
Make a new app
> Start with your own data
を選択
Choose your data
から先ほど作ったスプレッドシートを選択すれば OK です。
インポートが完了すると、アプリが作成されます。
シートのヘッダーから自動的に App のカテゴリを認識して良い感じに作ってくれるはずです(すごい)。
あとは、ちょいちょい項目名とかを直してデプロイすれば完了です。
AppSheet のデプロイについてはこちらを参考にさせていただきました。
おわりに
以上「茨城県の Go To Eat サイトが見づらかったので、Playwright + AppSheet で自分用に作り直した話」でした。
Playwright も AppSheet 初めて使ったのですが、どちらも使いやすいですね。
かかった時間は AppSheet のキャッチアップ含めて 3 時間くらいでした。今回みたいな限定した用途でアプリを作るには便利そうです。
三密気をつけながらこのアプリを使って Go To Eat していきたいです。
Discussion