IEでのスクレイピングができなくなったので別の方法を色々と検討中
以前にVBAとIEを用いて乗り換え検索での所要時間を取得するツールを使っていましたが、IEが使えなくなったので代替手段を検討しておりまして、前回はこちらでPythonのBeautifulSoupを使ったコードをご紹介しました。
Pythonは使える環境にある人は便利なのですが、プログラミングを知らない多くの人に共有する際には環境構築が面倒だったり、バージョン違いによる挙動の差を考慮しないといけなかったり制約が多いです。
そこでもっと手軽に共有できる方法を求めて、Googleアカウントさえあれば環境構築もなく無料で使用できるGASでコードを考えてみました。
今回はYahoo乗り換え検索を用いて所要時間を確認するGASのコードと使い方をご紹介します。
スプレッドシートについて
スプレッドシートの概要説明
もともと大量の経路について所要時間を調べる目的のツールですので、スプレッドシートは1行ごとに調べたい経路を記載しておいて、
その情報をGASで読み取って乗り換え検索ページに入力する運用を想定しています。
取得した結果については同じスプレッドシートの右側に記載欄を用意して入力されるようにしています。

条件入力列(A~L列)
検索用の条件入力は以下の通りです。
①出発
駅名もしくは住所などを記載します。大宮駅(埼玉・京都)など同じ駅名などがある場合は住所を記載した方が確実です。
②到着
出発と同じく駅名もしくは住所などを記載します。
③出発・到着:時間などを記載する際の条件入力欄です。
「出発」(出発時間で検索する)、「到着」(到着時間で検索する)、「始発」、「終電」、「指定なし」を選択します。
④日付
検索したい日付を入力します。「ダイヤ改正の影響」と「平日・休日」での違いも含んで結果を受け取るために正確に入力した方が精度が高くなります。
⑤時間(空欄なら9時)
検索条件の出発時間・到着時間を入力する欄です。
もともと会社への到着時間を想定して作成したので、空白だった場合③の条件次第で朝9時(出発・到着)を検索します。
⑥飛行機・⑦新幹線・⑧有料特急・⑨高速バス・⑩路線バス・⑪フェリー
飛行機・新幹線などの移動手段を使用するかしないかを選択します。
空欄だった場合使用しないことになります。(私は「〇」を入力して使用するフラグにしています。)
⑫優先
検索の際に優先する項目です。「到着が早い順」、「料金が安い順」、「乗り換え回数順」の中から選択します。
結果入力(M~T列)
結果については1ページ目に表示される3種類の所要時間と交通費、および検索で使用したURLを記載します。
スポンサーリンク
GASのコードの紹介
GASのコードについては以下の通りです。
今回はネットで情報収集しやすかった「Parser」というライブラリ(ライブラリID:1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw)を使用します。
ライブラリの追加はこちらのページを参考にさせていただきました。
タグの取得手順はIEとVBAの操作やSeleniumなどよりはPythonで紹介したBeautifulSoupに近い印象でした。
(文字列で取得する方法は慣れていなくて理解するのが難しかったです。)
function getRoute() {
let ss = SpreadsheetApp.getActiveSpreadsheet();
let tarSheet = ss.getSheets()[0];
let ssArr = func_shToArr(tarSheet);
for (i = 1; i < ssArr.length; i++) {
let tarRowArr = [ssArr[i]]; //1行分を対象として抜き出して、行数1の二次元配列に格納
let tarUrl = func_getUrl(tarRowArr);
let response = UrlFetchApp.fetch(tarUrl);
let content = response.getContentText("utf-8");
let body = Parser.data(content).from('').build()
// console.log(body);
let boxInfo = Parser.data(body).from('
').to('/g, "").replace(/
/g, "").replace(/<.*>/g, " "); // 条件入力
let navi = Parser.data(content).from('').to('
').to('').iterate()
let pFareArr = Parser.data(navi).from('').to('').iterate()
for (x = 0; x < 3; x++) {
// 時間・余計なタグ情報を削除
pTimeArr[x] = pTimeArr[x].replace(/<\/span>/g, "").replace('', "").replace('', " ").replace(//g, " ");
tarRowArr[0][13 + 2 * x] = pTimeArr[x];
// 料金・余計なタグ情報を削除
pFareArr[x] = pFareArr[x].replace(/<\/span>/g, "").replace('', "").replace(/<.*>/g, " ");
tarRowArr[0][14 + 2 * x] = pFareArr[x];
}
tarRowArr[0][19] = tarUrl;
arrToSh(tarRowArr, tarSheet, i + 1, 1); // 行ごとに入力(エラーがあったときに途中まではきちんと入力されているのを確認できるように。)
}
}
// スプレッドシートの情報から検索条件を取得・GET送信なのでURLのパラメータを設定して返す
function func_getUrl(tarRowArr) {
出発 = tarRowArr[0][0];
到着 = tarRowArr[0][1];
if (tarRowArr[0][2] == "出発") {
検索タイプ = "1";
} else if (tarRowArr[0][2] == "到着") {
検索タイプ = "4";
} else if (tarRowArr[0][2] == "始発") {
検索タイプ = "3";
} else if (tarRowArr[0][2] == "終電") {
検索タイプ = "2";
} else if (tarRowArr[0][2] == "指定なし") {
検索タイプ = "5";
} else {
検索タイプ = "5";
}
if (tarRowArr[0][3] != "") {
日付 = tarRowArr[0][3];
} else {
let date = new Date();;
日付 = Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy/MM/dd');
}
if (tarRowArr[0][4] != "") {
時間 = tarRowArr[0][4];
} else {
時間 = "09:00";
}
if (tarRowArr[0][5] != "") {
飛行機 = "1";
} else {
飛行機 = "0";
}
if (tarRowArr[0][6] != "") {
新幹線 = "1";
} else {
新幹線 = "0";
}
if (tarRowArr[0][7] != "") {
有料特急 = "1";
} else {
有料特急 = "0";
}
if (tarRowArr[0][9] != "") {
高速バス = "1";
} else {
高速バス = "0";
}
if (tarRowArr[0][9] != "") {
路線バス = "1";
} else {
路線バス = "0";
}
if (tarRowArr[0][10] != "") {
フェリー = "1";
} else {
フェリー = "0";
}
if (tarRowArr[0][11] == "到着が早い順") {
検索結果の表示順 = "0";
} else if (tarRowArr[0][11] == "料金が安い順") {
検索結果の表示順 = "1";
} else if (tarRowArr[0][11] == "乗り換え回数順") {
検索結果の表示順 = "2";
} else {
検索結果の表示順 = "0";
}
let tarUrl = "https://transit.yahoo.co.jp/search/result?flatlon=&" +
"from=" + encodeURI(出発) +
"&tlatlon=" +
"&to=" + encodeURI(到着) +
"&via=&via=&via=" +
"&y=" + 日付.substring(0, 4) + //Utilities.formatDate(日付,"yyyy")
"&m=" + 日付.substring(5, 7) + //Utilities.formatDate(日付,"MM")
"&d=" + 日付.substring(8, 10) +
"&hh=" + 時間.substring(0, 2) +
"&m2=" + 時間.substring(4, 5) +
"&m1=" + 時間.substring(3, 4) +
"&type=" + 検索タイプ +
"&ticket=" + "ic" +
"&al=" + 飛行機 +
"&shin=" + 新幹線 +
"&ex=" + 有料特急 +
"&hb=" + 高速バス +
"&lb=" + 路線バス +
"&sr=" + フェリー +
"&s=" + 検索結果の表示順 +
"&expkind=" + "1" + "&ws=" + "3"
return tarUrl;
}
//最終行を取得する関数
function func_getTarLastRow(sheet) {
//最終行の取得フロー開始
let tarValues = sheet.getRange('A:Z').getValues().filter(String); //A-Z列の値を全て取得
let tarValuesFilterData = [];
//配列の中で空欄のものを除外して、lengthを算出・最終行取得
for (let i = 0; i < tarValues.length; i++) {
if (tarValues[i].join("") != "") { //空文字列で行内のセルの値を結合
tarValuesFilterData.push(tarValues[i]);
}
}
return tarValuesFilterData.length; //空白の要素を除いた長さを取得
}
//最終列を取得する関数
function func_getTarLastColumn(sheet) {
// 最初の10行が空欄以外の数をカウント
let tarArr = sheet.getRange("1:10").getValues().filter(String);
let tarArrFilterData = [];
//配列の中で空欄のものを除外して、lengthを算出・最終行取得
for (let k = 0; k < tarArr[0].length; k++) {
let checkStr = "";
for (let i = 0; i < tarArr.length; i++) {
checkStr = checkStr + tarArr[i][k];
}
if (checkStr !=""){
tarArrFilterData.push(tarArr[0][k]);
}
}
return tarArrFilterData.length; //空白の要素を除いた長さを取得
}
// シートを配列に格納する関数
function func_shToArr(tarSheet, columnsCount) {
if (columnsCount == undefined){
columnsCount = func_getTarLastColumn(tarSheet);
}
retArr = tarSheet.getRange(1, 1, func_getTarLastRow(tarSheet), columnsCount).getDisplayValues();
return retArr;
}
// 配列をシートに格納する関数
function arrToSh(tarArr, tarSheet, tarRow, tarColumn) {
tarSheet.getRange(tarRow, tarColumn, tarArr.length, tarArr[0].length).setValues(tarArr);
}
実行結果について
上記のコードを実行すると以下画像のようにA~L列の内容に応じてM~T列に結果が表示されます。

コメント