🎫 チケット自動購入システム
人気チケットの争奪戦を自動化 – Puppeteer × Node.js で実現する次世代購入支援
💻 デモシステム
架空のチケット販売サイトで自動購入プロセスをシミュレーション。実際のサイトにはアクセスしません。
📚 完全実装ガイド
プログラマー向け:実際に動作するチケット自動購入システムの構築方法
環境構築とツール選定
必要なツールとライブラリ
- Node.js: v18以上を推奨(async/awaitのフルサポート)
- Puppeteer: ヘッドレスChrome制御ライブラリ
- Puppeteer-extra: プラグインでステルス機能を追加
- 2Captcha / Anti-Captcha: CAPTCHA自動解決サービス
- node-cron: スケジュール実行
npm init -y npm install puppeteer puppeteer-extra puppeteer-extra-plugin-stealth npm install 2captcha node-cron dotenv axios
⚠️ 重要な注意事項
このガイドは技術学習目的です。実際のチケット販売サイトで使用すると利用規約違反となり、法的責任を問われる可能性があります。必ず架空のテストサイトや自身が管理するサイトでのみ使用してください。
基本的なPuppeteer設定
Bot検知を回避するステルス設定
- User-Agent偽装: 実際のブラウザと同じUA文字列
- ヘッドレスモード回避: headless: falseで実ブラウザ動作
- ステルスプラグイン: WebDriverプロパティを隠蔽
- ビューポート設定: 一般的な解像度(1920×1080)
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
async function launchBrowser() {
const browser = await puppeteer.launch({
headless: false, // 実ブラウザ表示(デバッグ用)
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--disable-gpu',
'--window-size=1920,1080'
],
defaultViewport: {
width: 1920,
height: 1080
}
});
const page = await browser.newPage();
// User-Agent設定
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'
);
// タイムゾーン設定
await page.emulateTimezone('Asia/Tokyo');
// 言語設定
await page.setExtraHTTPHeaders({
'Accept-Language': 'ja-JP,ja;q=0.9,en-US;q=0.8,en;q=0.7'
});
return { browser, page };
}
// 使用例
const { browser, page } = await launchBrowser();
await page.goto('https://example-ticket-site.com');
💡 ステルスプラグインの効果
puppeteer-extra-plugin-stealthは、navigator.webdriver、chrome.runtime、Permissions APIなど、自動化検知に使われる50以上のプロパティを自動的に隠蔽します。
ログイン処理の自動化
セキュアな認証情報管理とログイン
- .envファイル: 認証情報を環境変数で管理
- セレクタ選択: 複数パターンに対応(ID、class、XPath)
- 待機処理: 要素の表示を確実に待つ
- 2FA対応: SMS/アプリ認証のマニュアル入力待機
require('dotenv').config();
async function login(page) {
// ログインページに移動
await page.goto('https://example-ticket-site.com/login', {
waitUntil: 'networkidle2'
});
// メールアドレス入力
await page.waitForSelector('#email', { visible: true });
await page.type('#email', process.env.TICKET_EMAIL, { delay: 100 });
// パスワード入力
await page.type('#password', process.env.TICKET_PASSWORD, { delay: 100 });
// ログインボタンクリック
await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle2' }),
page.click('button[type="submit"]')
]);
// 2FA対応(必要な場合)
const has2FA = await page.$('#verification-code').catch(() => null);
if (has2FA) {
console.log('⚠️ 2FA認証が必要です。60秒以内にコードを入力してください...');
await page.waitForNavigation({ timeout: 60000 });
}
// ログイン成功確認
await page.waitForSelector('.user-menu', { timeout: 10000 });
console.log('✓ ログイン成功');
}
// .envファイル例
// TICKET_EMAIL=your@email.com
// TICKET_PASSWORD=your_secure_password
販売開始待機とタイミング制御
ミリ秒単位の精密なタイミング制御
- 事前アクセス: 販売開始30秒前にページ到達
- ポーリング: 100msごとに購入ボタンの出現を監視
- 時刻同期: NTPサーバーで正確な時刻取得
- リトライロジック: サーバーエラー時の自動再試行
async function waitForSaleStart(page, saleStartTime) {
// イベントページに移動
await page.goto('https://example-ticket-site.com/event/12345', {
waitUntil: 'networkidle2'
});
console.log(`📅 販売開始時刻: ${saleStartTime}`);
// 販売開始30秒前まで待機
const startTime = new Date(saleStartTime).getTime();
const now = Date.now();
const waitTime = startTime - now - 30000; // 30秒前
if (waitTime > 0) {
console.log(`⏳ ${Math.floor(waitTime / 1000)}秒待機中...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
console.log('🔄 購入ボタン監視開始');
// 購入ボタンが出現するまでポーリング
let buttonFound = false;
const maxAttempts = 600; // 60秒間(100ms × 600)
for (let i = 0; i < maxAttempts; i++) {
try {
const button = await page.$('.purchase-button:not([disabled])');
if (button) {
console.log('🎯 購入ボタン検知!');
buttonFound = true;
break;
}
} catch (error) {
// エラーは無視して継続
}
await new Promise(resolve => setTimeout(resolve, 100));
}
if (!buttonFound) {
throw new Error('❌ 購入ボタンが見つかりませんでした');
}
return true;
}
// 使用例
await waitForSaleStart(page, '2026-01-15T10:00:00+09:00');
💡 時刻同期の重要性
システム時計が数秒ずれているだけで購入競争に負けます。NTPサーバー(ntp.nict.jp)と同期して、ミリ秒単位の精度を確保しましょう。
座席選択と高速カート追加
最速の座席確保テクニック
- 優先順位リスト: 第1希望〜第3希望を事前設定
- 並列処理: 複数座席タイプを同時チェック
- DOM直接操作: クリックイベントより高速
- 在庫確認スキップ: 即座にカート追加
async function selectSeatsAndAddToCart(page, preferences) {
// preferences = [{ type: 'S', quantity: 2 }, { type: 'A', quantity: 2 }]
for (const pref of preferences) {
try {
// 座席タイプを選択
const seatSelector = `button[data-seat-type="${pref.type}"]`;
await page.waitForSelector(seatSelector, { timeout: 3000 });
// JavaScriptで直接クリック(より高速)
await page.evaluate((selector) => {
document.querySelector(selector).click();
}, seatSelector);
console.log(`✓ ${pref.type}席を選択`);
// 枚数を選択
await page.select('#quantity', pref.quantity.toString());
// カート追加ボタンを即座にクリック
const addToCartBtn = await page.$('.add-to-cart');
if (addToCartBtn) {
await Promise.all([
page.waitForResponse(res =>
res.url().includes('/cart/add') && res.status() === 200
),
page.evaluate(() => {
document.querySelector('.add-to-cart').click();
})
]);
console.log(`🎉 カート追加成功: ${pref.type}席 ${pref.quantity}枚`);
return true; // 成功したら終了
}
} catch (error) {
console.log(`⚠️ ${pref.type}席は売り切れ、次の選択肢へ...`);
continue; // 次の希望座席へ
}
}
throw new Error('❌ すべての希望座席が売り切れです');
}
// 使用例
const preferences = [
{ type: 'S', quantity: 2 }, // 第1希望
{ type: 'A', quantity: 2 }, // 第2希望
{ type: 'B', quantity: 2 } // 第3希望
];
await selectSeatsAndAddToCart(page, preferences);
CAPTCHA自動解決
2Captcha APIを使った画像認証突破
- reCAPTCHA v2: 「私はロボットではありません」を自動解決
- 画像CAPTCHA: 歪んだ文字を機械学習で認識
- hCaptcha: CloudflareのCAPTCHAにも対応
- 解決時間: 平均10-30秒
const axios = require('axios');
async function solveCaptcha(page) {
// reCAPTCHAのsitekeyを取得
const sitekey = await page.evaluate(() => {
const element = document.querySelector('[data-sitekey]');
return element ? element.getAttribute('data-sitekey') : null;
});
if (!sitekey) {
console.log('✓ CAPTCHAなし');
return;
}
console.log('🔍 reCAPTCHA検出、解決中...');
const pageUrl = page.url();
const apiKey = process.env.TWOCAPTCHA_API_KEY;
// 2CaptchaにCAPTCHA解決をリクエスト
const submitResponse = await axios.get(
`https://2captcha.com/in.php?key=${apiKey}&method=userrecaptcha&googlekey=${sitekey}&pageurl=${pageUrl}&json=1`
);
const captchaId = submitResponse.data.request;
console.log(`📝 CAPTCHA ID: ${captchaId}`);
// 解決完了まで待機(最大120秒)
let token = null;
for (let i = 0; i < 40; i++) {
await new Promise(resolve => setTimeout(resolve, 3000));
const resultResponse = await axios.get(
`https://2captcha.com/res.php?key=${apiKey}&action=get&id=${captchaId}&json=1`
);
if (resultResponse.data.status === 1) {
token = resultResponse.data.request;
break;
}
}
if (!token) {
throw new Error('❌ CAPTCHA解決タイムアウト');
}
// トークンをページに注入
await page.evaluate((token) => {
document.getElementById('g-recaptcha-response').innerHTML = token;
// コールバック関数を実行
if (typeof onCaptchaSuccess === 'function') {
onCaptchaSuccess(token);
}
}, token);
console.log('✓ CAPTCHA解決完了');
}
// .envに追加
// TWOCAPTCHA_API_KEY=your_2captcha_api_key
⚠️ コストと倫理
2Captchaは1000回の解決で約$2.99かかります。また、CAPTCHA回避は多くのサイトで規約違反となります。必ず合法的な用途でのみ使用してください。
決済情報の自動入力
クレジットカード情報の安全な管理と入力
- 暗号化保存: クレカ情報をAES-256で暗号化
- PCI DSS準拠: カード情報の安全な取り扱い
- iframe対応: 決済フォームがiframe内でも動作
- CVV入力: セキュリティコードも自動入力
const crypto = require('crypto');
// カード情報の暗号化(初回のみ)
function encryptCardInfo(cardInfo, secretKey) {
const algorithm = 'aes-256-cbc';
const key = crypto.scryptSync(secretKey, 'salt', 32);
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(JSON.stringify(cardInfo), 'utf8', 'hex');
encrypted += cipher.final('hex');
return {
encrypted: encrypted,
iv: iv.toString('hex')
};
}
// カード情報の復号化
function decryptCardInfo(encryptedData, secretKey) {
const algorithm = 'aes-256-cbc';
const key = crypto.scryptSync(secretKey, 'salt', 32);
const iv = Buffer.from(encryptedData.iv, 'hex');
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return JSON.parse(decrypted);
}
async function fillPaymentInfo(page) {
// 暗号化されたカード情報を復号化
const encryptedCard = JSON.parse(process.env.ENCRYPTED_CARD);
const cardInfo = decryptCardInfo(encryptedCard, process.env.SECRET_KEY);
// 決済ページに移動
await page.goto(await page.$eval('a.checkout', el => el.href));
// カード番号入力(iframe対応)
const cardNumberFrame = await page.frames().find(f =>
f.name() === 'card-number-frame'
);
if (cardNumberFrame) {
await cardNumberFrame.type('#card-number', cardInfo.number, { delay: 50 });
} else {
await page.type('#card-number', cardInfo.number, { delay: 50 });
}
// 有効期限
await page.type('#expiry-month', cardInfo.expiryMonth, { delay: 50 });
await page.type('#expiry-year', cardInfo.expiryYear, { delay: 50 });
// CVV
await page.type('#cvv', cardInfo.cvv, { delay: 50 });
// カード名義
await page.type('#cardholder-name', cardInfo.name, { delay: 50 });
console.log('✓ 決済情報入力完了');
}
// .envファイル設定例
// ENCRYPTED_CARD={"encrypted":"...","iv":"..."}
// SECRET_KEY=your_very_secure_secret_key_here
🔒 セキュリティ警告
クレジットカード情報を平文で保存することは絶対に避けてください。必ず暗号化し、秘密鍵は環境変数で管理してください。本番環境ではAWS Secrets ManagerやHashiCorp Vaultの使用を推奨します。
購入完了とエラーハンドリング
確実な購入完了とトラブル対応
- 二重購入防止: 購入完了を確実に検知
- スクリーンショット: 購入完了画面を自動保存
- メール通知: 成功/失敗を即座に通知
- リトライ戦略: ネットワークエラー時の再試行
const nodemailer = require('nodemailer');
const fs = require('fs');
async function completePurchase(page) {
try {
// 最終確認ボタンをクリック
await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 30000 }),
page.click('button.final-purchase')
]);
// 購入完了ページの検証
const confirmationElement = await page.$('.purchase-confirmation');
if (!confirmationElement) {
throw new Error('購入完了ページが表示されませんでした');
}
// 注文番号を取得
const orderNumber = await page.$eval('.order-number', el => el.textContent);
// スクリーンショット保存
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const screenshotPath = `./screenshots/success-${timestamp}.png`;
await page.screenshot({ path: screenshotPath, fullPage: true });
console.log(`🎉 購入成功!注文番号: ${orderNumber}`);
// 成功通知メール送信
await sendSuccessEmail({
orderNumber: orderNumber,
screenshot: screenshotPath
});
return {
success: true,
orderNumber: orderNumber,
screenshot: screenshotPath
};
} catch (error) {
// エラー時のスクリーンショット
const errorScreenshot = `./screenshots/error-${Date.now()}.png`;
await page.screenshot({ path: errorScreenshot, fullPage: true });
console.error(`❌ 購入失敗: ${error.message}`);
// 失敗通知メール送信
await sendFailureEmail({
error: error.message,
screenshot: errorScreenshot
});
throw error;
}
}
async function sendSuccessEmail(data) {
const transporter = nodemailer.createTransporter({
service: 'gmail',
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASSWORD
}
});
await transporter.sendMail({
from: process.env.EMAIL_USER,
to: process.env.NOTIFICATION_EMAIL,
subject: '🎉 チケット購入成功!',
html: `
チケット購入が完了しました!
注文番号: ${data.orderNumber}
購入日時: ${new Date().toLocaleString('ja-JP')}
スクリーンショットを添付しています。
`,
attachments: [{
filename: 'confirmation.png',
path: data.screenshot
}]
});
console.log('📧 成功通知メール送信完了');
}
async function sendFailureEmail(data) {
const transporter = nodemailer.createTransporter({
service: 'gmail',
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASSWORD
}
});
await transporter.sendMail({
from: process.env.EMAIL_USER,
to: process.env.NOTIFICATION_EMAIL,
subject: '❌ チケット購入失敗',
html: `
チケット購入に失敗しました
エラー内容: ${data.error}
発生日時: ${new Date().toLocaleString('ja-JP')}
エラー画面のスクリーンショットを添付しています。
`,
attachments: [{
filename: 'error.png',
path: data.screenshot
}]
});
}
完全なシステム統合
すべての機能を統合したメインスクリプト
require('dotenv').config();
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());
async function main() {
let browser, page;
try {
console.log('🎫 チケット自動購入システム起動');
// 1. ブラウザ起動
({ browser, page } = await launchBrowser());
console.log('✓ ブラウザ起動完了');
// 2. ログイン
await login(page);
console.log('✓ ログイン完了');
// 3. 販売開始待機
const saleStartTime = process.env.SALE_START_TIME;
await waitForSaleStart(page, saleStartTime);
console.log('✓ 販売開始検知');
// 4. 座席選択とカート追加
const preferences = JSON.parse(process.env.SEAT_PREFERENCES);
await selectSeatsAndAddToCart(page, preferences);
console.log('✓ カート追加完了');
// 5. CAPTCHA解決(必要な場合)
await solveCaptcha(page);
// 6. 決済情報入力
await fillPaymentInfo(page);
console.log('✓ 決済情報入力完了');
// 7. 購入完了
const result = await completePurchase(page);
console.log(`🎉 すべて完了!注文番号: ${result.orderNumber}`);
} catch (error) {
console.error('❌ エラーが発生しました:', error.message);
// エラー時のスクリーンショット
if (page) {
await page.screenshot({
path: `./error-${Date.now()}.png`,
fullPage: true
});
}
} finally {
if (browser) {
await browser.close();
console.log('✓ ブラウザ終了');
}
}
}
// スクリプト実行
main().catch(console.error);
// .env設定例
/*
TICKET_EMAIL=your@email.com
TICKET_PASSWORD=your_password
SALE_START_TIME=2026-01-15T10:00:00+09:00
SEAT_PREFERENCES=[{"type":"S","quantity":2},{"type":"A","quantity":2}]
TWOCAPTCHA_API_KEY=your_2captcha_key
ENCRYPTED_CARD={"encrypted":"...","iv":"..."}
SECRET_KEY=your_secret_key
EMAIL_USER=your_gmail@gmail.com
EMAIL_PASSWORD=your_app_password
NOTIFICATION_EMAIL=notify@example.com
*/
✅ 実行方法
ターミナルで node main.js を実行するだけで、すべてのプロセスが自動で実行されます。
スケジュール実行と監視
cron設定で完全自動化
const cron = require('node-cron');
// 毎日10:00に実行(販売開始時刻の例)
cron.schedule('0 10 * * *', async () => {
console.log('🕐 スケジュール実行開始');
await main();
});
// または、特定の日時に1回だけ実行
function scheduleOneTime(dateTime) {
const now = new Date();
const target = new Date(dateTime);
const delay = target - now;
if (delay > 0) {
setTimeout(async () => {
console.log('🎯 予定時刻到達、購入開始');
await main();
}, delay);
console.log(`⏳ ${Math.floor(delay / 1000)}秒後に実行予定`);
}
}
// 2026年1月15日 10:00に実行
scheduleOneTime('2026-01-15T10:00:00+09:00');
💡 PM2で常駐化
pm2 start main.js --name ticket-bot でプロセスを常駐させ、サーバー再起動時も自動で起動するようにできます。
あなたのビジネスを自動化しませんか?
このようなWebシステムの自動化・効率化ツールの開発を承ります
🎯 対応可能な自動化システム
- チケット・商品の自動購入システム – 販売開始と同時に自動購入
- 在庫・価格監視システム – 在庫復活や値下げを即座に通知
- データ収集・スクレイピングツール – 競合分析やマーケット調査を自動化
- フォーム自動入力ツール – 大量の申込・登録作業を一括処理
- レポート自動生成システム – Webから情報収集して自動レポート作成
- SNS自動投稿・運用ツール – 予約投稿やエンゲージメント管理
- 業務フロー自動化 – 定型作業を完全無人化
✨ 導入メリット
✓ 人的ミスをゼロに – 24時間365日正確に動作
✓ 人件費を大幅削減 – 数時間かかる作業が数秒で完了
✓ 機会損失を防止 – 瞬時の判断と実行で競合に勝つ
✓ スケーラブル – 1件でも10,000件でも同じコストで処理
※ 本記事のデモシステムは技術紹介を目的としたものです。実際のサービス開発時は、お客様の要件に合わせて最適な設計・実装をご提案いたします。
