Amazon 特選タイムセール開催中

iMacrosとJavaScript【開発者メモ】

iMacrosとJavaScript【開発者メモ】

開発者用のメモです。

筆者(テイくん)が、プログラムを作成した時のコードをまとめて載せています。

ご自分で解決できないことがあった場合の参考にして頂ければと思います。

1. まずはじめに

他のページと違い、基本的な部分の解説を省いていますので中級者以上の内容になっています。

もし理解ができない時は、コマンド一覧と使い方「基礎講座」の記事一覧などで勉強して頂ければと思います。

補足
コードの書き方は人によって違いますので正解はありません。
最終的に自分の思ったとおりマクロが動いてくれればOKです。

2. コード一覧(iMacrosファイル)

円マーク(\)と半角カンマ(,)を削除

EXTRACTで抜き出した後にEVALでreplace関数を2回使って削除する。

iim
TAG POS=1 TYPE=SPAN ATTR=* EXTRACT=TXT
SET TRIMMED EVAL("\"{{!EXTRACT}}\".replace(/[\\\\\¥]/g,'').replace(/,/g,'');")
  • 円マーク(\):.replace(/[\\\\\¥]/g,'')
  • 半角カンマ(,):.replace(/,/g,'')

参考:teratail

空白と改行を削除

EXTRACTで抜き出した後、EVALでreplace関数で2回使って削除する。

iim
TAG POS=1 TYPE=TH ATTR=TXT:* EXTRACT=TXT
SET TRIMMED EVAL("\"{{!EXTRACT}}\".replace(/ /g,'').replace(/\s/g,'');")
  • 空白:.replace(/ /g,'')
  • 改行:.replace(/\s/g,'')

#EANF#をセルに表示させない

EXTRACTでデータがない場所を抜き出すと#EANF#がセルに表示される。

if文を使ってもし#EANF#時は空の値、それ以外は通常の値を返す。

iim
TAG POS=1 TYPE=IMG ATTR=SRC:https://* EXTRACT=HTM
SET TRIMMED EVAL("var s='{{!EXTRACT}}'; var x; if(s!='#EANF#'){ x='{{!EXTRACT}}';} x")

参考:iMacrosフォーラム(英語)

EVENTを使ってフォームのデータを上書き入力

JavaScriptで作成されたよくあるフォームに、新しいデータを入力する場合少しテクニックがいります。

通常の方法ですると、前のデータが残った状態になり正常に上書きできません。
※EVENTコマンドを使っている場合だけです。

iim
'「前のデータ」を削除(control+Aを押しながらBACK)
EVENT TYPE=KEYPRESS SELECTOR="#sell-container>DIV>DIV>FORM>DIV:nth-of-type(5)>DIV>UL>LI>DIV>DIV>DIV>INPUT" KEY=8 MODIFIERS = "ctrl,A"
WAIT SECONDS=1

'777とフォームに入力
EVENTS TYPE=KEYPRESS SELECTOR="#sell-container>DIV>DIV>FORM>DIV:nth-of-type(5)>DIV>UL>LI>DIV>DIV>DIV>INPUT" CHARS=7777
注意
待ち時間(WAIT SECONDS=1)を入れ忘れると、Errorが起きる可能性があります。
注意
このEVENTコマンドはバグが多いため検証しながら作成する必要があります。検証をされた方がいましたのでリンクを紹介しておきます。
公式フォーラム(英語)

2. コード一覧(JavaScriptファイル)

EVENTSを使う方法

Experimental event recording modeに変更してキーボードなどの操作を自動記憶した場合、コードをそのまま.jsで使うとエラーが起きます。

囲いを“(ダブルコーテーション)ではなく‘(シングルコーテーション)に変更、もしくは\(エスケープ)を追加する必要があります。

js
//NG
macro += "EVENTS TYPE=KEYPRESS SELECTOR="(上略)>DIV:nth-of-type(2)>DIV>DIV>INPUT" CHARS={{!COL2}}" + "\n";

//OK '(シングルコーテーション)
macro += 'EVENTS TYPE=KEYPRESS SELECTOR="(上略)>DIV:nth-of-type(2)>DIV>DIV>INPUT" CHARS={{!COL2}}' + "\n";

//OK \(エスケープ)
macro += "EVENTS TYPE=KEYPRESS SELECTOR=\"(上略)>DIV:nth-of-type(2)>DIV>DIV>INPUT\" CHARS={{!COL2}}" + "\n";

SET !DATASOURCEを使う方法

DATASOURCEフォルダ内で使う場合は.iimも.jsも書き方は全く同じです。

iim
SET !DATASOURCE test.csv
js
macro += "SET !DATASOURCE test.csv" + "\n";

DATASOURCEフォルダ以外で使う場合は、書き方が少し変わります。
区切りの\(バックスラッシュ)の数が違うので注意。

iim
SET !DATASOURCE C:\Users\PC\Desktop\test.csv
js
macro += "SET !DATASOURCE C:\\Users\\PC\\Desktop\\test.csv" + "\n";
  • .iim:区切りは\を1個
  • .js:区切りは\\を1個

XPATHを使う方法

XPATHを.iimと同じ構文で.jsで書くとエラーが起きます。

.jsの場合は=の後の“(ダブルコーテーション)を消します。

iim
TAG XPATH="/html/body/div[1]/section/div[1]/table/tbody/tr[2]/td/a[1]/div"
js
macro += "TAG XPATH=/html/body/div[1]/section/div[1]/table/tbody/tr[2]/td/a[1]/div" + "\n";

それとXPATH+EXTRACTを使うときは特に間違いやすいので注意が必要です。

iim
TAG XPATH="/html/body/div[1]/section/div[1]/table/tbody/tr[2]/td/a[1]/div" EXTRACT=TXT
js
macro += "TAG XPATH=/html/body/div[1]/section/div[1]/table/tbody/tr[2]/td/a[1]/div EXTRACT=TXT" + "\n";
補足
.jsで書く時のポイントは、始まりと終わりにのみ”(ダブルコーテーション)を入れるです。

空白と改行を削除

.jsと.iimでは少しreplaceの使い方が変わってきます。

.iimで作ったものを.jsに変えた場合動かない場合があります。よくあるのが\(エスケープ)の追加です。

js
macro += "TAG POS=1 TYPE=TH ATTR=TXT:* EXTRACT=TXT" + "\n";
macro += "SET TRIMMED EVAL(\"'{{!EXTRACT}}'.replace(/ /g,'').replace(/\\s/g,'');\")" + "\n";

//以下のでも可
macro += "SET TRIMMED EVAL(\"var s='{{!EXTRACT}}'; s.replace(/ /g,''); s.replace(/\\s/g,''); \")" + "\n";
補足
ポイントはこの部分です→replace(/\\s/g,'')
iim内では(/\s/g,'')で問題ありませんが、.js内では(/\\s/g,'')\(エスケープ)を入れてあげないと改行として認識しません。

値によって条件分岐

取得した値によって条件分岐させる場合はEAVL内でif文を使えば可能です。

js
//100以上の場合は◯、それ以外は☓
macro += "SET MARK EVAL(\"var s={{!EXTRACT}}; if(100 <= s ){s= '○';} else{s = '×';} \") " + "\n";

//100以上、999以下の場合は◯、それ以外は☓
macro += "SET MARK EVAL(\"var s={{!EXTRACT}}; if(100 <= s && s <= 999){s= '○';} else{s = '×';} \") " + "\n";
注意
if(100 <= s <= 999)はNGです。100以上、999以下の条件に見えますが動きません。
参考 javascriptのif文で2つ以上の数値を比較する(範囲指定、条件分岐)Qiita

LOOP回数を任意にユーザーが設定する

JavaScriptではRepeat MacroのMAX数値を変更してもLOOP(繰り返し再生)できません。

解決方法は、for文とif文を追加するとiimと同じように使うことができます。

js
var num = prompt("繰り返したい回数を入力してください!\n ");

    // キャンセルを押した場合の処理
    if(num == null) { 
      iimClose(); // マクロを終了
      }
	
    // 値を何も入力しなかった場合の処理
    else if(num == "") { 
      alert("数値は必須事項です!");
      iimClose();
      }
	
    // 1~99までの数値(半角)を入力しなかった場合の処理
    else if(isNaN(num) || !(num >=1 && num <=99)) {
      alert("1~99までの数値(半角)を入力してください!");
      iimClose();
      }

var macro = "CODE:";
macro += "PROMPT {{loop}}" + "\n"; 

    //1から順番に99まで1づつ増える
    for (var loop = 1; loop <= 99; loop++){
    
      // numより数値が大きくなった場合マクロ終了
      if (loop > num){
        iimClose();
        } 
		
iimSet("loop", loop);           
iimPlay(macro);                 
}

上記のようにすることで.iimと同じようにLOOP回数をユーザーが簡単に選ぶことができます。

補足
alertを使ってなぜマクロが動かなかったのかメッセージを表示させるのがポイントです。
それと99の数値を増やせば無限ループさせることも可能です。

replaceを使った割引きの方法

何割引きにするかをユーザーに選んでもらうときに使う方法です。

計算式の数値は小数点が出てくるので、整数で入力できるように変更します。

割引の計算方法
1割引きなら×0.9
2割引きなら×0.8
3割引きなら×0.7
js
var value = prompt("何割値引きするか入力してください!\n・1~9までの半角数字\n・0は割引なし\n ");
    if(value == null) {
      iimClose();
    }
    
    else if(value == "") {
      alert("数値は必須事項です!");
      iimClose();
    }    

    else if(isNaN(value) || !(value>=0 && value<=9)) {
      alert("0~9までの数値(半角)を入力してください!");
      iimClose();
    }
    
//valueの数値を置き換えして割引率を出す
switch( parseInt(value, 10) ) {
    case 0: var off = value.replace(0, 1);   //割引なし
      break;
    case 1: var off = value.replace(1, 0.9); //1割引
      break;
    case 2: var off = value.replace(2, 0.8); //2割引
      break;
    case 3: var off = value.replace(3, 0.7); //3割引
      break;
    case 4: var off = value.replace(4, 0.6); //4割引
      break;
    case 5: var off = value.replace(5, 0.5); //5割引
      break;
    case 6: var off = value.replace(6, 0.4); //6割引
      break;
    case 7: var off = value.replace(7, 0.3); //7割引
      break;
    case 8: var off = value.replace(8, 0.2); //8割引
      break;
    case 9: var off = value.replace(9, 0.1); //9割引
      break;
}

var macro = "CODE:";
macro += "SET !VAR1 2000" + "\n";
macro += "SET PRICE_A EVAL(\"var s = {{!VAR1}}; s = s * {{off}};\")" + "\n";
macro += "PROMPT 入力した数値:{{value}}<br>置き換え後の値:{{off}}<br>割引の計算式:{{!VAR1}}*{{off}}={{PRICE_A}}" + "\n";

macro += "SET !VAR2 999" + "\n";
macro += "SET PRICE_B EVAL(\"var s = {{!VAR2}}; s = s * {{off}};\")" + "\n";
macro += "PROMPT 入力した数値:{{value}}<br>置き換え後の値:{{off}}<br>割引の計算式:{{!VAR2}}*{{off}}={{PRICE_B}}" + "\n";

//小数点を四捨五入するバージョン
macro += "SET !VAR2 999" + "\n";
macro += "SET PRICE_B EVAL(\"var s = {{!VAR2}}; s = s * {{off}}; s = Math.round(s);\")" + "\n";
macro += "PROMPT ※四捨五入したバージョン<br>入力した数値:{{value}}<br>置き換え後の値:{{off}}<br>割引の計算式:{{!VAR2}}*{{off}}={{PRICE_B}}" + "\n";

iimSet("value", value);    
iimSet("off", off);           
iimPlay(macro);

数学が苦手な方の場合入れ間違える可能性がありますので、上記のように置き換えれば分かりやすくなります。
参考 【JavaScript入門】Switch文で条件分岐する方法(default/break)samurai Blog

補足
少数点を四捨五入する場合はround関数を使います。 s = Math.round(s)を後ろに追加するだけです。
参考 【JavaScript入門】四捨五入/切り上げ/切り捨てを桁数を指定して行うsamurai Blog

EXTRACT抜き出しデータをjsで使う

iimで抜き出したデータはjsでは使うことができません。

jsで使いたい場合は、iimGetExtractコマンドが必須です。

js
//【iMacrosエリア】
// 1000、2000、3000を順番にEXTRACTに入れる
var macro = "CODE:";
macro += "SET !REPLAYSPEED MEDIUM" + "\n";
macro += "SET !VAR1 1000" + "\n";
macro += "SET !VAR2 2000" + "\n";
macro += "SET !VAR3 3000" + "\n";

macro += "ADD !EXTRACT {{!VAR1}}" + "\n";
macro += "ADD !EXTRACT {{!VAR2}}" + "\n";
macro += "ADD !EXTRACT {{!VAR3}}" + "\n";
iimPlay(macro);


//【JavaScriptエリア】
//iMacrosで抜き出したデータをJavaScriptに受け渡す
var getA = iimGetExtract(1); //1個目のEXTRACTデータを変数「getA」に渡す
var getB = iimGetExtract(2); //2個目のEXTRACTデータを変数「getB」に渡す
var getC = iimGetExtract(3); //3個目のEXTRACTデータを変数「getC」に渡す

alert(getA); //変数「getA」の値を確認
alert(getB); //変数「getB」の値を確認
alert(getC); //変数「getC」の値を確認

//JavaScriptにあるデータを100で割ったあとiMacrosにセットする
iimSet("getA", getA / 100);
iimSet("getB", getB / 100);
iimSet("getC", getC / 100);


//【iMacrosエリア】
//JavaScriptから受け渡されたデータをiMacrosで使う
var macro2 = "CODE:";
macro2 += "PROMPT {{getA}}" + "\n"; 
macro2 += "PROMPT {{getB}}" + "\n"; 
macro2 += "PROMPT {{getC}}" + "\n";
iimPlay(macro2);

iimGetExtract(1)のカッコの中の数値は、上から何番目のExtractの値という意味です。

注意
SET !EXTRACT NULL(データ破棄)SAVEAS TYPE=EXTRACT FOLDER=* FILE=*のコマンドを使うとExtract内のデータがなくなります。
参考 iimGetExtractiMacros Wiki(英語)

データソースの列(COL)でLOOPさせる

LINEでLOOPする場合はSET !DATASOURCE_LINE {{!LOOP}}{{!COL}}使えばできます。

では、COLでLOOPする場合はSET !DATASOURCE_COLUMNS {{!LOOP}}{{!LINE}}を使えばできるような気がしますが、{{!LINE}}というコマンドが存在しません。

データソース使用時に使えるコマンドは{{!COL}}だけです。もしどうしてもカラム1→2→3…としたい時はJavaScriptを使うしかありません。

下記の方法を使えばカラムでも可能です。

js
function csvColumn(loop) {
  var macro = "CODE:";
  macro = "SET !DATASOURCE test.csv" + "\n"; //ここに+を入れるとエラーが起きるので注意!
  macro += "SET !DATASOURCE_LINE 1" + "\n";
  macro += "PROMPT {{!COL" + loop + "}}" + "\n";
  return macro;
}

for (loop = 1; loop <= 5; loop++) { //5カラム目まで繰り返す
  iimPlayCode(csvColumn(loop)); //Codeを忘れないよう
}

ファイルを作成するのが面倒な方はコピペして試しに動かしましょう。
ファイル名はtest.csvです。

1 2 3 4 5
A B C D E
参考 Pass column number in iimset (javascript)iMacrosフォーラム(英語)

iimSet内で変数(動的)と文字列を一緒に使う

変数 + “文字列”でコードを書けば繰り返す毎に変数の値を増やすことができます。

js
var macro = "CODE:";
macro += "PROMPT {{NUM}}" + "\n";

for (var loop=1; loop <= 5; loop++){
  iimSet("NUM", loop + "回目" );
  iimPlay(macro);
}

両端に文字を入れることもできます。

js
var macro = "CODE:";
macro += "PROMPT {{NUM}}" + "\n";

for (var loop = 1; loop <= 5; loop++){
  iimSet("NUM","現在の繰り返し回数は" + loop + "回目" );
  iimPlay(macro);
}
注意
ただし変数名(NUM)の部分はこの方法は使えません。

JavaScript内のエラー回避

  • iMacros:SET !ERRORIGNORE YESでエラー回避します。
  • JavaScript:try catchでエラー回避します。
js
try{
//ここに処理を書く
} catch(e){
//ここにエラー時の処理を書く(何もなければ空白でもOKです)
}

途中でエラーが起きても止まることがなく処理を継続できます。

値を特定の基準(2や3の倍数など)で増やす

全て5回繰り返すサンプルです。

js
//2の倍数で増やす
var macro = "CODE:";
macro += "PROMPT {{loop}}" + "\n";

for (var loop=0; loop <= 10; loop += 2){
  iimSet("loop", loop);
  iimPlay(macro);
}
js
//3の倍数で増やす
var macro = "CODE:";
macro += "PROMPT {{loop}}" + "\n";

for (var loop = 0; loop <= 15; loop += 3){
  iimSet("loop", loop);
  iimPlay(macro);
}
js
//2ずつ増やす
var macro = "CODE:";
macro += "PROMPT {{loop}}" + "\n";

for (var loop = 1; loop <= 11; loop += 2){
  iimSet("loop", loop);
  iimPlay(macro);
}
js
//3ずつ増やす
var macro = "CODE:";
macro += "PROMPT {{loop}}" + "\n";

for (var loop = 1; loop <= 16; loop += 3){
  iimSet("loop", loop);
  iimPlay(macro);
}

新しいフォルダを自動生成する

場所を指定して新しいフォルダを生成することができます。

以下を動かすと各フォルダに「test」が自動で生成されます。

js
//Macrosフォルダ
var foldername = "test";
imns.FIO.makeDirectory(imns.Pref.getFilePref('defsavepath').path+"\\"+foldername);

//Datasourcesフォルダ
var foldername = "test";
imns.FIO.makeDirectory(imns.Pref.getFilePref('defdatapath').path+"\\"+foldername);

//Downloadsフォルダ
var foldername = "test";
imns.FIO.makeDirectory(imns.Pref.getFilePref('defdownpath').path+"\\"+foldername);

変数を定義せずに直接ファイル名を入れる場合は

js
//Macrosフォルダ
imns.FIO.makeDirectory(imns.Pref.getFilePref('defsavepath').path+"\\"+"test");

//Datasourcesフォルダ
imns.FIO.makeDirectory(imns.Pref.getFilePref('defdatapath').path+"\\"+"test");

//Downloadsフォルダ
imns.FIO.makeDirectory(imns.Pref.getFilePref('defdownpath').path+"\\"+"test");

さらに下層にフォルダを生成することもできます。ただあまりする方はいないと思いますが…

js
var foldername = "test";
var foldername2 = "test2";
imns.FIO.makeDirectory(imns.Pref.getFilePref('defsavepath').path+"\\"+foldername+"\\"+foldername2);
参考 imacros javascript-新しいフォルダーの作成iMacrosフォーラム(英語) 参考 iMacrosフォルダーの場所の問題iMacrosフォーラム(英語)

特定の位置まで画面スクロール

scrollBy(0,1000)の1000の部分を大きくすればスクロールする量を増やすことも出来ます。

ただ、サイトの作りによっては動かない場合があります。

例えばFacebookやTwitterなどのように一部分だけ無限スクロールになっているようなサイトです。

js
var macro = "CODE:";
macro += "URL GOTO=https://www.yahoo.co.jp/" + "\n";
macro += "URL GOTO=javascript:window.scrollBy(0,1000)"+ "\n"; // スクロール
macro += "WAIT SECONDS=1"+ "\n";
macro += "URL GOTO=javascript:window.scrollBy(0,1000)"+ "\n"; // スクロール
macro += "WAIT SECONDS=1"+ "\n";
macro += "URL GOTO=javascript:window.scrollBy(0,1000)"+ "\n"; // スクロール
macro += "WAIT SECONDS=1"+ "\n";
macro += "URL GOTO=javascript:window.scrollBy(0,1000)"+ "\n"; // スクロール
macro += "WAIT SECONDS=1"+ "\n";
macro += "URL GOTO=javascript:window.scrollBy(0,1000)"+ "\n"; // スクロール
iimPlay(macro);