前回に引き続き、Winautomationで作成したロボットについて紹介していきます。
前回は乗換案内から経路の所要時間や片道料金などを取得しました。
今回は取得した文字列から不要な文字を削除していきます。
取得した文字の整形 (固定の文字列の消去)
まずは取得情報整理のFunctionを用意し、Main Functionで結果取得の次にくるようにします。
文字を整形していく前に、[Extract Data From Web Page]で取得したデータへの参照方法について説明します。
今回は「%DataFromWebPage%」という名前のDataTable型の変数に取得した値が入っています。
DataTable型の変数は2次元配列の変数です。
変数の型は[Extract Data From Web Page]での取得設定によって変わるので、1次元配列であったり配列でない場合もあります。
Winautomationで2次元配列内の特定の場所を指定する方法ですが、
%変数名[x][y]%
のように書きます。(x、yはインデックスの数字で0はじまり)
今回の場合だと下の画像のようになります。
「%DataFromWebPage%」の中で片道料金に該当するものは以下3つです。
%DataFromWebPage[0][1]%
%DataFromWebPage[1][1]%
%DataFromWebPage[2][1]%
片道料金を参照する際は「%DataFromWebPage[n][1]%」のnを0~2に変化させると良いですね。
というわけで、新しく作成した取得情報整理のFunctionにループアクションを置きます。
LoopIndexが0~2の間で繰り返すように設定します。
設定したループの中で、不要な文字を削除するアクションを置いていきます。
アクションは[Replace Text]を使用します。
取得した片道料金を参照する「 %DataFromWebPage[LoopIndex][1]%」としました。 [Text to Find]は[Text to Parse]内で置換する文字を設定します。
削除したい文字である「[priic]IC優先:」を設定しました。 [Replace With]:は何に置換するかを設定します。
今回は削除したいのでブランクとしますが、ブランクのままだとエラーになるため「%””%」と設定します。
Winautomationの文字列削除でよく使うテクニックです。
設定したらデバッグして値を確認します。
問題なく取得できていますね。
駅・経路の取得
次は各ルートの駅と経路を取得していきます。
Yahoo!路線情報の乗換案内ではHTMLの構造が少し複雑です。
HTMLを見ると、[station]のクラスが[fareSection]の中にはいっている場合があります。
実際のブラウザの画面と照らし合わせるとこんな感じです。
これだと同じstationでも階層が違うので、[Extract Data From Web Page]でDataTable型にして一括で取得するのは困難です。
そこで、今回は階層によらずclassが[station]のdivタグから駅名を、classが[access]のdivタグから経路を一括で取得してみます。
結果取得のFunctionで、[Extract Data from Web Page]を追加します。
リスト(1次元配列)で取得するので、格納する配列名は%StationList%としました。
[Modify Web Data to Extract]から取得するデータを設定します。
アクションをコピーした場合は、コピー元の設定が残っているのでリセットしてから詳細設定を開きます。
駅の取得はこのように設定しました。
class名に「station」を含むdivタグごとに、駅名にあたる部分を取得します。
class名が「station」だけとは限らなかったので、「station」を含むとしています。
Previewで確認すると、駅の一覧が取得できていますね。ただし、どのルートの駅かは分からなくなってしまっているのでどのルートか判定する処理が後で必要になります。
続いて経路も同様に取得していきます。
上の画像のように設定しました。
余分な文字列はありますが、経路が取得できていますね。
取得した文字の整形 (パターンマッチングを使用した文字列の消去)
取得した経路の余分な文字を削除していきます。
片道料金の時とは違い、削除する文字が固定ではありませんので、パターンマッチング(正規表現)を利用します。
取得情報整理のFunctionに[Loop]のアクションを置きます。
1次元配列の場合は「%変数名.Count%」で要素数を取得できます。
インデックスは0始まりなので「%変数名.Count-1%」で要素数分の回数ループさせることができます。
作成したループ内に、[Replace Text]を置きます。
正規表現を使用するので[Use Regular Expressions for find]にチェックを入れます。
今回のパターンでは”[”の文字から”]”の文字までを対象としています。
正規表現は検索すると色々でてくるので、わからない方は調べてみましょう。
設定したらデバッグして結果を確認します。
不要な部分を消すことができました。
駅リスト、経路リストからどのルートか判別させる
駅リスト、経路リストがどのルートか判別する方法ですが、
各ルートの出発駅と到着駅と比較し、上から順にルート1の出発駅から到着駅までをルート1の駅・経路、
ルート2の出発駅から到着駅までをルート2の駅・経路、残りをルート3の駅・経路とします。
(もっとスマートな方法があるかなと思いますが、思いついたのでとりあえずこれでやってみます。)
ということで、各ルートの出発駅と到着駅を取得します。
所要時間や片道料金を取得していたアクションのプロパティを開き、[Modify Web Data to Extract]から設定を変更します。
出発駅と到着駅を取得するSelectorをそれぞれ追加します。
追加は[Specify Additional CSS Selector]からできます。
以下のように設定しました。
CSS Selector 6(出発駅):div.routeDetail > div.station:first-of-type > dl > dt > a
CSS Selector 7(到着駅):div.routeDetail > div.station:last-of-type > dl > dt > a
「div.station:first-of-type」は、親要素の中で、classが「station」である最初のdivタグを意味しています。
親要素は「div.routeDetail」で、これは各ルートごとのタグです。
つまり、ルートごとの最初の駅を取得することができます。
どうように「div.station:last-of-type」で最後の駅を取得しています。
取得した結果は以下の画像のようになります。
すべてのルートで出発駅と到着駅は一緒になるはずですが、念のため全てのルートで取得しました。
ルートを判別する前に、
各ルートごとの駅を格納するリストを用意しておきます。
変数設定のFuction内に[Create New List]のアクションを置きます。
リストの変数名は%StationListRoute1%とし、ルート1の駅名を格納する変数としました。
同様にして駅リスト、経路リストをそれぞれ3つ用意しました。
では駅リストをループし、ルートごとに分割していきます。
情報取得整理のFunctionに%StationList%をループするLoopアクションを置きます。
ループ中にどのルートの処理をしているかを表す変数を用意します。
初期値は1とし、次のルートに映る際に+1 します。
ループの中で、1ルート目の場合の処理を作成します。
%Currentroute%が1のときに処理を通るようにIfアクションを挿入します。
リストへの要素追加には[Add Item to List]を使います。
Ifアクション内に[Add Item to List]を挿入し、%StationListRoute1%のリストに値が追加されるように設定します。
%StationList%の値と、ルート1の到着駅が一致した場合には、%CurrentRoute%を+1します。
[Add Item to List]の後にIfアクションを挿入して、条件を設定します。
到着駅は%DataFromWebPage%の7列目なので、1を引いた6がインデックスとなります。
また行のインデックスについてはCurrentRouteから1を引いたものと同じであるため利用しています。
作成したIfアクション内にCurrentRouteを+1するアクションを挿入します。
[Increase Variable]を使用します。
同様にルート2とルート3の処理を[Else If]アクションを使って作成します。
作成できたらデバッグしてリストの値を確認します。
正しく分割できました。
次は経路の分割ですが、ルートごとの経路の数は駅数によってわかります。
経路は駅と駅に挟まれていて、経路数は必ず駅数より1少ない数になります。
そのため、先ほど取得した各ルートの駅リストの要素数から1を引いた回数分を各ルートの経路リストに追加していきます。
まずは経路リストをループさせるLoopアクションを置きます。
ループインデックスが、ルート1の駅リストの要素数-1より小さい場合の条件分岐をIfアクションで作成します。
条件を満たす場合にはルート1の経路リストに値を追加します。
ルート2の場合、ルート3の場合も作成します。
ルート2のElse Ifアクションでは条件式の最後に-2していますが、
これは「ルート1の経路数+ルート2の経路数」が「ルート1の駅数+ ルート2の駅数」よりも2少なくなるためです。
また、ルート1、ルート2の条件にあてはまらないものは全てルート3となるため、残りはルート3となるようにしました。
設定したらデバッグして変数の値を確認します。
問題なく取得することができました。
今回はここまでです。
次回はアウトプットへの値の書込処理などを作成していきます。
はじめまして、Shintaroです。 Winautomationでプロセスを作成するのが好きなエンジニアです。 今回はWinautomationでYahoo!路線情報の乗換案内を利用した定期経路調査ロボット(プロセス)を作ったので、[…]
前回に引き続き、Winautomationで作成したロボットについて紹介していきます。 前回は取得した情報を整形し、各ルートごとに分割しました。 今回は取得した情報をアウトプットに書き込んでいきます。 アウトプットファイルの用意 […]