難しいテキスト入力をSendKeysで代替する方法【C#, chrome拡張機能】

機能概要

・フォルダAに「AUTO」で始まるファイルを放り込むと自動でファイルを開きます。

・ファイルの中身が「CLICK,100,200」であれば(100, 200)の座標をクリックします。

・ファイルの中身が「INPUT_TEXT,”田中”」であれば田中とキーストロークを送ります。

使用例

CLICK,100,100
INPUT_TEXT,"田中"
CLICK,200,200
INPUT_TEXT,"吉田"
CLICK,300,300
INPUT_TEXT,"沢村"

・3回に分けてクリックしたあと名前入力を行います。

なんでこんなものをつくったんですか?

私たちが普段当たり前だと思っているスマートフォンやタブレットは刑務所では使うことができませんね? つまりはそういうことです。

それはさておき、Salesforce含め昨今のシステムはとにかくスクレイピングしにくい作りになっています。

テキスト項目はvalueを書き換えるだけでは反映されず、プルダウンの項目はselectedIndexを切り替えるだけでは反映されず…

そういったわけでブラウザページのDOMをこねくり回すよりも、原始的にWinAPIを呼び出したほうが早いわけです。はい。

付け加えたい処理

この機能は常駐を前提としているので、タスクバーに表示させないようにしたいですね。

間違って閉じてしまう可能性もありますので。

ソースコード

using System;
using System.IO;

// Sleep
using System.Threading;
// DLLImport
using System.Runtime.InteropServices;
// SendKeys
using System.Windows.Forms;

// C# コンパイラ パス
// C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe
public class AutoOperation {

    // Win API
    public static class NativeMethods {
        [DllImport("USER32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void SetCursorPos(int X, int Y);

        [DllImport("USER32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
    }

    // メイン
    public static void Main() {

        while(true) { 
            string file_path;
            file_path = GetTargetFile();

            // 処理ファイルがある場合
            if (file_path != "") {
                // ファイル読み込み
                string text = File.ReadAllText(file_path);
                string[] del = {"\r\n"};
                string[] commands = text.Split(del, StringSplitOptions.None);
                // 各コマンドを実行する。
                foreach (string command in commands) {
                    string[] values = command.Split(',');
                    switch (values[0]) {
                        case "CLICK":
                            Console.WriteLine("CLICKがよばれました");
                            int x = int.Parse(values[1]);
                            int y = int.Parse(values[2]);
                            LeftClick(x, y);
                            break;
                        case "INPUT_TEXT":
                            Console.WriteLine("INPUT_TEXTがよばれました");
                            SendMessage(values[1]);
                            break;
                    }
                    Thread.Sleep(50);
                }
                BackupFile(file_path);
            }
            Thread.Sleep(1000);
        }
    }

    // 処理対象のファイル名を取得する。
    // ファイルがない場合は処理をしない。
    private static string GetTargetFile() {
        const string path = @"C:★フォルダA★";
        const string pattern = "AUTO*";
        string[] file_list = Directory.GetFiles(path, pattern);
        if (file_list.Length > 0) {
            Array.Sort(file_list);
            return file_list[0];
        } else {
            return "";
        }
    }

    // 処理済みのファイルを退避する。
    private static void BackupFile(string file_path) {
        const string dest = @"C:★\backup";
        string file_name = Path.GetFileName(file_path);
        File.Move(file_path, Path.Combine(dest,file_name));
    }

    // マウスクリック
    private static void LeftClick(int x, int y) {
        const int MOUSEEVENT_LEFT_DOWN = 0x2;
        const int MOUSEEVENT_LEFTUP = 0x4;
        NativeMethods.SetCursorPos(x, y);   
        NativeMethods.mouse_event(MOUSEEVENT_LEFT_DOWN, 0, 0, 0, 0); 
        NativeMethods.mouse_event(MOUSEEVENT_LEFTUP, 0, 0, 0, 0);
    }

    // メッセージ送信
    private static void SendMessage(string message){
        SendKeys.SendWait(message);
    }
}

ソースコード(画像)

 

コメントを残す