047501 ランダム
 ホーム | 日記 | プロフィール 【フォローする】 【ログイン】

satocchiaブログ

PR

キーワードサーチ

▼キーワード検索

プロフィール


satocchia

カレンダー

お気に入りブログ

まだ登録されていません

コメント新着

わたなべ@ Re:powershellコンソール、見づらくありませんか?(08/26) 初めまして、この情報最高です! 背景を白…
y__@ Re:uwscでGUIフォーム(05/12) UWSC 仮掲示板から飛んできました。 HTAで…
satocchia@ Re[1]:キー同時読み込み(12/25) せりあさんへ 上の追記のとおりです。得…
せりあ@ Re:キー同時読み込み(12/25) uwscの掲示板からきました。haiの配列をha…
satocchia@ Re:最短一致の落とし穴(04/26) こいうときは [/][^/]+?$ とやればよい

フリーページ

ニューストピックス

2018.02.07
XML
カテゴリ:powershell
powershellでIE操作しようとすると、私の環境では、DOMがまともに取り扱えません。
Microsoft.mshtml のアンセンブリがないためらしく、MS officeをインストールする必要があるのだとか。​参考
そこで対策。

ie.ps1

#IEオートメーションを扱う際、microsoht.mshtml.dllが適切にインストールされていないシステムでは、
#ドキュメントノードやエレメントのメソッドを呼び出す際、いちいちSystem.__ComObjectを介して
#間接的にメソッドを呼ばなければならない。書式は複雑で手順も煩雑なため、IE操作のための関数を用意した。
# IEの動作関係
# openURL WaitIE WaitForElement IeActivate 
# System.__ComObjectを介するメソッド呼び出し
# invokeComMethod 
# Dom要素取得
# querySelectorAll querySelector getElementById 
# getElementsByName getElementsByTagName getElementsByClassName
# Windowオブジェクトのpowershellから$ie.Document.parentWindowが取得できないのでWindow配下の
# メソッド呼び出し・プロパティ読み書きを行う関数も用意する。
# windowMethod windowProperty
# 参考サイト https://qiita.com/voidProc/items/b3037ccb31676b27ceba
##################################################################
#URLを開く
function openURL( $url, $visible=$false ){
    #IEオブジェクトの取得
    try{
        [Microsoft.VisualBasic.Interaction]::GetObject|out-null
    } catch {
        [reflection.assembly]::LoadWithPartialName("'Microsoft.VisualBasic")|out-null
    }
    try{
    #ieが起動していればそのオブジェクトを取得
        $ie =[Microsoft.VisualBasic.Interaction]::GetObject( "","InternetExplorer.Application" )
    } catch {
    #ieオブジェクトを生成
        $ie =new-object -com "InternetExplorer.Application"
    }
    $ie.Visible=$visible
    $ie.Navigate( $url )
    return $ie
}
# IEのページ読み込みが完了するまで待機する
function WaitIE( $ie, $OkSeconds=0.5 ){
    # ビジーでない状態が$OkSeconds秒継続したら読み込み終わったと判断する
    $limit =( get-date ).AddSeconds( $OkSeconds )
    do{
        if (($ie.Busy) -or ( $ie.ReadyState -ne 4 )){
            $limit =( get-date ).AddSeconds( $OkSeconds )
        }
        sleep -m 100
    }while( ( get-date ).CompareTo( $limit ) -lt 0 )
}
# 要素の出現を待つ(要素はCSSセレクタで指定)
function WaitForElement( $ie, [string]$selector ){
    WaitIE $ie
    while( $true ){
        try{
            if ( $e=(querySelector $ie.Document $selector) ){
                break
            }
        }catch{[void]"err"}
        [void]"Loop"
    }
}
# このままで動くが、動作が不安定
function _IeActivate{
    #VB.NETのアセンブリを呼んでおく
    try{
        [void][Microsoft.VisualBasic.Interaction]    
    }catch{
        Add-Type -AssemblyName "Microsoft.VisualBasic"
    }
    ps iexplore|%{
        [Microsoft.VisualBasic.Interaction]::AppActivate($_.id)
        #ウエイトがないとアクティベートされないらしい。
        sleep -m 200
    }
}
# IEウインドウをアクティブにする
# 
function IeActivate( $ie ){
    windowMethod $ie "focus"
}
#####################Windowオブジェクト対策
#windowオブジェクト配下のメソッド呼び出し
function windowMethod{
    $ie =$args[0]
    $methodName =$args[1]
    $others =if ( ($len=$args.length) -gt 2 ){
        $args[2..($len-1)]
    } else {
        $null
    }
    $sc=new-object -com scriptcontrol
    $sc.language="vbscript"
    $sc.addobject("ie",$ie)
    $statement ="ie.document.parentwindow.$methodName(${others})"
    #"$statement"
    $sc.executestatement( $statement )
}
#ウインドウのプロパティの取得と代入 
#  取得  windowProperty $ie "location.Href"
#  代入  windowProperty $ie "location.Href" "https://www.infoseek.co.jp/"
function windowProperty{
    $ie =$args[0]
    $PropertyName =$args[1]
    $sc =new-object -com scriptcontrol
    $sc.language ="vbscript"
    $sc.addobject("ie",$ie)
    $statement ="ie.document.parentwindow.$PropertyName"
    #引数に二つ目があれば代入
    if ( $val=$args[2] ){
        $assignExpression ="$statement = `"$val`""
        $sc.executestatement( $assignExpression )
        return $val
    } else {
        return $sc.eval( $statement )
    }
}
#####################Com上のメソッド呼び出し
#function invokeComMethod( $obj, $methodName ){
#    return [System.__ComObject].InvokeMember( $methodName, [System.Reflection.BindingFlags]::InvokeMethod, $null, $obj, $args )
#}
#引数が上の呼び方だと、動かないことがある。
#動かない例:invokeComMethod $親要素 "appendChild" $子ノード
#動かない例:二重の関数 function elementMethod( $elem, $method ){ invokeComMethod $elem $method }
function invokeComMethod{
    $obj =$args[0]
    $methodName =$args[1]
    $others =if ( ($len=$args.length) -gt 2 ){
        $args[2..($len-1)]
    } else {
        $null
    }
    return [System.__ComObject].InvokeMember( $methodName, [System.Reflection.BindingFlags]::InvokeMethod, $null, $obj, $others )
}
#########################以下Dom操作
# CSSセレクタでノードを得る(複数ノード)
function querySelectorAll($node, [string]$selector){
#どういうわけかinvokeComMethodで呼ぶとIEが落ちる
    $nodes = [System.__ComObject].InvokeMember("querySelectorAll", [System.Reflection.BindingFlags]::InvokeMethod, $null, $node, $selector)
    #$nodes =invokeComMethod $node "querySelectorAll" $selector
    #どういうわけか配列のままリターンするとIEが落ちる
    #return $nodes ではダメ
    $result = New-Object System.Collections.Generic.List[System.__ComObject]
    for ($i = 0; $i -lt $nodes.Length; $i++) {
        $result.Add([System.__ComObject].InvokeMember("item", [System.Reflection.BindingFlags]::InvokeMethod, $null, $nodes, $i))
    }
    $result
}
# CSSセレクタでノードを得る
function querySelector($node, [string]$selector){
    return invokeComMethod $node "querySelector" $selector
}
function GetElementById( $node, [string]$ID ){
    return invokeComMethod $node "getElementById" $ID
}
#どういうわけかこちらは配列のままでOK。むしろ、queryselectorAllと同様にすると動かない。以下同様
function GetElementsByName( $node, [string]$NAME ){
    return invokeComMethod $node "getElementsByName" $NAME
}
function GetElementsByTagName( $node, [string]$TagName ){
    return invokeComMethod $node "getElementsByTagName" $TagName
}
function GetElementsByClassName( $node, [string]$ClassName ){
    return invokeComMethod $node "getElementsByClassName" $ClassName
}
#########################テストプログラム
if ( $myInvocation.InvocationName -like "*\ie.ps1" ){
    # (1)Googleの検索結果一覧を取得してみる
    $ie =OpenUrl "https://www.google.co.jp/search?q=test"
    WaitIE $ie
    WaitForElement $ie "h3.r a"
    "LOADED"
    $links = querySelectorAll $ie.Document "h3.r a"
    $links | % { $_.innerText }
    "-----------------------"
    # (2)別のキーワードで検索してみる
    $text = querySelector $ie.Document "#lst-ib"
    $text.Value = "google"
    $btn =  querySelector $ie.Document "#_fZl"
    $btn.click()
    WaitIE $ie
    "-----------------------"
    $keyword =getElementById $ie.Document "lst-ib"
    $keyword.Value
    "-----------------------"
    #dom操作を試みる
    $ie =OpenUrl "about:blank"
    WaitIE $ie
    $doc=$ie.document
    $body=getElementsByTagName $doc "body"
    #HTMLを直接書き込む
    $body.innerHTML=@"
<div>
<input type="radio" name="rd" value="1">a
<input type="radio" name="rd" value="2">b
<input type="radio" name="rd" value="3">c
</div>
"@
    #Dom操作でラジオボタンを追加
    $radio_div =(getElementsByName $doc "rd")[0].parentNode
    $radio_d =invokeComMethod $doc "createElement" "input"
    invokeComMethod $radio_d "setAttribute" "type" "radio"|out-null
    invokeComMethod $radio_d "setAttribute" "name" "rd"|out-null
    invokeComMethod $radio_div "appendChild" $radio_d|out-null
    $radio_txt_d=invokeComMethod $doc "createTextNode" "d"
    invokeComMethod $radio_div "appendChild" $radio_txt_d|out-null
    $ie.Visible = $true
    IeActivate $ie
    sleep 2
    #Dom操作でラジオボタンをチェック
    $radios =getElementsByName $doc "rd"
    $radio=$radios[1]
    invokeComMethod $radio "setAttribute" "checked"|out-null
    sleep 4
    $ie.Visible = $false
    #Windowを消してアラート表示
    windowMethod $ie "alert" "`"aaa`""
    #Windowプロパティ取得
    windowProperty $ie "location.Href"
    #Windowプロパティ代入
    windowProperty $ie "location.Href" "https://www.infoseek.co.jp/"
    WaitIE $ie
    $ie.Visible = $true
    IeActivate $ie
}






最終更新日  2018.02.07 02:59:45
コメント(0) | コメントを書く
[powershell] カテゴリの最新記事

Copyright (c) 1997-2019 Rakuten, Inc. All Rights Reserved.