『うみうみ屋さんの掲示板』を題材に、スクリプト作成練習


スクリプト作成中毒者にとって、『うみうみ屋さんの掲示板』は題材の宝庫です。このコーナでは、課題に取り組んだが投稿には至らなかったスクリプトや、この掲示板に寄せる雑感を書きます。

目次


関数の使い方

IMPUTBOXを何度も使いたい (2007/1/23(Tue) 12:49 No.496)

[投稿要旨]
ひとつのIMPUTBOXを何度も使いたいのですがやり方がわかりません。どなたかヒントいただけないでしょうか。

回答スクリプトが完成し、投稿しようとしたら、いりやさんがすでに回答されていたので、投稿を見合わせました。しっかし、『アドホックな解』には、たまげました。解の内容ではなく、アドホックという言葉です。生まれて初めて接した言葉なのでググってしまいましたよ。
閑話休題。没投稿を載せます。
// (別解)二種類の入力処理をひとつの関数とする。
//       違いは、表示文字だけなので、関数の引数として指定する。代入先は、配列を使う。

dim kin[2],su[2]
id =getid("SSB")
for i=0 to length(kin)-1
	kin[i]=数値入力("単価 ("+(i+1)+")")
	su[i]=数値入力("数量 ("+(i+1)+")")
next

str=""
for i=0 to length(kin)-1
	str=str+kin[i]+"<#cr>"
	str=str+su[i]+"<#cr>"
next
msgbox(str)

////////////////////
// 数値を入力する
// (In)string		数値の種類(表示用)
// (戻り値)			入力された値
////////////////////
function 数値入力(string)
	while true 
		数値 = input(string+"を入力して下さい") 
		if 数値=empty then exitexit  
		ifb val(数値)=ERR_VALUE
			msgbox("数値を入れてください")
			Continue
		endif
		ifb 数値="" then 
			msgbox("入力が必要です") 
			CONTINUE
		ELSE
			BREAK
		ENDIF 
	WEND
	result=数値
fend

// スクリプトの終点

Linersさんも同じ題材のスクリプトを掲載されています。
16:単価と数量(非アドホックな解?)
2007/1/24(眠)

窓のタイトルとクラスが同じ場合の判別方法

GETIDについて (2007/1/27(Sat) 17:52 No.516)

[投稿要旨]
”名前を付けて保存”のウィンドウは、条件によっては、同名ウィンドウが2つ開きます。同名ウィンドウを判別するためのクラス名の指定の仕方を教えて下さい。

// 名前を付けて保存の窓はクラス名が同じです。
// よって、窓の中の文字列の内容で判断します。

str=""
fNam="file01"
doscmd("dir > "+fNam+".txt")	// 上書きになるようにファイルを作っておく。

id=exec("notepad.exe")
sendstr(id,"testの本文")
sckey(id,vk_alt,f,a)
id2=getid("名前を付けて保存","#32770")
if 0< pos("保存する場所",getstr(id2,1,STR_STATIC)) then str=str+"ファイル名入力窓のid:"+id2+"<#cr>"

sendstr(id2,fNam)
sckey(id2,vk_alt,s)				// 保存
sleep(1)

for i=0 to getallwin()-1
  id3=ALL_WIN_ID[i]
	ifb "名前を付けて保存"=status(id3,ST_TITLE) and "#32770"=status(id3,ST_CLASS) then
		if 0< pos("上書きしますか?",getstr(id3,2,STR_STATIC)) then str=str+"上書き確認窓のid:"+id3+"<#cr>"
	endif
next
msgbox(str)

// スクリプトの終点

上の手法はスクリプト『楽天証券 MarketSpeed 自動ログイン』でも使っています。
ボタン内容で判別するよりも、文字列で判別の方が、私の好みです。スクリプトコードが"上書きしますか?"といった問いかけに応えるような記述になるからです。
窓内の文字列の確認はスクリプト『指定する窓のすべてのアイテムや文字列および特殊変数を取得』が便利です。
2007/1/28(眠)

clkitem()不具合の回避策

指定した形式でファイル保存されない。 (2006/11/12(Sun) 15:30 No.367)

[投稿要旨]
ファイル保存時のファイルの種類の選択をclkitem()で行うと、見かけ上は指定したものが選択されるが、実際の保存結果では、異なる種類で選択される。

以前に、私が質問投稿したものを取り上げます。

> リストボックスの選択肢の先頭が半角カタカナなどの場合は、無効、という課題も残りました。

これは、sendstr()で対応できました。ついでに、ファイル保存処理を関数にしました。
// IEでファイル保存(comなし版)
fukidasi(GET_UWSC_VER)
id=exec("C:\Program Files\Internet Explorer\IEXPLORE.EXE http://www.h7.dion.ne.jp/~umiumi/")
repeat
	sleep(0.1)
until (! status(id,ST_BUSY))
SaveIe(id,4)
ctrlwin(id,close)

//////////
// IEで名前を付けて保存
// (In) id		IEの窓id
// (In) flgF	ファイルの種類 1:html完全 2:mht 3:htmlのみ 4:テキスト
// (戻り値)なし
// (動作確認済ソフト)  UWSC V4.1b|V4.1c
// (備考)UWSC V4.1bでは、ファイルの種類の選択でclkitem()を使うと正しく動作しない。よってsckey()とsendstr()で代用。
//////////
procedure SaveIe(id,flgF)
	sckey(id,VK_ALT,F,A)
	dim id2=getid("Web ページの保存","#32770")
	sckey(id2,VK_ALT,T)
	sleep(0.1)
	select flgF
		case 1
										// Html完全:何もしない
		case 2
			sckey(id2,W)				// "W"1回:mht
		case 3
			sckey(id2,W,W)				// "W"2回:Htmlのみ
		case 4
			sendstr(id2,"テ")			// テキスト
	selend
	clkitem(id2,"保存",ITM_BTN)
	repeat
		sleep(0.1)
	until 0> getid("Web ページの保存","#32770",0.1)
	sleep(0.2)
fend

// スクリプトの終点
2007/1/30(眠)

HTMLから数値データを取り出し、Excelへ書込。

WEBページのある数値データーをマウスを使わずクリップボードに格納したい。 (2007/3/9(Fri) 21:18 No.583)

[投稿要旨]
WEBページの数値データをEXCELで取り込んで加工したいです。
マウスを使わずWEBページの数値データーを直接クリップボードに格納する方法をお教えください。
更にバックグラウンドで処理出来れば最高です。
数値データーは6桁で4個有ります
取り込み頻度は5秒に1回です

// 松井証券サイトから日経225先物時価を5秒ごとに取得しEXCELへ追加。COM使用の例。
// 可視状態にするの行を無効にすれば、バックグラウンドで処理となります。
// 取得時価が変化するさまは未確認です。当方は実直な会社員なので、場中のスクリプト起動確認はできません。
// UWSC4.1d | WinXP Home SP2 | IE6.0SP2 | Excel 2002(10.2614.2625)

option explicit
dim IE,doc,doc2,tbl
dim i,j,n,flg
dim Excel,Workbook
dim 銘柄行1[]="銘柄種別","日経225先物期近","日経225先物期先","日経225mini期近","日経225mini期先"
dim 銘柄行2[4]
dim 時価[4]

IE=CreateOLEObj("InternetExplorer.Application")
IE.Visible=True							// 可視状態にする
IE.Navigate("https://www.deal.matsui.co.jp/ITS/login/MemberLogin.jsp")
BusyWait(IE)
doc=IE.Document
doc.form.clientCD.value=MATSUI_KOZA		// 会員ID
doc.form.passwd.value=MATSUI_PSWD		// 会員パスワード
doc.form.submit(); sleep(1); BusyWait(IE)
doc2=doc.frames.GM.document
for i=0 to doc2.links.length-1
	if "先物OP"=doc2.links(i).innerText then break
next
doc2.links(i).click; BusyWait(IE)
doc2=doc.frames.LM.document
for i=0 to doc2.links.length-1
	if "先物OP新規"=doc2.links(i).innerText then break
next
doc2.links(i).click; BusyWait(IE)
flg=FALSE						// tdタグに"日経225先物銘柄"がTRUE:見つかった FALSE:見つからない
tbl=doc.frames.CT.Document.body.all.tags("td")
for i=0 to tbl.length-1
	if "日経225先物銘柄"=tbl.item(i).innerText then flg=TRUE
	if (("銘柄"=tbl.item(i).innerText) and flg) then break
next
dim 基準添え字=i
j=i+4							// item(26):銘柄  item(30):現在値  その値は7の倍数を加算したもの
i=基準添え字
for j=0 to length(銘柄行2)-1
	銘柄行2[j]=chgmoj(strconv(tbl.item(i).innerText,SC_HALFWIDTH),"<#cr>","")
	i=i+7
next

Excel=CreateOLEObj("Excel.Application") 
Excel.Visible=True					// 可視状態にする 
Workbook=Excel.Workbooks.Add
行書込(Excel,1,銘柄行1)
行書込(Excel,2,銘柄行2)

n=3
while TRUE
	i=基準添え字+4
	gettime()
	時価[0]=G_TIME_HH2+":"+G_TIME_NN2+":"+G_TIME_SS2
	for j=1 to 4
		i=i+7
		時価[j]=token("〔",tbl.item(i).innerText)
	next
	行書込(Excel,n,時価)
	n=n+1; sleep(2)
	IE.Refresh2(0); BusyWait(IE)
	tbl=IE.Document.frames.CT.Document.body.all.tags("td")
	if getkeystate(VK_ESC) then break
wend

////////////////////////////////////////
//--- Excelへ一行書込
procedure 行書込(Excel,行番号,書込値[])
	dim x=1
	dim n,ss
	for n=0 to length(書込値)-1
		sleep(0.2)
		sendstr(0,書込値[n])
		ss=GETSTR(0)
		Excel.ActiveSheet.Cells(行番号,x).Activate
		Excel.ActiveSheet.PasteSpecial
		sendstr(0,"")
		x=x+1
	next
fend

//--- ブラウザ読み込み待ち
procedure BusyWait(ie)
	Sleep(0.5)
	repeat
		Sleep(0.2)
	until (! ie.busy) and (ie.readyState=4)
	Sleep(0.5)
fend

// スクリプトの終点

証券取引などの資産運用において、UWSCの利用価値は大きいです。自動ログインはもちろんのこと、自動売買に取り組んでいるサイトもあります。私の場合は、主に新聞記事や情報の取得に活用しています。いちいちマウスを5〜6回もクリックして、ページ表示で何回も待たされるのでは、記事を読むのがおっくうです。スクリプトで実ハードディスクのテキストファイルへ保存してしまえば、快適に多くの記事を読むことができます。
2007/3/11(眠)

Windows Media Player のCOM

メニューを取得できない (2007/3/23(Fri) 00:04 No.615)

この投稿の中で、Windows Media Player 11で、Playerが今停止中かどうかを、判定したいという内容がありました。 Media Player は COM が使えるので、調べてみました。結果として、その方法は分かりませんでした。少し分かったことと挫折の理由を覚え書きとして、書き残しておきます。 再生中か、停止中かを判別するには、PlayState プロパティが使えます。
WMP=createoleobj("WMPlayer.OCX")
WMP.URL="D:\Data\hoge.mpg"
for i=1 to 6
  ifb 1=(i mod 2) then
    WMP.controls.play()
  else
    WMP.controls.stop()
  endif
  fukidasi("playState="+WMP.playState)
  sleep(5)
next

再生中か否かは、区別できました。PlayState の値として 1:Stopped と 3:Playing が検出できています。しかし、なぜか音声は聞こえますが、映像はまったく見えません。そこで別の方法を試しました。
WMP=createoleobj("WMPlayer.OCX")
URL="D:\Data\hoge.mpg"
print "未再生 playState="+WMP.playState
sleep(2)
WMP.openPlayer(URL)
sleep(1)
repeat
  print "再生中 playState="+WMP.playState
until getkeystate(VK_ESC)

映像・音声ともに正しく再生されています。しかし、PlayState が常に 0 となります。あちらを立てれば、こちらが立たず。

この調査はこれにて打ち止め。私は、iTunes/iPod派なので、Media Playerを使いこなすメリットはないのです。Media Player のCOMは、プロパティの説明部にサンプルスクリプトが載っているので、iTunes.com よりはとっつきやすいです。ただしマイクロソフトのMedia Player 関係のサイトは異様に重かったです。初めからやる気をそがれました。

[動作確認環境]
Windows Media Player V11.0.5721.5145 / WinXP Home SP2

[参考サイト]
Windows Media Player 11 SDK About the Windows Media Player SDK
Windows Media Downloads
Windows Media SDK 開発者向けリソース
2007/4/9(眠)

接続している全ドライブ情報の取得

doscmd の結果 (2007/4/14(Sat) 14:12 No.681)

[投稿要旨]
doscmd("fsutil.exe fsinfo drives")の結果が正しく取得できません。

私自身の投稿の延長戦をここで行います。仮にUWSCの問題であるとしても、対応策はないかと私なりに探ってみて、お手挙げ状態での投稿でした。umiumiさんから直接回答いただき回避策を授けていただきました。何か、もったいない気分です。野球に例えれば、草野球のおっさんが、プロ野球選手から直接指導を受けるようなものでしょうか。
さて、いただいた回答を生かしてスクリプトを組みました。
///// (1) はじめ /////
option explicit,optpublic,defaultfont="MS ゴシック"
dim i
hashtbl drvLtr
getDrvLetter(drvLtr)
dim lenW=length(drvLtr)
dim strW="ドライブ数 : "+lenW+"<#cr>"
for i=0 TO lenW-1
	strW=strW+"<#cr>"+drvLtr[i,HASH_KEY]+" "+drvLtr[i,HASH_VAL]
next
msgbox(strW)

//////////
// 存在するドライブを取得  WinXP専用  UWSC V4.2
procedure getDrvLetter(var drvLtr[])
	dim hVal,strW
	hashtbl drvN
	doscmd("fsutil.exe fsinfo drives > drv.txt")
	dim adTypeText=2; dim adReadAll=(-1)
	dim src=CreateOleObj("ADODB.Stream")
	src.Type=adTypeText; src.Charset="Shift_JIS"
	src.Open; src.loadFromFile("drv.txt")
	dim drives=src.readText(adReadAll)
	src.Close
	drives=ChgMoj(drives,CHR(0)," ")
	token(" ",drives)
	while TRUE
		strW=token("\",drives)
		if drives="" then break
		hVal=doscmd("fsutil.exe fsinfo drivetype "+strW)
		token("-",hVal)
		drvLtr[strW]=trim(hVal)
	wend
fend
///// (1) おわり /////

///起動結果
ドライブ数 : 6

A: リムーバブル ドライブ
C: 固定ドライブ
D: 固定ドライブ
E: 固定ドライブ
Q: CD-ROM ドライブ
Z: 固定ドライブ

SUBST コマンドで作ったZドライブは、『固定ドライブ』と表示されました。本当はここで締めなのですが、XP専用というのが物足りないです。fsutil.exe はXPから装備されたコマンドです。ビスタは未確認です。
冒頭に書いた高揚感から、少し背伸びをして、WMIに取り組みました。
WMI にまともに取り組んだのは初めてですが、何とか結果が出せました。ですが、WMI の標準装備はWinME以降のようです。少しがっかり。
WMIの使い方を求めて、インターネットを漁っていたら、WMI Code Creator なるものを拾えました。MWI のサンプルスクリプト製造器です。残念ながら、UWSCスクリプトには対応していませんが、VBScript に対応してしました。VBScript からなら、がんばれば UWSCに変換できそうです。これでまたひとつUWSCで使える道具が増えました。WMI Code Creator のUWSC対応版を作る課題が頭をよぎりましたが、1分後に却下。
///// (2) はじめ /////
option explicit,optpublic,defaultfont="MS ゴシック"
hashtbl DrvTyp
DrvTyp[0]="Unknown"
DrvTyp[1]="No Root Directory"
DrvTyp[2]="Removable Disk"
DrvTyp[3]="Local Disk"
DrvTyp[4]="Network Drive"
DrvTyp[5]="Compact Disc"
DrvTyp[6]="RAM Disk"
DrvTyp[99]="Drive type could not be determined"
hashtbl drvLtr
dim i
dim strW2
dim cntW=getDriveLetters(drvLtr)
dim strW="Number of drives : "+cntW+"<#cr>"
for i=0 to cntW-1
	strW2=drvLtr[i,HASH_VAL]
	strW=strW+"<#cr>"+drvLtr[i,HASH_KEY]+" "+DrvTyp[strW2]
next
msgbox(strW)

//--------------------
// 接続全ドライブの種別を取得
// (出力値)drvLtr[]	全ドライブのドライブ名と種別
//     種別 0:Unknown  1:No Root Directory  2:Removable Disk  3:Local Disk
//        4:Network Drive  5:Compact Disc  6:RAM Disk
//         (例)HASH_KEY『A:』 HASH_VAL『3』種別が取得できない場合は『99』
// (戻り値)result	接続ドライブの数
// (動作確認ソフト)	WinXp Home Sp2 のみ。
// (備考)Win2000/WinME も使えるはず。Win9xは Windows Management Instrumentation (WMI)CORE 1.5
//       をインストールすれば使えるらしい。
// 2007/4/17(眠)
//--------------------
function getDriveLetters(var drvLtr[])
	dim flgR[]=0,1,2,3,4,5,6			// Win32_LogicalDisk - DriveType
	dim objItem,i,j
	dim strW
	dim Locator=CreateOleObj("WbemScripting.SWbemLocator") 
	dim Obj_WMI=Locator.ConnectServer.ExecQuery("Select * From Win32_LogicalDisk")
	dim cnt=GetOleItem(Obj_WMI)
	dim str="Number of drives : "+cnt+"<#cr>"
	for i=0 to cnt-1
		objItem=all_ole_item[i]
		strW=objItem.DeviceID
		drvLtr[strW]=99
		for j=0 to length(flgR)-1
			ifb objItem.DriveType=flgR[j] then
				drvLtr[strW]=objItem.DriveType
			endif
		next
	next
	result=cnt
fend
///// (2) おわり /////
///起動結果
Number of drives : 6

A: Removable Disk
C: Local Disk
D: Local Disk
E: Local Disk
Q: Compact Disc
Z: Local Disk

[動作確認環境] UWSC Pro V4.2 / WinXP Home SP2

[参考サイト]
msdn Win32_LogicalDisk
Hey, Scripting Guy! - ドライブ名として次に使用可能な文字を特定する方法はありますか
TechNet スクリプト センター - ドライブ タイプの識別
WMI Code Creator v1.0
Windows Management Instrumentation (WMI) CORE 1.5 (Windows 95/98/NT 4.0)
ドライブの情報(タイプ、ボリュームラベル、ファイルシステムなど)を取得する
2007/4/17(眠)

別解として、Scripting.FileSystemObject を使った方法を載せます。

option explicit,optpublic,defaultfont="MS ゴシック"
dim aryDrvTyp[]="Unknown","Removable Disk","Hard Disk","Network Drive","CD-ROM","RAM Disk"

hashtbl drvLtr
dim i
dim cntW=getDriveLetters(drvLtr)
dim strW="Number of drives : "+cntW+"<#cr>"
for i=0 to cntW-1
	strW=strW+"<#cr>"+drvLtr[i,HASH_KEY]+" "+aryDrvTyp[drvLtr[i,HASH_VAL]]
next
msgbox(strW)

//--------------------
// 接続全ドライブの種別を取得
// (出力値)drvLtr[]	全ドライブのドライブ名と種別
//     種別 0:Unknown  1:Removable Disk  2:Hard Disk
//        3:Network Drive  4:CD-ROM  5:RAM Disk
//         (例)HASH_KEY『A:』 HASH_VAL『3』
// (戻り値)result	接続ドライブの数
// (動作確認ソフト)	UWSC V4.424 | WinXp Home Sp2
// 2008/7/14(眠)
//--------------------
function getDriveLetters(var drvLtr[])
	dim i
	dim objFs,objDrvs
	objFs=CreateOLEObj("Scripting.FileSystemObject")
	objDrvs=objFs.Drives
	for i=0 to GETOLEITEM(objDrvs)-1
		drvLtr[ALL_OLE_ITEM[i].DriveLetter+":"]=ALL_OLE_ITEM[i].DriveType
	Next
	result=objDrvs.Count
fend

///起動結果
Number of drives : 11

A: Removable Disk
C: Hard Disk
D: Hard Disk
E: Hard Disk
F: Hard Disk
H: Removable Disk
I: Removable Disk
J: Removable Disk
K: Removable Disk
Q: CD-ROM
Z: Hard Disk

動作確認環境が若干変わっているので、起動結果は、異なっています。
3つの方法を載せましたが、Scripting.FileSystemObject を使った方法がお勧めです。たぶんOSを選ばずに動作するからです。

[参考サイト]
msdn - Scripting ランタイム ライブラリ DriveType プロパティ

2008/7/14(眠)

slctbox()関数の初期選択項目

SLCTBOXの項目について (2007/5/22(Tue) 23:36 No.796)

[投稿要旨]
SLCTBOXのチェックボックス、ラジオボタンなど予めn番目の項目を選択している状態にしたいのですができませんか?

質問は、SLCT_CHK と SLCT_RDO だけですが、全種別を対象に作ってみました。
UWSC Pro V4.2 | WinXp Home Sp2

option explicit,samestr,optpublic
option defaultfont="MS ゴシック"
dim i,j,ret
dim selType[]=SLCT_BTN,SLCT_CHK,SLCT_RDO,SLCT_CMB,SLCT_LST
for i=1 to 5
	msgbox(i+"番目を選択状態にします。")
	for j=0 to length(selType)-1
		thread slct_sel(i,selType[j])
		ret=SLCTBOX(selType[j],0,"slctbox()関数デモ","AAAA","BBBB","CCCC","DDDD","EEEE")
	next
next

//--------------------
// slctbox()のn番目の項目を選択状態にする; slctbox()の直前にスレッドで起動)
// (入力値)n	選択状態にする項目
// (入力値)flgK	slctbox()関数の種別(第1引数) SLCT_BTN SLCT_CHK SLCT_RDO SLCT_CMB SLCT_LST
// (戻り値)なし
//--------------------
procedure slct_sel(n,flgK)
	dim id,endNum,i
	dim namW=GET_UWSC_NAME;  namW=token(".",namW)
	while TRUE
		id=getid(namW,"TFSectBox.UnicodeClass")
		ifb 0 < id
			// 前処理
			if SLCT_RDO=flgK or SLCT_RDO=flgK or SLCT_LST=flgK then sckey(id,VK_TAB)
			// 移動回数
			endNum=n-1					// SLCT_BTN,SLCT_RDO,SLCT_LST
			if SLCT_CHK=flgK or SLCT_CMB=flgK then endNum=n
			// 移動処理
			for i=1 to endNum
				sckey(id,VK_DOWN)
			next
			// 後処理
			if SLCT_LST=flgK and 1=n then sckey(id,VK_SPACE)
			if SLCT_RDO=flgK or SLCT_CMB=flgK or SLCT_LST=flgK then sckey(id,VK_TAB)
			if SLCT_CHK=flgK then sckey(id,VK_SPACE)
			if SLCT_CHK=flgK then clkitem(id,"OK",CLK_BTN,FALSE)
			break
		endif
	wend
fend

// スクリプトの終点
2007/05/23(眠)
移動キーを変更 2007/05/24(眠)

msgbox()関数の窓タイトルの大文字小文字区別

msgboxのタイトルの大文字小文字の区別 (2007/7/20(Fri) 01:03 No.958)

[投稿要旨]
Win98SEでは、EXE化した時にMSGBOX等でのタイトルがすべて大文字となってしまいます。

自身の投稿の後日談を書きます。汎用性がないテーマである気がするので、わざわざ公式掲示板を使わずに備忘としてここに残します。
UWSC側で対応ができなければ、スクリプト側で対処が可能かどうかです。模索してみました。

[結論]
Win9x でmsgbox()の窓のタイトルのファイル名が大文字になるのは、我慢してそのままとする。

[経緯]
UWSC掲示板 『インプットボックスについて』(2006/11/24(Fri) 18:22 No.391)に投稿された2つの手法を検討
  1. 大文字小文字が区別された自スクリプト名の取得は、ここの付記で記載した方法。
  2. VBScript のmsgbox関数をUWSCに取り込む方法は却下。Win98 では ScriptControl が標準装備されていないため。たかだか、窓タイトルの変更のために ScriptControl のインストールを促すのは適当でない。
  3. SetWindowTextA()でタイトルを書き換える手法は、動作が不安定なので却下。動作確認環境は『Microsoft Virtual PC』配下のWin98SE であり、Virtual PC 環境固有のエラーか否かの検証もしていない。
[参考文献]
Windows Script Control
ソフトウェアサポート掲示板 - by AOK マクロが使えません 2005/09/16 05:03
2007/07/23(眠)

『HTMLかんたん解析』でスクリプト作成 (1)

input type="button"の押下 (2007/7/26(Thu) 11:13 No.972)

[投稿要旨]
input type="button"のクリックができない。
@ホームページ上で物件データベースの検索結果を表示(結果が複数件の場合もあり)
A検索結果のうち、「図」と書かれたボタンがある物件のみ、当該ボタンをクリック

HTML の操作をするには、HTMLの知識や慣れが必要です。これだけでは、身も蓋もないので、私ならどう解くかをここで明かします。
質問の焦点ははっきりしています。『「図」と書かれたボタンをクリック』これをスクリプトでどう書くかです。
ブラウザでソースを表示して、HTMLを追っかける? 達人はそれで分かるのでしょうか。私の場合は、拙作スクリプト『HTMLかんたん解析 』(HTMLStarkNaked.uws)を使います。試してみる気になった方は、次の手順をどうぞ。


  1. 『HTMLかんたん解析 』をダウンロードし、変名する。HTMLStarkNaked.uws.txt → HTMLStarkNaked.uws
    置き場所はどこでも良い。
  2. 以下を test.uws という名前で保存。
  3. ///// test.uws /////
    TEXTBLOCK htmlSmp
    <input type="button" value="図" onclick="return ClickPrc2(15,'201337971511')">
    ENDTEXTBLOCK
    
    IE=CreateOLEObj("InternetExplorer.Application")
    IE.Visible=True
    IE.Navigate("about:blank")
    sleep(0.5)
    IE.document.write(htmlSmp)
    

  4. test.uws を起動。
    → IEが開き、『図』ボタンが表示。
  5. 『図』ボタンをマウスでクリック。
    → IEのステータスバーに『ページでエラーが発生しました。』が表示されることを確認しておく。
  6. IEに『図』ボタンが表示された状態で HTMLStarkNaked.uws を起動(クリック)。
    → デスクトップに xxxxxxx.log が保存され、xxxxxxx.log がエディタで開く。(xxxxxxx は任意の数字。ここでは 1840204.logとして進める)
  7. 1840204.logをエディタの検索機能を使って、『図』という言葉で検索。
    → 下の2行にマッチする。
  8. ///// 1840204.log /////
    doc.all.tags("input").item(0).outerHTML :"<INPUT onclick=<#dbl>return ClickPrc2(15,'201337971511')<#dbl> type=button value=図>"
    doc.all.tags("input").item(0).value :"図"
    

    この結果のうち『doc.all.tags("input").item(0).value』と、上から3行目の『doc=IE.document』をスクリプトコードとして採用。
  9. IEを閉じる。
  10. 下のように書いて、test.uws の末尾に追加。
  11. doc=IE.document
    msgbox(doc.all.tags("input").item(0).value)    // (A)
    

  12. test.uws を起動。
    → IEが開き、中央の小窓に『図』という文字が表示。

  13. これで、図ボタンを捕らえることができました。次にクリックします。
  14. test.uws の(A)を変更。
  15. msgbox(doc.all.tags("input").item(0).value)
     ↓
    doc.all.tags("input").item(0).click
    

  16. test.uws を起動。
    →IEのステータスバーに『ページでエラーが発生しました。』が表示されれば、クリック成功。
  17. 後は最後の仕上げ。ボタンが複数あれば『item(0)』では対応できないことがあります。
    doc=IE.document
    for i=0 to (doc.all.tags("input").length)-1
      ifb "図"=(doc.all.tags("input").item(i).value)  // 「図」と書かれたボタンなら
        doc.all.tags("input").item(i).click()     // クリック
        break
      endif
    next
    


    ひとつ目の『図』をクリックするのはこれでいいはずですが、WITH 〜 ENDWITH でコードを質素にします。
    with IE.document.body.all.tags("input")  // フレームを使ったページの場合は、適宜変更が必要。
      for i=0 to (.length)-1
        ifb "図"=(.item(i).value)     // 『図』と書かれたボタンなら
          .item(i).click()        // クリック
          break
        endif
      next
    endwith
    


なお、『図』と書かれたボタンが複数の場合にすべての『図』ボタンをクリックする処理は省きます。『図』ボタンクリック後のIEの挙動により処理が異なるからです。

スクリプト名変更に合わせて更新。 2007/3/16(眠)
2007/7/26(眠)

UWSC掲示板投稿用に特殊文字を変換

UWSC Ver4.3 で追加されたoption specialchar の活用事例です。投稿文書内に<#dbl>などの特殊文字が含まれていても、そのまま出力できるようになりました。

////////////////////////////////////////
// UWSC掲示板投稿用に特殊文字を変換
// 
// [使い方]
// (1)投稿予定文章をクリップボードへコピー
// (2)本スクリプトを起動。
// (3)投稿フォームへ貼り付け。
// 
// [参考文献]
// 『LINERS WEBSITE』-『実用スクリプト』-『No.3 掲示板用の特殊文字変換(クリップボード内で変換)』
// http://www.nagomi-jp.net/~liners/jituyou.htm
// 2007/7/1(眠)
////////////////////////////////////////
option specialchar
dim i
hashtbl strTBL
strTBL["<"]="<"
strTBL[">"]=">"
strTBL["  "]=" "
strTBL["	"]="  "
dim strW=GetStr(0)
for i=0 to length(strTBL)-1
	strW=CHGMOJ(strW,strTBL[i,HASH_KEY],strTBL[i,HASH_VAL])
next
SendStr(0,strW)

// スクリプトの終点

2007/8/1(眠)

タブブラウザといえば Sleipnir

GetActiveOLEObj関数のタイトルについて (2007/8/20(Mon) 10:52 No.1026)

[投稿要旨]
IE7.0にて、同一ウィンドウ内で3つのタブを開き、ウィンドウ自体を最小化した状態で、タイトルによって取得するウィンドウを決定したいが、GetActiveOLEObj関数がエラーとなる。

(他のブラウザを使った解)
Sleipnir なら複数ドキュメントから、指定のドキュメントオブジェクト、または、IEオブジェクトを API で容易に取得出来ます。
ですが、投稿はあくまでもIE7がテーマなので、完全にお門違い。なので、ここにこっそりとSleipnirの場合の使用事例を掲載。

// Sleipnir V1.61 / Sleipnir V2.5.12 (ブラウザエンジンは IE6.0Sp2) | WinXp Home Sp2
option explicit,optpublic,samestr
dim IE,SP,objSh,id
const SLEIPNIR_EXE="D:\Prg\sleipnir\Sleipnir.exe"

exec(SLEIPNIR_EXE+" http://www3.bigcosmic.com/board/s/board.cgi?id=umiumi")
exec(SLEIPNIR_EXE+" http://www.yahoo.co.jp/")
exec(SLEIPNIR_EXE+" http://www.google.co.jp/")
id=getid("Sleipnir")
repeat
	sleep(0.1)
until !status(id,ST_BUSY)                     // ここまでで複数ページ表示
objSh=CreateOleObj("Shell.Application"); objSh.ToggleDesktop   // 全窓を最小化
sleep(1)   /////////////////////////////////////////////
SP=CreateOLEObj("Sleipnir.API")

IE=GetIEObj(SP, "Yahoo")
msgbox(IE.document.title+" "+IE.document.url)

IE=GetIEObj(SP, "Google")
msgbox(IE.document.title+" "+IE.document.url)

//--------------------
// Sleipnir から、指定タイトルのInternetExplorer.Applicationオブジェクトを取得
// (入力値)SP     Sleipnir.API
// (入力値)title    タイトル(部分一致でも可)
// (戻り値)result   InternetExplorer.Applicationオブジェクト
//--------------------
function GetIEObj(SP, title)
	dim i,IE
	result=NOTHING
	for i=0 to SP.GetCount-1
		IE=SP.GetWebBrowserObject(SP.GetDocumentID(i))
		ifb 0 < pos(title, IE.LocationName)
			result=IE; break
		endif
	next
fend

// スクリプトの終点

2007/08/20(眠)

『HTMLかんたん解析』でスクリプト作成 (2)

hotmailへの自動ログイン (2007/9/8(Sat) 20:22 No.1081)

[投稿要旨]
hotmail へのサインインができません。HtmlAnalyzer.uws を使ってその付近をみてみましたが、それをどうしたらいいのか、想像がつきません。

[のうがき]

回答はここで行います。
  • 回答が長くなる。
  • 『本サイトのスクリプトに対する質問などをUWSCの作者の方に対して行うのは、おやめください。』と書いている。
というのが、回答を『UWSC掲示板』でなく、ここで行う理由です。

『想像がつきません。』という反響はとてもありがたいお言葉でした。自分としては、HtmlAnalyzer は力作であり、使用頻度の高いスクリプトです。しかしながら他の方に使われていないのは、HTML の初心者にとって敷居が高いことが一因と、改めて分かりました。 (もちろんそれ以外にも至らない点はたくさんあるでしょう)
その敷居を少しでも下げたいところからの本稿執筆です。さりとて超初心者向けのスクリプトを目指す気はありません。
**********
[準備]
  1. 『HTMLかんたん解析 』をダウンロードし、ファイル名を変更する。
    HTMLStarkNaked.uws.txt → HTMLStarkNaked.uws
  2. HTMLStarkNaked.uws を好きな場所に置き、気軽に起動できるようにする。
    (例)スタートメニューへ登録、デスクトップにショートカットを置く、など。
[前提条件]
  1. Live ID: abc444@hotmail.co.jp
  2. パスワード: def666
  3. ブラウザは IE6 | UWSC Pro V4.3c | WindowsXP Home SP2 | HtmlAnalyzer 2007/05/14版
という仮定の元に書く。

[手順]
  1. IE または Sleipnir がすでに起動している場合は、閉じる。
  2. IE6 を起動し、アドレスバーに『http://www.hotmail.com』を入力し[Enter]キーを押す。
    → Windows Live Hotmail のページが表示。
  3. 『Live ID』の右側の入力欄に『abc444@hotmail.co.jp』、『パスワード』の右側の入力欄に『def666』を入力。
  4. HTMLStarkNaked.uws を起動。
    → 786986.log がデスクトップに作成され、786986.log が開く。(『786986』は不定の数字)
  5. 786986.log のファイル内を『abc444』という言葉で検索。
  6. doc.forms(0).elements(7).value :"abc444#hotmail.co.jp"
    および
    doc.all.tags("input").login.value :"abc444#hotmail.co.jp"
    


    にマッチする。このどちらかを使えば、Live ID の入力を行えることが分かる。 さらに、786986.log の上の3行に注目。
    --- HTMLドキュメント・オブジェクトの取得・記述例 ---
    IE=getactiveoleobj("InternetExplorer.Application")
    doc=IE.document
    

  7. これらの記述から新規スクリプト test.uws を書いてみる。
  8. //--- test.uws (Step1) ---
    IE=getactiveoleobj("InternetExplorer.Application")
    doc=IE.document
    doc.all.tags("input").login.value="abc444@hotmail.co.jp"
    

  9. すでに起動している IE6 のアドレスバーに『http://www.hotmail.com』を入力し[Enter]キーを押す。
    → 新たに、Windows Live Hotmail のページが表示。『Live ID』は何も入力されていない。
  10. test.uws (Step1)を起動。
    →『Live ID』の入力欄に『abc444@hotmail.co.jp』が入力される。『Live ID』の入力記述ができた。
  11. 786986.log のファイル内を『def666』という言葉で検索。
  12. doc.forms(0).elements(8).value :def666
    および
    doc.all.tags("input").passwd.value :def666
    


    にマッチする。このどちらかを使えば、パスワード の入力を行えることが分かる。
  13. test.uws に追加する。
  14. //--- test.uws (Step2) ---
    IE=getactiveoleobj("InternetExplorer.Application")
    doc=IE.document
    doc.all.tags("input").login.value="abc444@hotmail.co.jp"
    doc.all.tags("input").passwd.value="def666"
    


  15. すでに起動している IE6 のアドレスバーに『http://www.hotmail.com』を入力し[Enter]キーを押す。
    → 新たに、Windows Live Hotmail のページが表示。『Live ID』と『パスワード』は何も入力されていない。
  16. test.uws (Step2)を起動。
    →『Live ID』の入力欄に『abc444@hotmail.co.jp』が入力され、『パスワード』の入力欄に『def666』が入力される。『パスワード』の入力記述ができた。
  17. 786986.log のファイル内を『サインイン』という言葉で検索。
  18. doc.forms(0).elements(11).value :"  サインイン  "
    および
    doc.all.tags("input").SI.value :"  サインイン  "
    


    にマッチする。このどちらかを使えば、『サインイン』ボタンをクリックできることが分かる。
  19. test.uws に追加する。
  20. //--- test.uws (Step3) ---
    IE=getactiveoleobj("InternetExplorer.Application")
    doc=IE.document
    doc.all.tags("input").login.value="abc444@hotmail.co.jp"
    doc.all.tags("input").passwd.value="def666"
    doc.all.tags("input").SI.click()
    


  21. すでに起動している IE6 のアドレスバーに『http://www.hotmail.com』を入力し[Enter]キーを押す。
    → 新たに、Windows Live Hotmail のページが表示。『Live ID』と『パスワード』は何も入力されていない。
  22. test.uws (Step3)を起動。
    →『Live ID』と『パスワード』欄に指定の文字列が入力され、『メール アドレスまたはパスワードが間違っています。もう一度やり直してください。』が表示される。『サインイン』ボタンをクリックできた。
  23. 現状の test.uws は、すでにブラウザが開いていることを想定しているので、新規にブラウザを起動するように変更する。
  24. //--- test.uws (Step4) ---
    IE = CreateOLEObj("InternetExplorer.Application")
    IE.Visible = True
    IE.Navigate("http://www.hotmail.com")
    BusyWait(IE)
    doc=IE.document
    doc.all.tags("input").login.value="abc444@hotmail.co.jp"
    doc.all.tags("input").passwd.value="def666"
    doc.all.tags("input").SI.click()
    //------
    Procedure BusyWait(ie)
    	Sleep(0.5); repeat; Sleep(0.2); until (! ie.busy) and (ie.readyState=4); Sleep(0.5)
    Fend
    

  25. IE を閉じる。
  26. test.uws (Step4)を起動。
    → 『Live ID』と『パスワード』欄に指定の文字列が入力され、『メール アドレスまたはパスワードが間違っています。もう一度やり直してください。』が表示される。『サインイン』ボタンをクリックできた。完成。
2007/09/09(眠)
スクリプト名変更に合わせて更新。 2007/3/16(眠)

IEの操作をどう学ぶか

IEを操作するための知識をどう学んだら良いか、という問いかけが UWSC 掲示板にありました。

UWSC 掲示板 フレーム内の操作法 (2007/9/10(Mon) 10:35 No.1086)

ともさんの回答は『ベンダーのヘルプ、リファレンス』とのことでした。
HTMLソースと『ベンダーのヘルプ、リファレンス』をにらめっこしてスクリプトが書けるのは、HTMLやDOMをすでに理解している人だけという気がします。
ということで、私自身がどのように取り組んできたかを書いておきます。

  1. 操作したい部分のHTMLソースを表示
  2. そこに使われているHTMLタグなどをインターネットで検索
  3. 検索結果から、スクリプト実例を探しだし、自分の目的に近くように少しづつ変更。
操作したい部分のソース表示は、Sleipnir の『選択部分のソースを表示』の機能を使います。FireFox にも標準で同様の機能があります。Opera ではプラグイン? で実現できるようです。これらのブラウザは無料なので、活用しないのはもったいないです。IEしか使っていない方には、複数ブラウザを併用することをお勧めします。

インターネットで検索するときのキーワードを何にするかは、ひとことで説明するのは難しいです。INPUTタグを調べる場合は、『UWSC INPUT』『VBS INPUT』『スクリプト INPUTタグ』といったキーワードが考えられます。UWSCの使用事例だけを当てにしても期待した結果が得られないことが多いです。他のスクリプトやプログラムの事例をUWSCに変換するという作業も、恐れずに行いました。期待する結果が得られるまで何十回でもキーワードを変えてしつこく検索しました。

それとは別に、UWSC掲示板の過去ログをひととおり解読するということも行いました。もちろんすべてを理解できてはいませんが、読み返すたびに、分からないものが減っていけば、それは進歩の証ということです。

さらに、新たなHTMLタグを使うたびに、HTML解析スクリプトへ追加して行きました。その結晶が拙作スクリプト HTMLかんたん解析です。

それにしても、IEを操作するスクリプトを作るときに、みなさんは、どんな方法でHTMLを解読しているのでしょうか。

[参考文献]
Sleipnir 2.xx リファレンス メニュー
Firefox の結構使える10の基本機能
My Opera View selection source (Monday, 29. May 2006, 13:54:36)
HTMLかんたん解析 :: 拙作UWSCスクリプト
UWSC 掲示板−WEBページ解析の道具 (2007/9/7(Fri) 22:12 No.1076)
2007/09/16(眠)

BetWeenStr()の代替関数

BETWEENSTRでの文字列取得について (2007/9/18(Tue) 20:15 No.1102)

[投稿要旨]
BETWEENSTR関数の結果が意図したとおりになりません。BETWEENSTR関数の引数の指定方法は誤っておりますでしょうか?

引数の指定方法が誤っているという訳ではないでしょうね。単に戻り値が期待する結果と異なるだけです。 これが仕様だとしたら、私は不本意です。標準関数の挙動が不本意な場合は、自作関数で対応する方法があります。質問の本旨はBetWeenStr()関数の仕様の質問であり、代替策の質問ではないので、ここで取り上げます。
str = "テスト,テスト1,テスト2,テスト3,テスト4,テスト5,テスト"
for n = 1 to 5
  data = BetweenStr2( str, ",", "," ,n)
  print "【" + n + "】" + data
next
sleep(2)
/////

//--------------------
// 指定文字列間の文字列を返す
// (入力値)strTarget  探す元になる文字列
// (入力値)strBefore  得たい文字列の前にある文字列
// (入力値)strAfter   得たい文字列の後にある文字列
// (入力値)n      n個目の該当文字列を返す(マイナス値を指定すると後ろからサーチ)
// (戻り値)result    指定文字列間の文字列
//--------------------
function BetWeenStr2(strTarget, strBefore, strAfter, n)
  string1=copy(strTarget, pos(strBefore, strTarget, n)+length(strBefore), length(strTarget))
  result=copy(string1, 1, pos(strAfter, string1)-1)
fend

// スクリプトの終点

これで質問者の意図した結果が得られました。ところで、私の用途では上の自作関数でも満足できません。前文字と後文字を含んだ文字列を取得する機能もつけたいのです。ここまで行くと標準関数の変更に期待するより、自分で勝手にやれという内容と思われます。なので勝手にやります。
2007/9/19(眠)

input type="file" へ非COMで入力

<input type="file" name="file">に貼り付けるには? (2007/9/25(Tue) 20:45 No.1121)

[投稿要旨]
<input type="file" name="file">に貼り付けを行いたいのですがどうすればいいでしょうか。

IE7では IESetData()関数でinput type="file"への入力ができないため、非COMの方法を umiumi さんが紹介しています。しかし、BTN()関数とKBD()関数は最終手段にしたい。WindowIDを指定する関数の方が安定動作が期待できるからです。 そこで、別解をつくりました。

// UWSC V4.3d1 | IE6.0 SP2 | WinXP Home SP2
const IEXPLORE_EXE="C:\Program Files\Internet Explorer\iexplore.exe"
ifb !fopen(IEXPLORE_EXE, F_EXISTS); msgbox(IEXPLORE_EXE+" が見つかりません。"); exitexit; endif
id=exec(IEXPLORE_EXE+" about:<html><body><input type=file name=file><br><br><input type=file name=file></body></html>")
setInputTypeFile(id, "abcde", 2)
setInputTypeFile(id, "12345", 3)

//--------------------
// input type="file" へ文字列を入力
// (入力値)id    Windowを識別するID 
// (入力値)string1  文字列
// (入力値)num    左上から数えたエディトコントロールの順番 SENDSTR()関数の第三引数と同じ
// (戻り値)result  TRUE:正常 FALSE:異常
//--------------------
function setInputTypeFile(id, string1, num=1)
  result=FALSE
  sendstr(0, string1)
  sendstr(id,"", num, TRUE,TRUE)
  sckey(id, VK_CTRL, V)
  if string1=getstr(id, num, STR_ACC_EDIT) then result=TRUE
fend

// スクリプトの終点

残念ながら IE7 の環境は無いので、IE7 での確認は出来ません。

2007/09/27(眠)

IEのリンク文字列をExcelへ転送

取得しExcelに貼り付けるには? (2007/9/26(Wed) 07:12 No.1122)

[投稿引用]
http://www.asahi.com/list.html
のページにある記事のみを取得し、Excelに貼り付けたいのですが、どのようにすればいいのでしょうか?

umiumi さんの『とりあえず書いてみた』スクリプトを見たら、自分でも無性にスクリプトを書きたくなりました。


// UWSC V4.3d1 | Excel 2002(10.2614.2625) | IE6.0 SP2 | WinXP Home SP2
option explicit,optpublic
dim objXl,objSheet,objIe,objDoc
dim i,n

fukidasi("ブラウザを起動しています。")
objIe=CreateOLEObj("InternetExplorer.Application")
//objIe.Visible=True
objIe.Navigate("http://www.asahi.com/list.html")
BusyWait(objIe)
objDoc=objIe.document

fukidasi("Excel を起動しています。")
objXl=CreateOLEObj("Excel.Application")
objXl.Visible=TRUE
objSheet=objXl.Workbooks.Add().ActiveSheet

fukidasi(objIe.LocationName+" から記事一覧を取得しています。")
n=0
for i=0 to objDoc.links.length-1
	if 0=pos("/update/", objDoc.links(i).href) then continue
	n=n+1
	objSheet.Cells(n,1).Value=objDoc.links(i).innerText
next
objIe.quit; objIe=NOTHING
fukidasi()

//------
Procedure BusyWait(objIe)
	Sleep(0.5); repeat; Sleep(0.2); until (! objIe.busy) and (objIe.readyState=4); Sleep(0.5)
Fend

// スクリプトの終点

2007/9/27(眠)

複数項目の入力窓

入力フォームの作成 (2007/12/31(Mon) 03:31 No.1350)

[投稿要旨]
uwscにはInputBoxが用意されていますが、このInputBoxを複数表示させることはできますでしょうか?

yanyan さんの提示されたスクリプトは、onclick属性でvalueを書き換えて、ボタンが押されたか否かを判定している点が優れています。この方法を採用させていただいた上で、作ってみました。IEを利用して複数項目の入力窓を実現しています。操作者には IE を意識させませんが、タスクバーにIEが表示されてしまいます。

option explicit
hashtbl hshItem
hshItem["名前"]=20
hshItem["住所"]=50
hshItem["電話"]=40
hshItem["郵便番号"]=10

dim lngRet,lngLoop
dim strW1

lngRet=inputX("個人情報入力", "各項目を入力してね。", hshItem, 800, 310)
ifb 0=lngRet
  strW1=""
  for lngLoop=0 to length(hshItem)-1
    strW1=strW1+"<#CR>"+hshItem[lngLoop, HASH_KEY]+" "+hshItem[lngLoop, HASH_VAL]
  next
  msgbox(trim(strW1))
elseif (-1)=lngRet
  msgbox("破棄されました。"); exitexit
elseif (-2)=lngRet
  msgbox("InternetExplorer が見つかりません。"); exitexit
endif

//--------------------
// 入力窓を表示し、入力テキストを取得。複数の入力窓を指定可能。
// (入力値)  strDspTitle      タイトル
// (入力値)  strDspMsg      表示メッセージ
// (入力値)  hshItem[](HASH_KEY)  入力項目名
// (入/出力値)hshItem[](HASH_VAL)  入力領域の桁数/入力された値
// (入力値)  lngWidth        入力窓の幅
// (入力値)  lngHeght        入力窓の高さ
// (戻り値)  result        0:正常 -1:破棄 -2:IEがない -3:入力項目の9個を越えている。
//
// UWSC V4.4 | WinXPHome SP2 | IE 6.0.2900.2180 SP2
//--------------------
function inputX(strDspTitle, strDspMsg, var hshItem[], lngWidth, lngHeght)
  dim strHtml1="#DSP_MSG#<br><#CR><Form Method='Post' Name='InputForm'><table>"
  dim strHtml2="<tr><td>#STR_DSP_ITEM#</td><td><input type=<#DBL>text<#DBL> accesskey='#AKEY#'"_
  	+" name=<#DBL>#STR_INPUT_ITEM#<#DBL> size=#LNG_SIZE# maxlength=#LNG_SIZE#></td></tr>"
  dim objIe
  dim strWx,strW1
  dim lngLoop

  ifb 9<length(hshItem)
    result=(-3); exit
  endif
  COM_ERR_IGN
  objIe=CreateOLEObj("InternetExplorer.Application")
  COM_ERR_RET
  ifb COM_ERR_FLG
    result=(-2); exit
  endif

  objIe.Width=lngWidth; objIe.Height=lngHeght
  strHtml1=chgmoj(strHtml1, "#DSP_MSG#", strDspMsg)
  strWx=""
  for lngLoop=0 to length(hshItem)-1
    strW1=strHtml2
    strW1=chgmoj(strW1, "#STR_DSP_ITEM#", hshItem[lngLoop, HASH_KEY]+"("+(lngLoop+1)+")"+)
    strW1=chgmoj(strW1, "#STR_INPUT_ITEM#", "inputItem"+(lngLoop+1))
    strW1=chgmoj(strW1, "#LNG_SIZE#", hshItem[lngLoop, HASH_VAL])
    strW1=chgmoj(strW1, "#AKEY#", lngLoop+1)
    strWx=strWx+strW1
  next

  objIe.Navigate("about:blank")
  objIe.Menubar=False; objIe.Toolbar=False; objIe.Statusbar=False; objIe.Resizable=False
  objIe.document.body.scroll="no"
  objIe.document.body.bgColor="MENU"
  objIe.document.body.style.border="none"
  objIe.document.body.insertAdjacentHTML("AfterBegin", strHtml1+strWx+blkHtml3)
  objIe.document.title=" "+strDspTitle+format(" ", objIe.Width/2)
  objIe.Top=(objIe.document.parentWindow.screen.availHeight-objIe.Height)/2
  objIe.Left=(objIe.document.parentWindow.screen.availWidth-objIe.Width)/2
  objIe.document.all.tags("input").item(0).Focus
  objIe.Visible=True
  for lngLoop=0 to length(hshItem)-1
    hshItem[hshItem[lngLoop, HASH_KEY]]=""
  next
  ctrlwin(getid("Internet Explorer","IEFrame"), activate)

  COM_ERR_IGN
  repeat
    sleep(0.1)
    if 1>objIe.document.all.tags("input").length then break  // [×]ボタンが押された
    ifb objIe.document.InputForm.okbtn.value = "入力終了選択"
      for lngLoop=0 to length(hshItem)-1
        eval("hshItem[hshItem["+lngLoop+", HASH_KEY]]:=objIe.document.InputForm.inputItem"_
        	+(lngLoop+1)+".value")
      next
      result=0; break
    elseif objIe.document.InputForm.cancelbtn.value = "破棄選択"
      result=(-1); break
    endif
  until getkeystate(VK_ESC)
  objIe.Quit
  COM_ERR_RET
fend


//------
Procedure BusyWait(objIe)
  Sleep(0.5); repeat; Sleep(0.2); until (! objIe.busy) and (objIe.readyState=4); Sleep(0.5)
Fend

//--------------------
textblock blkHtml3
</table>
<br>
<input type="button" accesskey='y' name="okbtn" value="入力終了(y)" onClick=" value='入力終了選択'"> 
<input type="button" accesskey='n' name="cancelbtn" value=" 破棄(n) " onClick="value='破棄選択'">
<br><br>
<font size="-2">[alt]キーと数字キーの同時押しで、項目移動ができるよ。</font>
endtextblock

// スクリプトの終点

2008/01/03(眠)

HTMLのテーブルを検索して1行取り出し

HTMLの中から情報と取り出したいが同じようなタグがあってうまくいかない。 (2008/2/16(Sat) 00:58 No.1465)

[投稿要旨]
Yahoo!電話帳-大阪府 - 市区町村機関
http://phonebook.yahoo.co.jp/a127/g117/g20078/g38910100/

このページの電話番号一覧からひとつを任意に取り出して 名称 電話番号 住所を、それぞれを新規で開いたエクセルのA1 B1 C1 に貼り付けしたいのです。

UWSC掲示板では、非COM主体での解き方が紹介されています。ここでは、COM 処理を取り上げます。

それにしても、最近 IE のテーブル処理の質問が多いです。私はテーブルの取得は、
  elmsTable.item(i).all.tags("tr").item(j).all.tags("td").item(k).innerText
のように行っていましたが、UWSC 掲示板でいりやさんが紹介されていた
  elmsTable.rows.item(r).cells.item(c).innerText
の方が分かりやすいですね。さっそく今回取り入れました。

さてまずは、操作対象のテーブルをスクリプトが適切にとらえているかを確認するために、全行列を Excel へ書き出してみます。

////////////////////////////////////////
// IEのテーブルをExcelへ書き出す。
////////////////////////////////////////
const xlUp		= (-4162)
const xlToLeft	= (-4159)

// IE起動と初期処理
objIe=CreateOLEObj("InternetExplorer.Application")
objIe.Visible=True
objIe.Navigate("http://phonebook.yahoo.co.jp/a127/g117/g20078/g38910100/")
Sleep(0.5); repeat; Sleep(0.2); until (! objIe.busy) and (objIe.readyState=4); Sleep(0.5)
objDoc=objIe.document

// 取得対象テーブル
elmTbl=objDoc.getElementsByTagName("table").item(15)	// もう一工夫したい

// Excel起動と初期処理
objExcel=CreateOLEObj("Excel.Application")
objExcel.Visible=TRUE
objSheet=objExcel.Workbooks.Add().ActiveSheet

// tableの項目名とデータをExcelへ
for r=0 to elmTbl.rows.length-1
	for c=0 to elmTbl.rows(r).cells.length-1
		objSheet.Cells(r+1, c+1).Value=elmTbl.rows(r).cells(c).innerText
	next
next

// Excel の見映えを整える
MaxRow=objSheet.Cells(objSheet.Rows.Count, 1).End(xlUp).Row
MaxCol=objSheet.Cells(1, objSheet.Columns.Count).End(xlToLeft).Column
celRD=objSheet.Cells(MaxRow, MaxCol)
objSheet.Range("A1", celRD).Columns.AutoFit

// スクリプトの終点

意図した結果になりました。Excel への出力結果を見ると、最上行と最下行は項目の行なので、検索対象から外すべきということが分かります。次に解答に進みます。

ところで下の記述は私の好みではありません。
elmTbl=objDoc.getElementsByTagName("table").item(15)
『item(15)』の数字の部分がひとつずれるだけで処理が崩壊するからです。ここも変更します。

////////////////////////////////////////
// IEのテーブルから指定条件の行をExcelへ書き出す。
////////////////////////////////////////
const xlUp		= (-4162)
const xlToLeft	= (-4159)
hashtbl hshItmSel

// IE起動と初期処理
objIe=CreateOLEObj("InternetExplorer.Application")
objIe.Visible=True
objIe.Navigate("http://phonebook.yahoo.co.jp/a127/g117/g20078/g38910100/")
Sleep(0.5); repeat; Sleep(0.2); until (! objIe.busy) and (objIe.readyState=4); Sleep(0.5)
objDoc=objIe.document

// 取得対象テーブルの特定
blnF=FALSE
for i=0 to objDoc.getElementsByTagName("table").length-1
	elmTbl=objDoc.getElementsByTagName("table").item(i)
	ifb "名称  "=elmTbl.rows(0).cells(0).innerText
		blnF=TRUE; break
	endif
next
ifb !blnF; msgbox("HTMLの構造が変わりました。"); exitexit; endif

// 電話番号選択
for r=1 to elmTbl.rows.length-2			// 項目行は除外
	hshItmSel[r]=elmTbl.rows(r).cells(1).innerText	// 電話番号
next
strItmSel=SLCTBOX(SLCT_BTN or SLCT_STR, 0, "選んでね", hshItmSel, "選択中止")
ifb "選択中止"=strItmSel or (-1)=strItmSel
	msgbox("選択中止が選ばれました。")
	objIe.quit; objIe=NOTHING
	exitexit
endif

// Excel起動と初期処理
objExcel=CreateOLEObj("Excel.Application")
objExcel.Visible=TRUE
objSheet=objExcel.Workbooks.Add().ActiveSheet

// テーブルを検索して、マッチする行をExcelへ
cntR=0
for r=1 to elmTbl.rows.length-2			// 項目行は除外
	ifb strItmSel=elmTbl.rows(r).cells(1).innerText	// 抽出の条件
		cntR=cntR+1
		for c=0 to elmTbl.rows(r).cells.length-1
			objSheet.Cells(cntR, c+1).Value=elmTbl.rows(r).cells(c).innerText
		next
		break
	endif
next

// Excel の見映えを整える
MaxRow=objSheet.Cells(objSheet.Rows.Count, 1).End(xlUp).Row
MaxCol=objSheet.Cells(1, objSheet.Columns.Count).End(xlToLeft).Column
celRD=objSheet.Cells(MaxRow, MaxCol)
objSheet.Range("A1", celRD).Columns.AutoFit

// スクリプトの終点

[参考文献]
MSDN - DHTML リファレンス - TABLEオブジェクト
MSDN - DHTML リファレンス - rowsコレクション
MSDN - DHTML リファレンス - cellsコレクション
Document Object Model - 3. TABLE
UWSC掲示板 - テーブルの値取得ができません (2006/10/31(Tue) 02:59 No.349)
UWSC掲示板 - TABLE中の要素にアクセスする方法 (2008/2/16(Sat) 17:42 No.1468)


2008/2/17(眠)

いりやさんから、本稿についてご指摘をいただきました。 眠たい詩人の掲示板 - table 要素へのアクセス方式
コレクションの同じ要素へのアクセスが複数回発生しているので、一回で済ませた方が処理速度が速いはずというご指摘と理解しました。それを受けて以下の変更を加えます。

// 変更前
for c=0 to elmTbl.rows(r).cells.length-1
	objSheet.Cells(cntR, c+1).Value=elmTbl.rows(r).cells(c).innerText
next

  ↓
// 変更後
objRow=elmTbl.rows(r)
for c=0 to objRow.cells.length-1
	objSheet.Cells(cntR, c+1).Value=objRow.cells(c).innerText
next

2008/3/3(眠)

掲示板の屑回答者?

UWSC 掲示板で紹介されていた、教えて君と屑回答者 は、おもしろかったです。うなずける面と耳が痛い面が在りました。

<<< 『教えて君と屑回答者』より引用はじめ >>>
自発的な回答は快楽を伴う自慰行為でもあります。
<<< 『教えて君と屑回答者』より引用おわり >>>

なるほど。自慰行為だとすれば、専ら自分のサイトだけで自慰に徹した方が無難かもしれませんね。
2008/2/20(眠)

指定フォルダ以外のフォルダを移動

お願いします (2008/3/7(Fri) 23:45 No.1534)

[投稿要旨]
DATAというフォルダに『file処理済』と『OI30050229』いうフォルダがあります。 file処理済は固定の名前で、『OI30050229』は処理をする度にフォルダ名が変わってきます。 『OI30050229』をfile処理済フォルダに入れようしていますが、 『OI30050229』のフォルダ名が毎回変わってしまうと対応できません。

要はフォルダ移動。OS の move コマンドが使えます。

// 指定フォルダ以外のフォルダを移動
// UWSC V4.41 | WinXP Home SP2
親フォルダ="C:\data"
子フォルダ転送先="file処理済"
for i=0 to GETDIR(親フォルダ, "\")-1
	子フォルダ転送元=GETDIR_FILES[i]
	if 子フォルダ転送先=子フォルダ転送元 then continue
	doscmd("move /y <#dbl>"+親フォルダ+"\"+子フォルダ転送元+"<#dbl> "+親フォルダ+"\"_
		+子フォルダ転送先+"\", true)
next

move コマンドの使用方法は、コマンドプロンプトを起動して『move /?』。

2008/03/10(眠)

連想配列で、重複不許可のランダムな数値を生成

一生のお願い (2008/3/28(Fri) 05:38 No.1586)

[投稿要旨]
5桁の数字00000〜99999までのIDをランダムで作りたいのです。 数字の重複が無いIDを求めています。

重複不許可の処理は連想配列を使うと楽にできます。

hashtbl hshNum
桁数=5
repeat
	strNum=RANDOM(10)
	if hshNum[strNum, HASH_EXISTS] then continue
	hshNum[strNum]=""
until 桁数<=length(hshNum)
strings=""
for i=0 to length(hshNum)-1
	strings=strings+hshNum[i, HASH_KEY]
next
msgbox(strings)

もうひとつ似た方法を紹介。

hashtbl hshNum
桁数=5
repeat
	hshNum[RANDOM(10)]=""
until 桁数<=length(hshNum)
strings=""
for i=0 to length(hshNum)-1
	strings=strings+hshNum[i, HASH_KEY]
next
msgbox(strings)

後者のスクリプトは、明示的に重複検査は行っていませんが、同じ結果となるはずです。連想配列のキーは、重複不許可であるという特徴を利用しています。 私の好みは、スクリプトコードが簡潔な後者です。ただし、速度の点でどちらかが優れているとしたら、速度優先としたいですね。気が向いたら、速度検証をすることが望ましいです。

2008/03/31(眠)

『プログラムの追加と削除』を自動操作

番外編です。教えてgoo!で『プログラムの追加と削除』から、アプリの削除を自動化したいという質問投稿があり、回答として、UWSC が紹介されていました。これに興味を惹かれて、次のテーマに取り組んでみます。

[お題]
『プログラムの追加と削除』の窓に表示されるアプリの中から特定のアプリを選択し、削除を行うボタンをクリックする。

  • 小手調べとして、拙作スクリプト『UWSCコードの断片生成器』を『プログラムの追加と削除』に対して当てて見たら、良好。clkitem()関数でアプリ選択ができそう。
  • しかし、実際にアプリの選択をclkitem()関数で行うと戻り値はTRUE(正常)が返るが、クリックされない。のみならず、指定したアプリが選択状態にもならない。『CLK_ACC or CLK_MUSMOVE or CLK_LEFTCLK』などを指定しても×。
  • そこで『↓』キーを複数回押して、指定したアプリが選択状態になるまで続けるという方法を検討。
  • 選択状態のアプリを取得することが、UWSCの関数では困難なのでこれも×。
★結論としては、以下のロジックに落ち着いた。
  1. 『プログラムの追加と削除』の窓に表示されるすべてのアプリを上から表示順に取得。配列に格納。
  2. 指定アプリが上から何番目かを取得。
  3. 『↓』キーを複数回押す。
  4. (2)を参考にして、理論的に指定アプリが選択行になったら、(3)をやめる。
  5. 『追加と削除』ボタンまたは、『削除』ボタンを押す。
  6. →『削除の確認メッセージ(Y/N)』が表示されたら、成功。
(手操作で『N』を選ぶ)

これをスクリプトコードに変換し、効率化したものを載せます。効率化により、配列は不要となりました。
// 『プログラムの追加と削除』で指定アプリの削除の初動まで
// UWSC V4.424 | WinXP Home SP2
strPrgName="UWSC Pro 4.4b"
dim aryExtWords[]="プログラムの"+chr(10)+"変更と削除","プログラムの"+chr(10)+"追加",_
	+"Windows"+chr(10)+"コンポーネントの"+chr(10)+"追加と削除","プログラムの"+chr(10)_
	+"アクセスと"+chr(10)+"既定の設定","更新プログラムの表示","開く","名前","サイズ",_
	"使用頻度","最終使用日","変更","削除"

doscmd("appwiz.cpl", TRUE)
id=getid("プログラムの追加と削除","NativeHWNDHost")
repeat; sleep(0.1); until clkitem(id,strPrgName,CLK_ACC,FALSE)
sleep(0.5)								// いらないかも
for i=0 to getitem(id,ITM_ACCCLK,-1)-1
	strApName=ALL_ITEM_LIST[i]
	for j=0 to length(aryExtWords)-1
		if aryExtWords[j]=strApName then continue 2
	next
	if strApName=strPrgName then break	// ターゲットが反転表示(のはず)なのでもう下げない
	sckey(id, VK_DOWN)					// 反転表示の行を下げる
next
// clkitem(id,"削除",CLK_ACC or CLK_SHORT) が何故か無効。
ret=clkitem(id,"削除",CLK_ACC)
if !ret	then clkitem(id,"変更と削除",CLK_ACC)
とりあえず、10回程度試して、毎回意図した動作になりました。しかしながら、このロジックで組んだスクリプトを世に配布するのは、厳しいです。sckey()がカラ振りしたらアウトだし、指定アプリが本当に選択されたかを確認していないからです。バグったら、他のアプリを消してしまう恐れがあるからです。
配布するなら、初めから指定アプリのアンインストールプログラムを起動する方法を採りたいものです。
2008/05/28(眠)

MACアドレスの取得(PowerShell版,VBScript版)

UWSC 掲示板 2855 にて、MACアドレスの取り出しがUWSC では1行で書けることにふれて、『はたしてどれだけの言語がこの処理を1行で書けるだろうか?』というくだりがありました。 UWSC が便利な点は同意。しかし本当に他言語で同処理が1行で書けないのか? という点にこだわってみます。 他言語といっても私がそこそこ使えるのは、UWSC と VBScript。その他には最近取り組んでいるのが、PowerShell。PowerShell は多用なパイプ処理があり1行でいろんなことが出来そうです。 さっそくMACアドレスの取得の1行記述にPowerShellで挑戦しました。以外にあっさりとできました。
# MACアドレスの表示 ; PowerShell V2.0 | WindowsXP Pro Sp3
([string](ipconfig /all)).SubString(497,17)
ついでに VBScriptでも書いて見ました。頭の体操になりおもしろかったです。しかし美しくはありません。
' MACアドレスの表示 ; VBScript 5.6 | WindowsXP Pro Sp3
msgbox Mid(CreateObject("WScript.Shell").Exec("ipconfig /all").StdOut.Readall,511,18)
どの言語が便利かは好みもあると思いし、どれかひとつに絞る必要もないので、用途で使い分けることになりそうです。PowerShell は、処理速度が難点です。速度が改善されれば活用の機会が増えそうです。何より、OSに標準装備という利点は大きいです。

[参考]
UWSC 掲示板 2855 - IP/MACアドレスに関するつぶやき
フィールドSEあがりの安納です : 【PowerShell】$result = ipconfig /all これは便利!
2010/02/20(眠)

unDonut の COM 操作

IE系プラウザの unDonut の COM 操作は、Sleipnir と似ています。
// 準備
// (1)[必須](unDonut の setup.exe起動)[unDonut セットアップ・プログラム] - [COMサーバー] - [ON] を選択しておく。
// (2)[任意](unDonut.exe起動)[Donutのオプション] - [確認ダイアログ] - [スクリプト機能を使用するとき]のチェックを外しておく。
// unDonut1.uws
//『UWSC』を検索語としてGoogleで検索し、『UWSC』を含むリンク文字列を選んで表示
option explicit
dim objIE,objDonutP,objSh
dim strUndonutExe
dim strWord="UWSC"

exec("D:\Prg\unDonut\unDonut.exe")
objDonutP=CreateOLEObj("DonutP.API")
objDonutP.NewWindow("http://www.google.co.jp/",TRUE)
objIE=objDonutP.GetWebBrowserObject(objDonutP.TabIndex)
// ここからはIEの操作と同様
BusyWait(objIE)
IESetData(objIE,strWord,"q")
IESetData(objIE,True,"btnG","Google 検索")
BusyWait(objIE)
IELink(objIE,strWord)
BusyWait(objIE)

//------
Procedure BusyWait(ie)
    Sleep(0.5); repeat; Sleep(0.2); until (! ie.busy) and (ie.readyState=4); Sleep(0.5)
Fend
ブラウザが起動していないときに、UWSC の CreateOLEObj("DonutP.API") を行っても、ブラウザは起動しませんでした。事前に unDonut.exe を起動したら、意図した挙動でした。Sleipnir V1.xx と同じパターンです。 DonutP.API の GetWebBrowserObjectメソッドで IE オブジェクトを取得することで、UWSC のIE系関数が使える点も Sleipnir.API と同じです。 上に掲載のスクリプトでも基本機能は満たしていますが、使用環境が変わると、unDonut.exe のパスを書き換えないといけないのが不本意。 そこで、unDonut.exe のフルパスをレジストリから取得できないか、という観点でレジストリを探ったら、分かりました。45分を費やしました。
// getExeFulPath.uws
// COMオブシェクト名に対応する実行形式ファイルをフルパスで取得
strComObj="DonutP.API"
objSh=CreateOLEObj("WScript.Shell")
strClass=betweenstr(objSh.RegRead("HKLM\SOFTWARE\Classes\"+strComObj+"\CLSID\"),"{","}")
strExe=objSh.RegRead("HKLM\SOFTWARE\Classes\CLSID\{"+strClass+"}\LocalServer32\")
msgbox(strExe)
上で取得している箇所は、準備(1)を行ったときに、レジストリに書かれていました。この技は汎用性があります。DonutP.API の代わりに Excel.Application や InternetExplorer.Application を指定しても意図した結果が得られました。
getExeFulPath.uws の処理を unDonut1.uws に 追加すれば完成です。
// unDonut2.uws
//『UWSC』を検索語としてGoogleで検索し、『UWSC』を含むリンク文字列を選んで表示
// unDonut release12d | IE 8.0.6001.18702 0 | UWSC V4.6 | WinXP Professional SP3
option explicit
dim objIE,objDonutP,objSh
dim strUndonutExe,strClass
dim strWord="UWSC"

objSh=CreateOLEObj("WScript.Shell")
strClass=betweenstr(objSh.RegRead("HKLM\SOFTWARE\Classes\DonutP.API\CLSID\"),"{","}")
strUndonutExe=objSh.RegRead("HKLM\SOFTWARE\Classes\CLSID\{"+strClass+"}\LocalServer32\")
ifb !fopen(strUndonutExe,F_EXISTS)
	msgbox(strUndonutExe+" が見つかりません。"); exitexit
endif
exec(strUndonutExe)
objDonutP=CreateOLEObj("DonutP.API")
objDonutP.NewWindow("http://www.google.co.jp/",TRUE)
objIE=objDonutP.GetWebBrowserObject(objDonutP.TabIndex)
BusyWait(objIE)
IESetData(objIE,strWord,"q")
IESetData(objIE,True,"btnG","Google 検索")
BusyWait(objIE)
IELink(objIE,strWord)
BusyWait(objIE)

//------
Procedure BusyWait(ie)
    Sleep(0.5); repeat; Sleep(0.2); until (! ie.busy) and (ie.readyState=4); Sleep(0.5)
Fend
[参考文献]
unDonutダウンロード
スクリプト実例・各種スクリプトでブラウザを操作
UWSC 掲示板 2937 - 任意ブラウザによる特定語句の含まれるURLの抽出
DonutP.API のリファレンスは、unDonut.exe に同梱されている Function.txt に記載されています。
2010/03/25(眠)

画像ファイルの幅と高さを取得

画像ファイルの幅と高さを取得する方法として、GetDetailsOfメソッドがありますが、画像の幅と高さの項目はWinXP 以降にしかないし、OSによって項目の番号が異なるので、取り扱いが面倒です。追加ソフト不要で、かつ、Windows7 と WindowsXP で取り扱いが同じものがないかを探したら、ありました。 VBScript の LoadPicture 関数です。
// Script Start
//
// UWSC V4.62
// Win7 / Win Vista / WinXP / Win2000

// 画像ファイルの幅と高さを表示する
// カレント(当スクリプトと同じ場所)に「a.bmp」を置いておく
strFile=GET_CUR_DIR+"\a.bmp"
ifb !fopen(strFile,F_EXISTS)
	msgbox("ファイル "+strFile+" が見つかりません。"); exitexit
endif
objSc=CreateOleObj("ScriptControl")
objSc.language="VBScript"
objSc.AddCode(VbSrc)
height=objSc.Run("getSizImg", strFile)
width=token("_",height)
msgbox(width+"x"+height)

/////
TEXTBLOCK VbSrc
FUNCTION getSizImg(strFile)
	set objPic = loadpicture(strFile)
	width=CLng(CDbl(objPic.Width) * 24 / 635)
	height=CLng(CDbl(objPic.Height) * 24 / 635)
	set objPic = NOTHING
	getSizImg = width & "_" & height
end FUNCTION
endTEXTBLOCK

// End of Script
Windows98 と WindowsME では動作しませんが、Windows Script Controlをインストールすれば動作するかも。(未検証)

[参考]
UWSC 掲示板 3256 - 画像サイズの取得
MSDN - LoadPicture 関数
VBScript で画像ファイルの画像の大きさを取得する (unibon)
Folder.GetDetailsOf Method
Hey, Scripting Guy! - Windows Media Player を使用せずに画像ファイルの高さと幅を知る方法はありますか
Hey, Scripting Guy! - .JPG ファイルの縦と横のサイズを表示する方法はありますか
2010/10/17(眠)
←トップページのカウンタと共通です。