あなたが探している情報は、この日記には記されていない可能性が高いです。(検索で来た人用)
にらどんは一杯500円。尚、出前は承っておりません。ご了承下さい。

WindowsScriptHost WSH ローカルファイル入出力

ひっどかった。
楽をしようとしたツケがこういう風にまわってくるのか。


先日、こともなくweb上のページからソースを抜き出してローカルのhtmlファイルに落としこんだところまではよかったのだけど、
これが実はよくなかったというのだからひどい話じゃないですか。
まず問題にあがったのはjsで操作しているIEからローカルファイルを開く方法。

	// ファイルオブジェクト初期化
	var fs = new WScript.CreateObject("Scripting.FileSystemObject");
	var file = fs.OpenTextFile("hoge.html", 2);
	// IEオブジェクト初期化
	var objIE = new ActiveXObject("InternetExplorer.Application");
	objIE.Visible = true;

	// webページを開く場合
	objIE.Navigate("http://d.hatena.ne.jp/needed/");

	// 同ローカルディレクトリにある"hoge.html"を開く場合
//	objIE.Navigate("hoge.html");						// "http://hoge.html"へアクセスする
	objIE.Navigate("file://" + fs.getAbsolutePathName("hoge.html"));	// ローカルファイルへアクセスする

ということで、objIE.Navigate()には"引数の先頭に自動で'http://'を付与する処理"が含まれているのです。
これが多分どこにも載ってない。日本語のページでは見つからなかった。英語読む前に解決してよかった。
同様のトラブル相談を見つけてなんとか解決したけど、単純にローカルファイルへのアクセス方法が載ってない。なんでやねん。


ようやくローカルファイルが開けたかと思ったら今度はjsによるDOMアクセスが失敗する。

	//  ページの読み込み待ち
	while( objIE.Busy  &&  objIE.ReadyState == READYSTATE_COMPLETE )
    		WScript.Sleep( 1000 );   // ループスピード緩和


	// <body></body>内のソースコードを全て取得してみる
	var str = objIE.Document.body.innerHTML;				// エラー


	// IEを閉じる
	objIE.Quit();
	// オブジェクトを解放
	objIE = null;
	// ファイルを閉じる
	file.close();

ここでまた詰まりまして。
調べた結果、「ローカルファイルだからダメ」とのこと。ええぇー。
IEのセキュリティ設定をいじればとのことだけども僕の環境だと変化なし。
テスト用ファイルを自分でweb上にアップロードして試してみると、通りました。ええぇー。


じゃあもういいやそれでってことでセレクタを抜き出していくんですが。
Firefoxのデフォルトの開発ツールがくっそ使いにくい。
一意のセレクタって書いてあるけどDOM的な解釈じゃないからぶっちゃけ意味がない。
階層とその要素中で何番目という表示なんだけど、
まず添え字は1〜で0〜のjsに対応してない。1個ずれる。これだけならまだいい。
これをgetElementsByTagName()で取得しようとすると話がややこしくなる。
せっかく階層ごとに何個目となっているのだから、それを1個ずらして指定すればいいと思うだろう。
しかし話はそう簡単ではないのだ。

<body>
 <table name="outer">
	<tr>
	 <td id="1"> <table name="inner">/*内部テーブル*/</table> </td>
	 <td id="2">hoge</td>
	</tr>
 </table>
</body>

これで"body.getElementsByTagName("table")(0).getElementsByTagName("tr")(0).getElementsByTagName("td")(1).innerText"で
"hoge"が得られると思ったら、大間違いなのだ。ていうか、そうなると今までずっと思っていたのだけど。
これだと<table name="inner">内の最初の<td>を拾います。
getEBTN()*1が返してくれるコレクションっていうのが入れ子を全部掘り下げてから次の要素に行くんですよ。

Array[0] == <td id="1">
Array[1~n] == <table name="inner">内の<td>
Array[n+1] == <td id="2">

というように。って書いてたらなんかこういう仕様だったような気がしてきた。
結局解決策は'body.getEBTN("td")(20)'みたいな全部の通し番号。</td>を上から検索で数えました(。∀゚)


かような困難に見舞われ、簡単な処理のはずが大変な目にあいました。
ていうか、せっかく保存したファイル、95MBぐらいあるのよね。これアップロードしなきゃいけないの?
だったら直でファイル生成しちゃったほうがいいような・・・。てかこの一件C++なら終わってたんじゃね・・・?
文字列処理でCに逃げることを考える日が来るとは思わなかった。

*1:略したのにゲット海老天になってかえって豪華な感じに