none
COMのHTMLFileでgetElementsByClassNameが使えなくなった。 RRS feed

  • 質問

  • WScriptで下記のように、HTMLFileオブジェクトを生成してHTMLパースを実施し、getElementsByClassNameを利用して、要素を取得していました。

    var doc = new ActiveXObject("HTMLFile");

    しかしながら、2021/2/10ぐらいにWindowsがアップデートされてからエラーが出るようになりました。

    エラー的にgetElementsByClassNameが存在しないような感じだったので、PowerShellを開いて下記のように実行し、mshtml.HTMLDocumentClassの要素を確認してみました。

    $com = New-Object -ComObject HTMLFile

    $com|Get-Member


    確認してみると、IHTMLDocument5の要素までしか存在せず、IHTMLDocument8がありませんでした。(Get系の関数は下記だけでした。)

    getElementById                                      Method     mshtml.IHTMLElement, Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a getElementById(string v), mshtml.IHTMLElement, Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a DispHTML...

    getElementsByName                                   Method     mshtml.IHTMLElementCollection, Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a getElementsByName(string v), mshtml.IHTMLElementCollection, Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b0...

    getElementsByTagName                                Method     mshtml.IHTMLElementCollection, Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a getElementsByTagName(string v), mshtml.IHTMLElementCollection, Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken...

    GetHashCode                                         Method     int GetHashCode()

    GetLifetimeService                                  Method     System.Object GetLifetimeService()

    GetType                                             Method     type GetType()


    IHTMLDocument8まで使えるようにしたい場合どのようにすればいいでしょうか。

    もしくは、同様に使えるHTMLパーサーは何かあるでしょうか。

    よろしくお願いします。

    2021年2月24日 12:09

回答

  • documentModeというものを検索してみたのですが、変更の仕方がよく分りませんでした分りませんでした。

    以前はまとまった資料がいろいろあったのですが、今となっては、Web 上からも情報が失われつつありますね…。

    Web コンテンツの場合は、サーバー側で HTTPレスポンスヘッダ を指定するものですが、静的データの場合には、HTML コンテンツ内の meta タグでの指定となります。

    使ってるテキストのhtmlファイルは無いですよ。

    ファイルからでも良いですし、オンメモリでの書き込みでもよいので、 モード指定しましょう。

    検証用コード。

    var doc = new ActiveXObject("HTMLFile");
    doc.write('');
    WScript.Echo('==== 指定なし ====');
    WScript.Echo('documentMode=>' + doc.documentMode);
    WScript.Echo('compatMode=>' + doc.compatMode);
    WScript.Echo('doctype=>' + doc.doctype);
    WScript.Echo('getElementsByClassName=>' + doc.getElementsByClassName);
    WScript.Echo('getElementsByName=>' + doc.getElementsByName);
    
    var lists = ['なし', '5', '7', 'EmulateIE7', '8', 'EmulateIE8', '9', 'EmulateIE9', '10', 'EmulateIE10', '11', 'EmulateIE11', 'Edge'];
    for(var i = 0; i < lists.length; i++) {
      var ie = lists[i];
    
      for (var j = 0; j <= 1; j++) {
        var docType = (j == 0) ? '' : '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';
        var meta = (ie == 'なし') ? '' : '<meta http-equiv="X-UA-Compatible" content="IE=' + ie + '">';
    
        WScript.Echo('==== 互換指定:' + ie + ' / DOCTYPE: ' + ((j==0) ? 'なし' : 'あり') + ' ====');
    
        doc = new ActiveXObject("HTMLFile");
        doc.write(docType + '<html><head>' + meta + '</head><body></body></html>');
        WScript.Echo('documentMode=>' + doc.documentMode);
        WScript.Echo('compatMode=>' + doc.compatMode);
        WScript.Echo('doctype=>' + doc.doctype);
        WScript.Echo('getElementsByClassName=>' + doc.getElementsByClassName);
        WScript.Echo('getElementsByName=>' + doc.getElementsByName);
      }
    }
    WScript.Quit();

    2021年2月27日 13:58
  • X-UA-Compatibleは最新のIEに対応していないページにつけるタグのように見えるのですが、何も指定されていないhtmlはIE11で読み込むようには出来ないのでしょうか。

    IE10までと違い。IE11からはデフォルトでdocumentModeは11になるように変更されています。ただしそれはInternet Explorerとしての挙動であって、COMオブジェクトの方は過去との互換もあり、一部異なる挙動をします。

    念のため、ドキュメント モードの選択のフローチャートを参照し、documentModeを変更する設定が含まれていないか確認してみてください。

    • Site list <emie> section(エンタープライズモードなので違う)
    • Site list <docMode> section(なんだっけ? でもたぶん違う)
    • X-UA-Compatible meta tag(今話題になっている)
    • X-UA-Compatible header(ウィンドウズスクリプトプログラマさんが少し触れた、たぶん違う)
    • Microsoft Compat View list(これも違う)
    • Group Policy for IE5 and IE7
    • Local Compat View list
    • Internet setting
    • !DOCTYPE declared(どっちにしろIE11モードになるので違う)

    HTMLFileの場合、直接ファイル生成していてURLがないという事情も踏まえると、このフローチャートのほとんどが該当しませんが、とはいえIE11モードでなくIE7モードに切り替える理由はこの中にあるかもしれません。

    • 回答としてマーク 毎日 2021年2月28日 14:25
    2021年2月27日 21:44
  • © ウィンドウズスクリプトプログラマ - Windows Script Programmer 2021

    <!DOCTYPE html>
    があると、7。なければ、5。みたい。

    有り無しでどう変わるかは、
    IE11 でドキュメントモードが選択されていることを示すフルサイズのフローチャート - Internet Explorer | Microsoft Docs  これに書いてあるのかも。ie11もhtmlfileも似たようなものでしょう。

    そういう話になると、Msdn フォーラム - Internet Explorer で聞いて。
    2021年2月28日 2:11
  • ご回答ありがとうございます。

    ウィンドウズスクリプトプログラマさんのコードと 魔界の仮面弁士さんのコメントを見て、下記のようなファイルを作成してみました。

    test_getElementsByClassName.vbs

    set doc=wscript.getobject("test_get.html")
    msgbox "typename(doc): " & typename(doc)
    msgbox "doc.documentMode: " & doc.documentMode
    msgbox doc.getElementsByClassName("gettest").item(2).innerHtml

    test_get.html

    <!DOCTYPE html>
    <html lang="pl">
    	<head>
    		<title>get test page</title>
    		<meta http-equiv="X-UA-Compatible" content="IE=11" >
    	</head>
    	<body>
    		<div class="gettest">項目1</div>
    		<div>項目2</div>
    		<div class="gettest">項目3</div>
    		<div class="gettest">項目4</div>
    	</body>
    </html>


    実行してみると、確かに「doc.documentMode: 11」と表示され、getElementsByClassNameも問題なく実行されました。

    また、以前うまく取得できなかったページもVBScript.RegExpでheadタグを下記のように書き換えてやると、documentMode 11として実行出来ました。

    <head><meta http-equiv="X-UA-Compatible" content="IE=11" ></head>

    一点気になったのですが、test_get.htmlからmetaタグを削除すると、documentModeは7と表示されるようになりました。
    X-UA-Compatibleは最新のIEに対応していないページにつけるタグのように見えるのですが、何も指定されていないhtmlはIE11で読み込むようには出来ないのでしょうか。





    • 編集済み 毎日 2021年2月28日 7:12
    • 回答としてマーク 毎日 2021年2月28日 14:25
    2021年2月27日 18:56

すべての返信

  • © ウィンドウズスクリプトプログラマ - Windows Script Programmer 2021
    デフォルトのdocumentModeが5のせいなのでは。

    <meta http-equiv="X-UA-Compatible" content="IE=11" >
    だと、あります。
    2021年2月26日 0:56
  • 回答ありがとうございます。

    > デフォルトのdocumentModeが5のせいなのでは。

    > <meta http-equiv="X-UA-Compatible" content="IE=11" >
    > だと、あります。

    documentModeというものを検索してみたのですが、変更の仕方がよく分りませんでした分りませんでした。

    どこから変更すればいいのでしょうか。

    よろしくお願いします。

    2021年2月26日 13:13
  • © ウィンドウズスクリプトプログラマ - Windows Script Programmer 2021


    ヘッダか、同等の<meta>


    <meta http-equiv="X-UA-Compatible" content="IE=11" >
    です。

    2021年2月26日 13:58
  • 使ってるテキストのhtmlファイルは無いですよ。

    PowerShellで下記コマンドを打ち込んで、HTMLFILEオブジェクトのメンバー関数を確認しているだけなので。

    $com = New-Object -ComObject HTMLFile

    $com|Get-Member

     ウィンドウズスクリプトプログラマさんは、どのような操作をされて確認をされたのでしょうか。

    2021年2月27日 12:02
  • © ウィンドウズスクリプトプログラマ - Windows Script Programmer 2021


    vbsですが、


    set doc=wscript.getobject("C:\    \a.htm")
    msgbox typename(doc)
    msgbox doc.documentMode
    msgbox doc.getElementsByClassName("a")



    2021年2月27日 13:09
  • documentModeというものを検索してみたのですが、変更の仕方がよく分りませんでした分りませんでした。

    以前はまとまった資料がいろいろあったのですが、今となっては、Web 上からも情報が失われつつありますね…。

    Web コンテンツの場合は、サーバー側で HTTPレスポンスヘッダ を指定するものですが、静的データの場合には、HTML コンテンツ内の meta タグでの指定となります。

    使ってるテキストのhtmlファイルは無いですよ。

    ファイルからでも良いですし、オンメモリでの書き込みでもよいので、 モード指定しましょう。

    検証用コード。

    var doc = new ActiveXObject("HTMLFile");
    doc.write('');
    WScript.Echo('==== 指定なし ====');
    WScript.Echo('documentMode=>' + doc.documentMode);
    WScript.Echo('compatMode=>' + doc.compatMode);
    WScript.Echo('doctype=>' + doc.doctype);
    WScript.Echo('getElementsByClassName=>' + doc.getElementsByClassName);
    WScript.Echo('getElementsByName=>' + doc.getElementsByName);
    
    var lists = ['なし', '5', '7', 'EmulateIE7', '8', 'EmulateIE8', '9', 'EmulateIE9', '10', 'EmulateIE10', '11', 'EmulateIE11', 'Edge'];
    for(var i = 0; i < lists.length; i++) {
      var ie = lists[i];
    
      for (var j = 0; j <= 1; j++) {
        var docType = (j == 0) ? '' : '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';
        var meta = (ie == 'なし') ? '' : '<meta http-equiv="X-UA-Compatible" content="IE=' + ie + '">';
    
        WScript.Echo('==== 互換指定:' + ie + ' / DOCTYPE: ' + ((j==0) ? 'なし' : 'あり') + ' ====');
    
        doc = new ActiveXObject("HTMLFile");
        doc.write(docType + '<html><head>' + meta + '</head><body></body></html>');
        WScript.Echo('documentMode=>' + doc.documentMode);
        WScript.Echo('compatMode=>' + doc.compatMode);
        WScript.Echo('doctype=>' + doc.doctype);
        WScript.Echo('getElementsByClassName=>' + doc.getElementsByClassName);
        WScript.Echo('getElementsByName=>' + doc.getElementsByName);
      }
    }
    WScript.Quit();

    2021年2月27日 13:58
  • ご回答ありがとうございます。

    ウィンドウズスクリプトプログラマさんのコードと 魔界の仮面弁士さんのコメントを見て、下記のようなファイルを作成してみました。

    test_getElementsByClassName.vbs

    set doc=wscript.getobject("test_get.html")
    msgbox "typename(doc): " & typename(doc)
    msgbox "doc.documentMode: " & doc.documentMode
    msgbox doc.getElementsByClassName("gettest").item(2).innerHtml

    test_get.html

    <!DOCTYPE html>
    <html lang="pl">
    	<head>
    		<title>get test page</title>
    		<meta http-equiv="X-UA-Compatible" content="IE=11" >
    	</head>
    	<body>
    		<div class="gettest">項目1</div>
    		<div>項目2</div>
    		<div class="gettest">項目3</div>
    		<div class="gettest">項目4</div>
    	</body>
    </html>


    実行してみると、確かに「doc.documentMode: 11」と表示され、getElementsByClassNameも問題なく実行されました。

    また、以前うまく取得できなかったページもVBScript.RegExpでheadタグを下記のように書き換えてやると、documentMode 11として実行出来ました。

    <head><meta http-equiv="X-UA-Compatible" content="IE=11" ></head>

    一点気になったのですが、test_get.htmlからmetaタグを削除すると、documentModeは7と表示されるようになりました。
    X-UA-Compatibleは最新のIEに対応していないページにつけるタグのように見えるのですが、何も指定されていないhtmlはIE11で読み込むようには出来ないのでしょうか。





    • 編集済み 毎日 2021年2月28日 7:12
    • 回答としてマーク 毎日 2021年2月28日 14:25
    2021年2月27日 18:56
  • X-UA-Compatibleは最新のIEに対応していないページにつけるタグのように見えるのですが、何も指定されていないhtmlはIE11で読み込むようには出来ないのでしょうか。

    IE10までと違い。IE11からはデフォルトでdocumentModeは11になるように変更されています。ただしそれはInternet Explorerとしての挙動であって、COMオブジェクトの方は過去との互換もあり、一部異なる挙動をします。

    念のため、ドキュメント モードの選択のフローチャートを参照し、documentModeを変更する設定が含まれていないか確認してみてください。

    • Site list <emie> section(エンタープライズモードなので違う)
    • Site list <docMode> section(なんだっけ? でもたぶん違う)
    • X-UA-Compatible meta tag(今話題になっている)
    • X-UA-Compatible header(ウィンドウズスクリプトプログラマさんが少し触れた、たぶん違う)
    • Microsoft Compat View list(これも違う)
    • Group Policy for IE5 and IE7
    • Local Compat View list
    • Internet setting
    • !DOCTYPE declared(どっちにしろIE11モードになるので違う)

    HTMLFileの場合、直接ファイル生成していてURLがないという事情も踏まえると、このフローチャートのほとんどが該当しませんが、とはいえIE11モードでなくIE7モードに切り替える理由はこの中にあるかもしれません。

    • 回答としてマーク 毎日 2021年2月28日 14:25
    2021年2月27日 21:44
  • © ウィンドウズスクリプトプログラマ - Windows Script Programmer 2021

    <!DOCTYPE html>
    があると、7。なければ、5。みたい。

    有り無しでどう変わるかは、
    IE11 でドキュメントモードが選択されていることを示すフルサイズのフローチャート - Internet Explorer | Microsoft Docs  これに書いてあるのかも。ie11もhtmlfileも似たようなものでしょう。

    そういう話になると、Msdn フォーラム - Internet Explorer で聞いて。
    2021年2月28日 2:11
  • 皆さん、ご回答ありがとうございます。

    ツリーを見てみると、F12 tools docmodeoverrideが多分一番近そうですが、comオブジェクトに対して設定出来そうなものは見つけられませんでした、

    ひと先ず、読み込むHTMLソースにX-UA-Compatibleを追加することで対処しようと思います。

    ありがとうございました。

    2021年2月28日 14:25