PerlでWebブラウザ自動操作ロボット作成方法のまとめ - 実用的なRPAをPerlで作ってみよう

PerlでWebブラウザ自動操作ロボット作成方法をここにまとめていきます。Windowsのユーザーが対象です。

Strawberry PerlをWindowsにインストールする

Webブラウザ自動操作ロボットを作成するためには、Windows用にセッティングされたPerlが必要です。

Active PerlとStrawberry Perlという選択枝がありますが、ここでは、Strawberry Perlを使います。

Strawberry Perlには、Webブラウザ自動操作ロボットを作成するための、GUI操作のモジュールがインストールされています。マウス位置指定、クリック、キーボード操作、クリップボード操作などです。

Webブラウザ自動操作ロボット作成に使うPerlモジュール

Webブラウザ自動操作ロボット作成に使うPerlモジュールは、以下が中心です。

ウィンドウ操作

ウィンドウ操作について解説します。

Win32::GuiTest

Windowsで、ウィンドウの取得、マウス位置指定、クリック、キーボード操作を行うにはWin32::GuiTestを使い、必要な関数を読み込みます。

use Win32::GuiTest (
  'UnicodeSemantics',
  'GetDesktopWindow',
  'GetParent',
  'GetWindowText',
  'GetClassName',
  'GetChildWindows',
  'GetChildDepth',
  'MouseMoveAbsPix',
  'SendLButtonUp',
  'SendLButtonDown',
  'SendKeys',
);

以下のようにWin32::GuiTestを読み込むと、関数がすべてインポートされます。プログラムの保守性を上げたい場合は、上の記述、とりあえず楽に書きたい場合は、下の記述が使えます。

# 関数をすべてインポート
use Win32::GuiTest;

ユニコードセマンティクスを有効にする

PerlはPerl 5.8以降で、ユニコード対応されていますので、Win32::GuiTestの方も、ユニコードに対応したセマンティクスが使えるようにします。Perlのソースコードは、UTF-8で記述し「use utf8;」を記述していることが前提です。

# ユニコードセマンティクスを有効にする
UnicodeSemantics(1);

デスクトップウィンドウの取得

デスクトップウィンドウを取得するには、GetDesktopWindow関数を使用します。デスクトップウィンドウとは、デスクトップ全体を示すウィンドウのことです。

# デスクトップウィンドウの取得
my $desktop_win = GetDesktopWindow();

子ウィンドウの一覧を取得

Webブラウザ自動操作を行うためには、ブラウザのウィンドウを取得する必要がありますが、そのためには、まずデスクトップウィンドウの下で管理されている子ウィンドウの一覧を取得する必要があります。子ウィンドウの一覧を取得するには、GetChildWindowsを使用します。

# 子ウィンドウの一覧を取得
my @windows = GetChildWindows($desktop_win);

# 子ウィンドウをループ
for my $window (@windows) {
  
}

ウィンドウのテキストを取得

ウィンドウのテキストを取得するにはGetWindowText関数を使います。

# ウィンドウのテキストを取得
my $win_text = GetWindowText($win);

ウィンドウのテキストは、ブラウザの種類によって、異なる可能性があります。Google Chromeで確認したものでは、以下のように「ウィンドウのタイトル - アプリケーション名」になっていました。

Perlクラブ - Google Chrome

対象ウィンドウの取得

Webブラウザ自動操作ロボットを作る場合は、子ウィンドウの一覧から、対象のウィンドウを取得する必要があります。対象のウィンドウを取得するサンプルを記述します。確実に、対象のWebブラウザの対象のページが、一つ立ち上がっていることをチェックします。

# 対象のウィンドウを取得(Perlクラブ - Google Chrome)
my $win;
{
  my $desktop_win = GetDesktopWindow();
  die "Oops!" if GetParent($desktop_win) != 0;

  my @browser_wins;
  my $browser_name = 'Chrome';
  for my $win (GetChildWindows($desktop_win)) {

    # ウィンドウの名前
    my $win_text    = GetWindowText($win);

    # ブラウザ名
    if ($win_text =~ /\b$browser_name\b/) {
      if ($win_text =~ /Perlクラブ/) {
        push @browser_wins, $win;
      }
    }
  }

  my $browser_wins_count = @browser_wins;
  unless ($browser_wins_count == 1) {
    die "Must be open one window");
  }
  $win = $browser_wins[0];
}

マウス操作

マウス操作ついて説明します。

マウスを移動させる

マウスを移動させるにはMouseMoveAbsPix関数を使用します。原点は、デスクトップウィンドウの左上になります。

# マウスを移動させる
MouseMoveAbsPix($x, $y);

対象ウィンドウの左上の位置を取得する

ブラウザを操作する場合は、ブラウザのウィンドウの左上の位置を知りたいですね。GetWindowRect関数を使うと、対象のウィンドウの原点の位置を取得できます。

# 対象ウィンドウの左上の位置を取得する
my ($win_left, $win_top, $win_right, $win_bottom) = Win32::GuiTest::GetWindowRect($win);

対象ウィンドウの原点から、左100px、下200pxの位置にマウスを移動させるには次のようにします。

# 対象ウィンドウの原点から、左100px、下200pxの位置にマウスを移動
my $left = 100;
my $top = 200;
MouseMoveAbsPix($win_left + $left, $win_top + $top);

マウスの左ボタンを押す

マウスの左ボタンを押すにはSendLButtonDown関数を使用します。

# マウスの左ボタンを押す
SendLButtonDown();

マウスの左ボタンを離す

マウスの左ボタンを離すにはSendLButtonUp関数を使用します。

# マウスの左ボタンを押す
SendLButtonDown();

マウスを左クリックする

マウスを左クリックするには、マウスの左ボタンを押して、離します。

# マウスを左クリックする
SendLButtonDown();
SendLButtonUp();

マウスの左ボタンをダブルクリックする

マウスの左ボタンをダブルクリックするには、マウスの左ボタンを押して、離してを2回繰り返します。

# ダブルクリック
SendLButtonDown();
SendLButtonUp();
SendLButtonDown();
SendLButtonUp();

その他のマウスイベント

その他のマウスイベントです。真ん中のボタンを押す、離す、右ボタンを押す、離すです。

# 真ん中のボタンを押す
SendMButtonDown()

# 真ん中のボタンを離す
SendMButtonUp()

# 右ボタンを押す
SendRButtonDown()

# 右ボタンを離す
SendRButtonUp()

キーボード入力

キーボード入力ついて説明します。

キーボード入力の基本

キーボード入力するにはSendKeys関数を使用します。複数の文字を指定した場合は、デフォルトで50m間隔でキーボード入力が行われます。

# 「a」とキーボード入力
SendKeys('a');

# 「abcde」とキーボード入力
SendKeys('abcde');

同じ文字を、繰り返し実行する場合は繰り返し演算子「x」を使うと簡単です。

「a」を5回入力
SendKeys('a' x 5);

アルファベット以外のキー

上下左右、タブ、ファンクションキー、Enterキーなどは、アルファベット以外のキーです。「{キー名}」という記法を使います。

SendKeys('{DOWN}');
SendKeys('{UP}');
SendKeys('{ENTER}');
SendKeys('{TAB}');
SendKeys('{F12}');

すべてのアルファベット以外のキー名です。Win32::GuiTestのドキュメントから引用しました。

{BACKSPACE}   Backspace
{BS}          Backspace
{BKSP}        Backspace
{BREAK}       Break
{CAPS}        Caps Lock
{DELETE}      Delete
{DOWN}        Down arrow
{END}         End
{ENTER}       Enter (same as ~)
{ESCAPE}      Escape
{HELP}        Help key
{HOME}        Home
{INSERT}      Insert
{LEFT}        Left arrow
{NUMLOCK}     Num lock
{PGDN}        Page down
{PGUP}        Page up
{PRTSCR}      Print screen
{RIGHT}       Right arrow
{SCROLL}      Scroll lock
{TAB}         Tab
{UP}          Up arrow
{PAUSE}       Pause
{F1}          Function Key 1
...           ...
{F24}         Function Key 24
{SPC}         Spacebar
{SPACE}       Spacebar
{SPACEBAR}    Spacebar
{LWI}         Left Windows Key
{RWI}         Right Windows Key 
{APP}         Open Context Menu Key

TABで特定のフォーム部品にフォーカスを当てたい場合は、繰り返し使うので、繰り返し演算子と一緒に使うと便利です。

SendKeys('{TAB}' x 5);

Ctrl, Alt, Shift

Ctrl, Alt, Shiftを押しながらのキーボード入力は、以下の文字を、先頭につけることでできます。

+ means SHIFT 
^ means CTRL 
% means ALT

Ctrl, Alt, Shiftを組み合わせた例です。

# Ctrl + c (コピー)
SendKeys('^c');

# Ctrl + v (貼り付け)
SendKeys('^v');

# Shift + a (A)
SendKyes('+a');

# Alt + l (画面ロック)
SendKyes('%l');

日本語のフォーム入力

IMEを使って日本語をキーボードからフォーム入力するのは、難しいです。

キーボードから入力するのではなくって、Perlの内部文字列を、Windowsのクリップボードに保存して、それを、フォーム入力に貼り付けるのがお勧めです。Perlのソースコードは、UTF-8で保存してください。

use utf8;
use Encode 'encode';

use Win32::GuiTest;
use Win32::Clipboard;

# クリップボードオブジェクトの作成
my $clip = Win32::Clipboard->new;

my $string = 'Perlゼミ';

# 文字列をクリップボードに保存
$clip->Set(encode('cp932', $string));

# 「Ctrl + v」で貼り付け
SendKeys('^v');

クリップボード操作

クリップボード操作について解説します。テキストをコピーしたり、フォームの入力欄に、文字を貼り付ける場合に使用します。

Win32::Clipboard

Windowsのクリップボードを扱うには、Win32::Clipboardモジュールを使用します。

use Win32::Clipboard;

クリップボードオブジェクトの生成

クリップボードオブジェクトをまず作成します。

# クリップボードオブジェクトの作成
my $clip = Win32::Clipboard->new;

クリップボードにPerl文字列を保存する

Setメソッドで、Perlの文字列を保存します。Perlのソースコードは、UTF-8で記述し「use utf8;」を記述していることが前提です。Windowsのクリップボードに、Perl側から文字列を保存するときは、cp932にエンコードして渡します。Windowsのクリップボードのテキストの文字コードが、cp932だからです。

# 文字列をクリップボードに保存
$clip->Set(encode('cp932', $string));

クリップボードからPerl文字列を取り出す

GetAsメソッドの引数に「CF_UNICODETEXT」を指定することで、「UTF16-LE」というユニコードのひとつの符号化形式で取得することができます。これを、PerlのEncode関数のdecode関数を使って、Perlの文字列に変換します。Windowsのクリップボードの内容をPerlの文字列として取得することができます。たんなるGetText関数では、正しく取得できないので、注意しましょう。

# クリップボードからPerl文字列を取り出す
my $string = $clip->GetAs(CF_UNICODETEXT);
$text = Encode::decode("UTF16-LE",  $string);

クリップボードの内容をフォーム部品に貼り付ける

クリップボードの内容を、テキストフィールドや、テキストエリアなどのフォーム部品に貼り付けるには「Ctrl + c」を送信します。「^」は「Ctrl」という意味です。

# クリップボードの内容をフォーム部品に貼り付ける
SendKeys('^c');

画面のHTMLの解析

ブラウザとRPAを組み合わせた場合にページのHTMLを解析する手法を解説します。

画面のHTMLを取得する

RPAとブラウザと組み合わせる場合は、HTMLの解析が利用できます。ChomeやEdgeでは、開発ツールと呼ばれるものが存在し、このツールを起動して、コピーすれば、クリップボードに、ページのHTMLを取得できます。Chromeでは、このツールをF12で開くことができます。「要素」タグが選択されている状態である必要があることに注意しましょう。

HTMLを取得するサンプルです。

# Chromeデベロッパーツールを開く
$self->SendKeys('{F12}');

# 開くのを待機
sleep 1;

# HTMLをクリップボードにコピー
$self->SendKeys('^c');

# クリップボードのテキストをUTF16-LEとして取得
my $html = $clip->GetAs(Win32::Clipboard::CF_UNICODETEXT());

# Perlの内部文字列にデコード
$html = Encode::decode("UTF16-LE", $html);

# Chromeデベロッパーツールを閉じる
$self->SendKeys('{F12}');

# 閉じるのを待機
sleep 1;

HTMLを解析する

HTMLを解析するには、HTMLをDOMに変換してくれるMojo::DOMを使うのが簡単です。取り出しが単純な場合は、Perlの正規表現を使うのもよいでしょう。

Mojo::DOMで、テーブルの列をたどるサンプルです。find関数には、任意のCSSセレクタが使えます。

use Mojo::DOM;

my $dom = Mojo::DOM->new($html);

for my $row ($dom->find('tr')->each) {
  my $row_text = $row->content;
  
  # 処理
}

特定の言葉が含まれているかをPerlの正規表現でチェックするサンプルです。

# 検索結果という文字列が含まれている
if ($html =~ /検索結果/) {
  # ...
}

HTMLの保存

HTMLを保存するには、通常のPerlのファイル入出力を使用します。

use FindBin;

# 保存場所(プログラムのあるディレクトリのdata/test.html)
my $file = "$FindBin::Bin/data/test.html";

# ファイルを書き込みモードでオープン
open my $fh, '>', $file
  or die "Can't open file $file: $!";

# 書き込み
print $fh $html;

RPAロボット作成のポイント

RPAロボット作成のポイントです。

ブラウザの起動サイズを決めておく

マウスでクリックする位置を確定させるために、ブラウザの起動サイズを決めて起動しましょう。

Chromeでは、ショートカット」「プロパティ」「リンク先」に次のように設定することで、ブラウザの起動サイズを決めることができます。

"C:\Program Files\Google\Chrome\Application\chrome.exe" --window-position=150,10 --window-size=1505,933

試験環境と本番環境でディスプレイのサイズをそろえる

試験環境と本番環境でディスプレイのサイズをそろえましょう。マウス移動は、ピクセル位置指定なので、ディスプレイの解像度が違うと、違う位置を指してしまいます。

ブラウザの応答を待つ

ブラウザの応答を待ちたい場合は、sleep関数を使います。ブラウザの応答が返ってくるなるべく安心な秒を設定しましょう。といっても、ネットワークの状況などに依存しますから、返ってこなくて、次の操作が始まって、動作が変になるということが、発生します。

# 3秒待つ
sleep 3;

RPAロボットの注意点

処理自動化・業務効率化において、RPAは、課題点が多い手法です。RPAロボットは、見た瞬間に、その動きに感銘を受けますが、処理速度、プログラムのメンテナンス性、自動化の信頼性が低いということに注意しましょう。

「WindowsのアップグレードでGUI画面が変わってしまったら?」「Webの利用サービスの更新でボタンの位置やテキストの表示が変わってしまったら?」「Webの応答が5秒間返ってこなかったら?」「マウスクリックやキーボードの入力がロストしたら?」「毎日だれが、そのプログラムをスタートさせるの?」「Linux上などで動いている他のプログラムとの連携はどうするの?」

処理自動化・作業効率化の最初に取りうる基本的で、実際に効果が高い手法は、テキスト化、コマンド化、Web化、バッチ化、RDBMS化です。

処理自動化・作業効率化を考える場合は、この五つの基本的な手段から、まずは検討してみませんか? 限られた部分に対して、RPAは効果を発揮するでしょう。

業務に役立つPerl

関連情報