GAS

GASで動的サイトのスクレイピングをする方法

GASは本来静的サイトのスクレイピングが得意ですが、APIを活用することで動的サイトにも対応できます。

▼参考サイト

https://qiita.com/kg_japan/items/f3d14ca7f86767092546

APIの準備

PhantomJsCloudにアクセスして、Sign upするとAPIキーを取得することができます

phantomjscloud.com

GASのコード

const APIKEY = ''; // PhantomJsCloudで取得するAPIキー
const DELAY_TIME = 10; // スクレイピング中の操作に対する待機時間

// PhantomJsCloudのエンドポイントを返す関数
const endpoint = apiKey => `https://PhantomJScloud.com/api/browser/v2/${apiKey}/`;

// スクレイピングの操作に関するペイロードを返す関数
const payload = (month, day, sisetu, delayTime) => ({
 url: 'https://www.net.city.nagoya.jp/cgi-bin/sp05001',
 renderType: 'html',
 outputAsJson: true,
 overseerScript: (`
 // 月の選択
 await page.waitForSelector("select[name=month]");
 await page.select("select[name=month]", "${month}");
 await page.waitForTimeout(${delayTime});

 // 日の選択
 await page.waitForSelector("select[name=day]");
 await page.select("select[name=day]", "${day}");
 await page.waitForTimeout(${delayTime});

 // 施設の選択
 await page.waitForSelector("select[name=sisetu]");
 await page.select("select[name=sisetu]", "${sisetu}");
 await page.waitForTimeout(${delayTime});

 // 照会ボタンのクリック
 await page.click("input[type=button][value=照会]");
 await page.waitForNavigation();

 // 結果ページの待機
 await page.waitForTimeout(${delayTime * 2});
 `)
});

// PhantomJsCloud APIを呼ぶためのオプションを返す関数
const options = payload => ({
 'method': 'post',
 'payload': JSON.stringify(payload)
});

// 指定した日付と施設の空き状況をスクレイピングする関数
function scrapeFacilityAvailability(month, day, sisetu) {
 try {
 const response = UrlFetchApp.fetch(
 endpoint(APIKEY), 
 options(payload(month, day, sisetu, DELAY_TIME))
 );
 
 const result = JSON.parse(response.getContentText())["content"]["data"];
 return result;
 } catch (error) {
 Logger.log(`エラーが発生しました: ${error}`);
 return null;
 }
}

// 実行例
function executeExample() {
 // 例: 4月1日の瑞穂アリーナ第1競技場の空き状況を確認
 const result = scrapeFacilityAvailability(
 "04", // 月
 "01", // 日
 "0261" // 瑞穂アリーナ第1競技場のコード
 );
 
 // スプレッドシートに結果を記録する例
 if (result) {
 const sheet = SpreadsheetApp.getActiveSheet();
 sheet.getRange("A1").setValue(result);
 }
}

// 複数施設の空き状況を一括で取得する関数
function scrapeMultipleFacilities() {
 const facilities = [
 { code: "0261", name: "瑞穂アリーナ第1競技場" },
 { code: "0262", name: "瑞穂アリーナ第2競技場" }
 ];
 
 const month = "04"; // 4月
 const day = "01"; // 1日
 
 const results = [];
 
 facilities.forEach(facility => {
 const result = scrapeFacilityAvailability(month, day, facility.code);
 if (result) {
 results.push({
 facility: facility.name,
 availability: result
 });
 }
 
 // APIの制限を考慮して少し待機
 Utilities.sleep(1000);
 });
 
 return results;
}

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です