Webサービスでポイントを貯める(ポイ活)ため毎日のようにブラウザを手動で操作していませんか?
そんなときはブラウザ操作を完全自動化して楽をしましょう!
ツールってほどではないですが参考にどうぞ。
もちろんポイ活以外の操作も同様に自動化できます。
ソース(動けばいいってコードなので汚さはご容赦を…):
サマリ
- 「SBI証券のWebサイトを毎日チェックし、新規IPOがあれば申し込む」というのを自動化した。申し込んでも大抵落選するのでIPOチャレンジポイントが貯まる。
- 「Puppeteerでブラウザ操作」するコードをApp Engineへデプロイし、cronで自動実行する。
- 毎月のGCP代は無料枠のおかげで10円だが、頻繁に稼働する場合は料金に注意
自動化していること
- (日次) SBI証券のIPOチェックと申し込み自動化
- 本記事で説明します。
- 例えば2020年はコロナ禍でも85社、つまり85回申し込めたので、手動ではさすがに面倒です。
- (月次) 新生銀行のポイントプログラム自動エントリー
開発
以下、コードは一部をピックアップしたものです。
主な使用技術
- App Engine (スタンダード環境)
- Node.js / JavaScript
- Puppeteer (ブラウザ操作用Nodeライブラリ)
Puppeteerによるブラウザ操作
ブラウザの起動。puppeteer.launch
でブラウザを起動しつつBrowserオブジェクトを取得します。
App Engineのより小さいインスタンスで動くよう、起動オプション(Chromiumの一覧はこちら)をいくつかつけてメモリの使用量を減らします。
import puppeteer from "puppeteer";
export const applyIPO = async () => {
const browser = await puppeteer.launch(
{
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'-–disable-dev-shm-usage',
'--disable-gpu',
'--no-first-run',
'--no-zygote',
'--single-process',
],
}
);
try {
// ブラウザの操作内容を書く
await _apply(browser);
} catch(e) {
console.log("error", e);
} finally {
browser.close();
}
};
次に、ブラウザの操作内容です。
const _apply = async (browser) => {
console.log("start applying IPO");
// タブの初期化
const page = await browser.newPage();
page.setViewport({width: 1280, height: 720});
console.log("succeeded to launch browser");
// ログイン。環境変数からの値取得方法は後述
await page.goto("https://www.sbisec.co.jp/");
await page.type("input[name=user_id]", process.env.SBI_USERNAME);
await page.type("input[name=user_password]", process.env.SBI_PASSWORD);
await page.click("input[name=ACT_login]");
// 1度に5件まで連続して申し込む
let n = 0;
while (n < 5) {
await page.waitForSelector("img", {timeout: 5000});
await page.goto("https://m.sbisec.co.jp/oeliw011?type=21", { waitUntil: "domcontentloaded" });
let canApply = true;
await page.waitForSelector("img[alt=申込]", {timeout: 5000}).catch((e) => {
if (!(e instanceof puppeteer.errors.TimeoutError)) {
console.error(e);
}
canApply = false;
});
// これ以上申し込み不可なら終了
if (!canApply) {
console.log("no more BB");
break;
};
await page.click("img[alt=申込]");
// 100株で申し込み
await page.waitForSelector("input[name=suryo]", {timeout: 5000});
await page.type("input[name=suryo]", "100");
await page.click("#strPriceRadio");
await page.type("input[name=tr_pass]", process.env.SBI_TRADE_PASSWORD);
await page.click("input[name=order_kakunin]");
await page.waitForTimeout(1000);
await page.click("input[name=order_btn]");
console.log(`apply ${n}`);
n += 1;
}
}
補足
- 単に
waitForTimeout
よりはwaitForSelector
のほうが、操作したいDOM Objectを待つなら望ましいです - 結果をSlackに投稿したいならこんな感じです。
API用意
App Engineのcronから呼び出せるよう、API化します。
import express from "express";
import { applyIPO } from "./apply_ipo";
// .envから
環境変数を読み込み
import dotenv from "dotenv";
dotenv.config();
const app = express();
app.get('/apply-ipo', (_, res, next) => {
console.log("requested");
applyIPO().then(
() => {
res.status(200).send('OK').end();
SERVER.close();
}
).catch(next);
});
const PORT = process.env.PORT || 8000;
const SERVER = app.listen(PORT, () => {
console.log(`App listening on port ${PORT}`);
console.log('Press Ctrl+C to quit.');
});
module.exports = app;
.envは環境変数名とその値を書くので
SBI_USERNAME=hoge
...
などとなります。
App Engine
package.jsonにbuild / start を登録します。babelは割愛
{
"scripts": {
"build": "babel src -d ./dist/",
"start": "node dist/app.js"
},
...
}
appの構成ファイルは↓だけでOKです。F2以下だとメモリ不足でエラーになる場合がありました。
runtime: nodejs12
instance_class: F4
gcloud app deploy --version=1 --quiet
定期実行するには
cron:
- description: Apply IPO on SBI Securities
url: /apply-ipo
schedule: every day 1:00
timezone: Asia/Tokyo
などと書いて
gcloud app deploy cron.yaml --quiet
で登録します。
セキュリティの強化
申し訳程度ですが、cronスケジューラからのAPIコールのみ許可するfirewallを設定します。
gcloud app firewall-rules update default --action=deny
gcloud app firewall-rules create 1 \
--action=allow \
--source-range='10.0.0.1'
gcloud app firewall-rules create 2 \
--action=allow \
--source-range='0.1.0.1'
費用
ポイントを貯めるのにサーバー費用がかさんでしまっては本末転倒です。
幸いなことに、GCPにはかなりの無料枠があるので毎月10円と安く済んでいます。
- App Engine: 0円
-
毎日28時間分のFインスタンスが無料なのは大きいです。
- 例: F2インスタンスなら 28/2 = 14時間、F4なら28/4 = 7時間相当が無料
-
毎日28時間分のFインスタンスが無料なのは大きいです。
- Cloud Storage: 9円
- 消費税: 1円
失敗談
5分おきに、とあるチケットをキャンセル待ちチェックしてSlackに通知していたのですが、
解除し忘れて4,515円かかりました。
App EngineはF2以上のインスタンスを常時稼働するとそれなりにかかるのでご注意ください。
また、急に料金が増えたときに気がつけるよう、予算アラートを設定しましょう!