それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

HTMLフォームのinputにイベントで文字列の値を突っ込む。スクレーパー用に使う。

課題:DOMを直接書き換えると反映されない

DOMでValueを書き換えても、反映されないJSのフレームワークが幾つかある。Angularとか。あのあたりをつかったログインフォームをかんたんに入力したい。

方法1 html のイベントをトリガーして文字列を突っ込む

最近は、domを直接書き換えないでJSでオブジェクトをObserveしていることが多いので、イベントを発火させて文字列を入力する。

inputElement = document.querySelector('input[name=nationalId]')
var event = new Event('input', {
    'bubbles': true,
    'cancelable': true
});

inputElement.value = '12345678'
inputElement.dispatchEvent(event);

めっちゃ単純ですね。通常通りDOMを書き換えたあとに、dispatchEvent で new Event('input') を発行してやるだけです。 これで、擬似的にフォームの入力をprogrammatically に試行できます。

方法2 execCommand

いにしえの手法 focus/ execCommand を使うともっと楽ちん。

document.querySelector('#tel001').focus()
document.execCommand('insertText', false, "090123456");

こちらは、focus したうえで、 execCommand を発行する。

focus したうえでイベントを発行するなら、他イベントも行けそうです。ただイベントを調べたりサポート状況が曖昧なので、execCommandという枯れた物を使います。

昔のやつ

https://takuya-1st.hatenablog.jp/entry/2014/11/12/162008

AngularJSのやつ

https://takuya-1st.hatenablog.jp/entry/2021/12/15/015820

Angular/AngularJSの場合は、スコープを取り出せば入力ができますが、フレームワークに特化すると後々が面倒そうなのでイベントを発火するほうが無難だと思う。

追記:パスワード自動入力ソフトの場合。

パスワード入力をするChrome のExtensionではどういう実装になっているのかというと、Bitwardenのソースコードを覗いてみました。

しつこくイベントを発行してました。

var event1 = el.ownerDocument.createEvent('HTMLEvents'),
                    event2 = el.ownerDocument.createEvent('HTMLEvents');
                el.dispatchEvent(doEventOnElement(el, 'keydown'));
                el.dispatchEvent(doEventOnElement(el, 'keypress'));
                el.dispatchEvent(doEventOnElement(el, 'keyup'));
                event2.initEvent('input', true, true);
                el.dispatchEvent(event2);
                event1.initEvent('change', true, true);
                el.dispatchEvent(event1);

https://github.com/bitwarden/browser/blob/master/src/content/autofill.js

ちなみに、bitwarden がこれだけイベント発火しても、一部のサイト(TP-Linkのルータログインページなど)では入力がうまくJS側に拾われないんですよねぇ。