Chatwork【メッセージ取得】
Chatwork画面からメッセージを取得します。Excelシートを検索して、すでに出力済のメッセージIDを求め、それより大きいIDのメッセージを順番に取得します。
Chatwork画面
メッセージ欄
- メッセージは、「メンバー名」「メッセージ本文」、「日時」、「添付ファイル」から構成されています。
- 各メッセージ欄は<div>要素で、id属性に一意のメッセージidを持っています。
- 同一人物が連続して発言した場合は、「メンバー名」は省略されています。「日時」も時刻のみとなっています。
- 添付ファイルの「ファイル名」をクリックすると、ファイルをダウンロードすることができます。
項目 | XPath |
---|---|
メンバー名 | //div[@id="_messageId9999999999999999999" ]//button/p |
日時 | //div[@id="_messageId9999999999999999999" ]//div[@class="sc-dovKpQ dnUtTf _timeStamp"] |
(改良後) //div[@id="_messageId9999999999999999999 " ]//div[contains(@class,"_timeStamp")]div[contains(@class,"_timeStamp")] は、【class属性に"_timeStamp"を含む<div>要素】を表します。 | |
メッセージ | //div[@id="_messageId9999999999999999999" ]//pre |
ファイルのダウンロード | //div[@id="_messageId9999999999999999999" ]//a[1] |
hiddenメッセージ
メッセージの中には、非表示のものがあります。(メッセージを削除した場合などが該当するようです)
class属性に “hiddenMessage"が指定されているので、取得対象外とします。
Excel最終行の取得
メッセージを出力するにあたり、Excelシートを検索して、すでに出力済のメッセージIDと、シートの行番号を取得します。
Excelシート(イメージ)
A列に値がある間、IDと現在のExcel行を取得し、変数に保存しておきます。
操作シナリオ
- 変数 ^row はExcelの行数を表し、変数 ^id には最新の出力済メッセージIDを格納します。
- ^rowはシートの2行目から始め、A列に値がある間、行を進めていきます。
- ループ終了時、^idにはA列最終行の値(取得済のメッセージID)が、まだ1件も取得していない場合は、初期値 -1が格納されます。
出力対象メッセージの特定
Chatwork画面を検索し、まだExcelシートに出力されていないメッセージを特定します。具体的には、すでにExcel出力済メッセージID(変数^id)よりも、大きいメッセージIDが対象です。
最新(画面最下部)のメッセージから、上に1つずつ前のメッセージを順番にたどって、メッセージIDが変数^idより大きい間、処理を繰り返します。
最新メッセージ取得
最新(画面最下部)のメッセージを取得します。
- No1:id属性に"_messageId"を含むdiv要素のうち、最後の要素のid属性(最新メッセージのid属性)を取得します。
“[last()]"は検索された要素のうち、最後の要素を返します。 - No2:取得したid属性を文字変数 ^str_midに代入します。
- id属性のフォーマットは “_messageId99…99″なので、No3のREPLACEで文字部分を削除し、No4のCONVERT-NUMで数値に変換し、 メッセージIDの数字部分を^num_midに格納します。
ループ処理
最新メッセージを起点に、1件ずつ前のメッセージを取得します。
ループ条件
WHILE文でメッセージIDが、変数^id(Excel出力済のメッセージID)より大きい間、処理を繰り返します。
現在のメッセージID(数値)が ^num_mid に保存されているので、^idと比較します。
現在のメッセージID ^num_midが ^idよりも大きい間、WHILE内の処理を繰り返します。
一つ前のメッセージを取得
現在のメッセージから、一つ前のメッセージを取得するには、自分より前の兄弟要素を取得する preceding-sibling::を使用します。文字変数^str_idに現在のメッセージのid属性が保存されているので、
画面要素 | XPath |
---|---|
現在のメッセージ | //div[@id="^str_mid"] |
それ以前のメッセージ (id属性に"_messageId"を含むdiv要素) | //div[@id="^str_mid"]/preceding-sibling::div[contains(@id,"_messageId")] |
その中で、直前のもの | //div[@id="^str_mid"]/preceding-sibling::div[contains(@id,"_messageId")][1] ※自分より直前のものは [last()] ではなく、[1] に注意が必要です。 |
表示範囲外のスクロール処理
画面上部に向けて、どんどん過去のメッセージを検索していくと、表示範囲外でメッセージが存在しなくなります。手動操作と同様に、画面を上にスクロールして過去のメッセージを描画させます。
- ^str_idには、現在のメッセージのid属性が保存されています。
- No2:^str_idが、現在の画面に表示されている最も古いメッセージ(id属性に"_messageId"を持つ<div>要素の1番目と同じ)であれば、先頭メッセージなので、No3:PageUpキーを押して上にスクロールします。
- No4:PageUpキーを押したにも関わらず、先頭メッセージに変化がない場合は、それより古いメッセージは存在しないので、No5.BREAKでループを脱出します。この場合、全メッセージがExcel出力対象となります。
そうでない場合は、新たに過去メッセージが表示されたので、検索を続けます。
出力対象メッセージIDを取得するWHILE文
まとめると以下になります。メッセージIDが^str_midより大きいメッセージがExcel出力対象となります。
ループの継続条件が、Excel出力済メッセージより大きいメッセージIDで、ループ内で1つ前のメッセージIDを ^str_midに代入しますので、ループ終了時には ^str_midにはExcel出力済の最後のメッセージIDが格納されています。
Excel側の出力済メッセージが0件の場合
Excelに1件もメッセージが出力されていない場合は、^idには -1が入っているので、WHILE文の条件は 【^num_mid > -1】となり、ループ終了時の ^str_midは、グループチャット全体で一番最初のメッセージが入ります。
メッセージの取得
最初の1件
上記より、Excel出力済メッセージが0件の場合は、^str_midのメッセージが取得対象です。
一方、すでにExcelシートに何らかのメッセージが出力されている場合は、^str_midの次のメッセージから出力します。
0件とそうでない場合で、ずれが生じているので、^idが -1以外の場合は1件先に進めます(^str_midに次のメッセージIDを代入)
そうすることで、すでにExcelにメッセージが入っている場合も^str_mid以降のメッセージが出力対象となります。
次のメッセージを取得するには、自分より後の兄弟要素を取得する following-sibling::を使用します。
画面要素 | XPath |
---|---|
現在のメッセージ | //div[@id="^str_mid"] |
それ以降のメッセージ (id属性に"_messageId"を含むdiv要素) | //div[@id="^str_mid"]/following-sibling::div[contains(@id,"_messageId")] |
その中で、最初(直後)のもの | //div[@id="^str_mid"]/following-sibling::div[contains(@id,"_messageId")][1] |
^idが -1と異なる場合、次のメッセージを検索して、メッセージIDを ^str_midに代入します。
次のメッセージが存在しない(Excel出力済のメッセージより新しいメッセージがない)場合は、すでに全メッセージが出力済なので、RETURNにてシナリオを終了します。
メッセージの出力
上記対応で、Excel出力済メッセージが0件と1件以上のいずれの場合においても、^str_midに出力対象の1件目のメッセージIDが格納されています。1件目のメッセージを出力します。
出力処理はサブルーチンにして、別タブに持たせます。
ループ処理
メッセージが存在する間、Excelに出力し、現在のメッセージID(^str_mid)を更新します。
- No4:出力処理のサブルーチンには、メッセージID(^str_mid)と現在のExcel行(^row)を渡します。出力処理側でExcel行が進むと^rowが加算され、戻り値として返ってきます。