Chatwork【メッセージ取得】

2023年4月6日

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"が指定されているので、取得対象外とします。

hidden項目

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と比較します。

WHILE文

現在のメッセージ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出力対象となります。

出力対象メッセージIDを取得するWHILE文

ループの継続条件が、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)を更新します。

WHILE文
  • No4:出力処理のサブルーチンには、メッセージID(^str_mid)と現在のExcel行(^row)を渡します。出力処理側でExcel行が進むと^rowが加算され、戻り値として返ってきます。

完成シナリオ