RPAのFlaUIベースのWeChatで特定の人物にメッセージを送信

RPAのFlaUIベースのWeChatで特定の人物にメッセージを送信

WeChatの一斉送信機能の実現

最終更新 2022/05/25 0:24
蓝创精英团队
読了目安 5 分
カテゴリ
.NET
タグ
.NET C# RPA

本文はネットユーザー藍創精鋭チームより寄稿されました。転載・共有は自由です

原文著者:藍創精鋭チーム

原文リンク:https://kesshei.blog.csdn.net/article/details/124955177


目的

ずっとWeChatの一斉送信機能を実現したいと思っていましたが、実現できていませんでした。理由の一つは法律違反を恐れていたからです。ある会社がWeChatのインターフェースを解析したことで何やかんやあって訴えられ、多額の罰金を科された記憶があります。

そこで考えました。もしRPA技術をベースにすれば、WeChatに一切影響を与えません。なぜなら、単に自分のPC操作をシミュレートしているだけであり、WeChat社も私の操作が違法であると認識できないからです。

したがって、このアプローチはおそらく安全な技術に基づくものになります。

そこで試してみました。同時にネット上の資料も参考にし、いくつかのヒントを得ました。


一、FlaUIとは?

FlaUIは、MicrosoftのUIAutomation技術に基づいており、Windows Vistaから導入された全く新しいUI自動化テスト技術です。略してUIAと呼ばれます。最新のWindows SDKでは、UIAはMSAAなど他のUI自動化技術をサポートするコンポーネントと共にリリースされており、Windows Automation APIと呼ばれています。

UIAは、UI自動化のための全く新しいインターフェースとパターンを定義しています。UI要素を走査し条件付きで検索するTreeWalker/FindAll、UI要素の属性(Name、ID、Type、ClassName、Location、Visibilityなど)を読み書きするUIA Property、UI要素の動作(Select、Expand、Resize、Check、Valueなど)を定義するUIA Pattern、そしてテストプログラムが新しいウィンドウのオープンなど特定のイベント発生時に通知を受け取れるUIA Eventインターフェースなどです。

現在、FlaUIが使用する技術はUIA2とUIA3の2つです。 ここでは主にUIA3を使用します。

二、使用手順

1. NuGetパッケージの導入

Install-Package FlaUI.UIA3 -Version 3.2.0

2. 特定の相手にメッセージを送信する簡単な実装

コード(例):

Process[] processes = Process.GetProcessesByName("WeChat");
if (processes.Count() != 1)
{
    Console.WriteLine("WeChatが起動していないか、複数のWeChatが起動しています");
}
else
{
    //1. WeChatプロセスにアタッチ
    using (var app = Application.Attach(processes.First().Id))
    {
        using (var automation = new UIA3Automation())
        {
            //2. メインウィンドウを取得
            var mainWindow = app.GetMainWindow(automation);
            Console.WriteLine("メインウィンドウを取得しました");
            //3. アドレス帳に切り替え
            var elements = mainWindow.FindAll(FlaUI.Core.Definitions.TreeScope.Subtree, TrueCondition.Default);
            var addressBook = mainWindow.FindFirstDescendant(cf => cf.ByName("アドレス帳"));
            addressBook.DrawHighlight(System.Drawing.Color.Red);
            var path = Debug.GetXPathToElement(addressBook);
            Console.WriteLine("アドレス帳をクリック");
            addressBook.Click();

            //4. 検索
            string target = "ファイル転送アシスタント";
            var searchTextBox = mainWindow.FindFirstDescendant(cf => cf.ByName("検索")).AsTextBox();
            searchTextBox.Click();
            Keyboard.Type(target);
            Keyboard.Type(VirtualKeyShort.RETURN);
            Console.WriteLine("対象を検索中");

            //5. ダイアログに切り替え
            Thread.Sleep(500);

            var searchList = mainWindow.FindFirstDescendant(cf => cf.ByName("検索結果"));
            if (searchList != null)
            {
                var searchItem = searchList.FindAllDescendants().FirstOrDefault(cf => cf.Name == target && cf.ControlType == FlaUI.Core.Definitions.ControlType.ListItem);
                searchItem?.DrawHighlight(System.Drawing.Color.Red);
                searchItem?.AsListBoxItem().Click();
            }
            else
            {
                Console.WriteLine("検索結果が見つかりませんでした");
            }
            Thread.Sleep(500);
            //6. テキストを入力
            string sendMsg = "これは私のWeChatからの入力情報です:" + DateTime.Now.ToString();
            var msgInput = mainWindow.FindFirstDescendant(cf => cf.ByName("入力")).AsTextBox();
            msgInput?.Click();
            System.Windows.Forms.Clipboard.SetText(sendMsg);
            Keyboard.TypeSimultaneously(new[] { VirtualKeyShort.CONTROL, VirtualKeyShort.KEY_V });
            var sendBtn = mainWindow.FindFirstDescendant(cf => cf.ByName("sendBtn"));
            sendBtn?.DrawHighlight(System.Drawing.Color.Red);
            sendBtn?.Click();
        }
    }
}

コードにはコメントがあり理解しやすいです。

指定した人を検索し、指定した情報を送信するだけです。完了です。

図示効果は以下の通り:


3. 会話リストを取得して一括送信する実装

コード(例):

Process[] processes = Process.GetProcessesByName("WeChat");
if (processes.Count() != 1)
{
    Console.WriteLine("WeChatが起動していないか、複数のWeChatが起動しています");
}
else
{
    //1. WeChatプロセスにアタッチ
    using (var app = Application.Attach(processes.First().Id))
    {
        using (var automation = new UIA3Automation())
        {
            //2. メインウィンドウを取得
            var mainWindow = app.GetMainWindow(automation);
            Console.WriteLine("メインウィンドウを取得しました");
            //3. チャット一覧に切り替え
            var elements = mainWindow.FindAll(TreeScope.Subtree, TrueCondition.Default);
            var addressBook = mainWindow.FindFirstDescendant(cf => cf.ByName("チャット"));
            addressBook.DrawHighlight(System.Drawing.Color.Red);
            var path = Debug.GetXPathToElement(addressBook);
            addressBook.Click();
            Console.WriteLine("チャットに切り替えました");
            Thread.Sleep(2000);
            //4. チャットリストを取得
            //先頭の6件のみ送信
            var count = 0;
            var searchTextBox = mainWindow.FindFirstDescendant(cf => cf.ByName("セッション")).AsListBoxItem();
            while (searchTextBox != null)
            {
                var list = searchTextBox.FindAllChildren();
                foreach (var item in list)
                {
                    count++;
                    var name = item.Name;
                    item.Click();
                    var type = item.ControlType;
                    item.DrawHighlight(System.Drawing.Color.Red);
                    var MsgSend = mainWindow.FindFirstDescendant(cf => cf.ByName("入力")).AsTextBox();
                    var MsgSendButton = mainWindow.FindFirstDescendant(cf => cf.ByName("sendBtn"));
                    if (MsgSend != null && MsgSendButton != null)
                    {
                        MsgSend.Click();
                        System.Windows.Forms.Clipboard.SetText($"一斉送信メッセージです。無視してください:{DateTime.Now}");
                        Keyboard.TypeSimultaneously(new[] { VirtualKeyShort.CONTROL, VirtualKeyShort.KEY_V });
                        MsgSendButton.Click();
                        Console.WriteLine($"送信しました:{name}");
                        Thread.Sleep(500);
                    }
                    if (count == 6)
                    {
                        break;
                    }
                }
                if (count == 6)
                {
                    break;
                }
                for (int i = 0; i < list.Length; i++)
                {
                    searchTextBox.Focus();
                    Keyboard.Press(VirtualKeyShort.DOWN);
                    Thread.Sleep(100);
                }
                searchTextBox = mainWindow.FindFirstDescendant(cf => cf.ByName("セッション")).AsListBoxItem();
                Thread.Sleep(2000);
            }
        }
    }
}

このコードは主に先頭6人に一斉送信します。セッションに送信ボタンがない場合は送信しないようにし、影響を最小限に抑えています。

図示効果は以下の通り:

何度か録画しましたが、最後には誰かに削除されてしまいました。気まずいです。

4. FlaUIでページ情報を取得する方法

FlaUInspectツールを開きます。

FlaUInspect

以下のようにXPathアドレスを確認できます。

FlaUInspectプロジェクトはWPFプロジェクトです。詳細を調べたい方はソースコードを確認し、デバッグしてみてください。

ここでは主に以下の2つの方法で必要な内容を取得できます。

1つ目は以下のように、同じページ内でユニークな名前を使って取得する方法です。

var addressBook = mainWindow.FindFirstDescendant(cf => cf.ByName("チャット"));

2つ目は以下のように、図の2番のXPathアドレスを使って目的のコントロールを見つける方法です。

var infoData = automationElement.FindAllByXPath("/Pane/Pane[1]");

まとめ

全体的に、この技術は非常に便利ですが、QQのように自己描画技術を使用しているものや、QT、Javaベースのアプリケーションでは実現できない可能性があります。対象となるのはMicrosoftの技術製品、WinFormsやWPFなどです。

大まかに言えば、使用時の難易度を下げてくれています。

例えば、このWeChatメッセージ送信機能があれば、自分で拡張できます。指定した人に送る、一斉送信、タイマー送信、タグ送信など、実現すれば個人にとっては非常に役立ちます。


2022年5月30日 改訂

他のユーザーが実行できない場合の解決策

以下のようなエラーが発生する場合。

https://github.com/FlaUI/FlaUI からソースコードをダウンロードし、nuget経由ではなく直接参照することで解決できます。

原因については深く調査していません。

さらに探索

関連読書

その他の記事
同じカテゴリ / 同じタグ 2026/04/22

各OSバージョンの.NETサポート状況(250707更新)

仮想マシンとテストマシンを使用して、各OSバージョンの.NETサポート状況を確認します。OSインストール後、対応するランタイムをインストールし、Stardustエージェントを実行できることを確認します(合格条件)。

続きを読む