Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2011年12月23日] [更新 2015年08月21日] Delphi サンプルプログラム集
   
941_ウェブページのテキスト入力とボタンクリック等
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) Pro + IE 11
941_IEObject_InputClick.zip [10,888 KB] 2015年08月21日版 (EXE 同梱)



  • 2012年02月24日
  • その他の項目の設定と取得と,JavaScript 関数の実行のサンプルを追加
  • 2013年03月20日
  • ファイルのアップロードのサンプルを追加




IE で表示しているウェブページの操作


IE (InternetExplorer) で表示しているウェブページに対する操作例のサンプルです.
ここではページにある入力欄に文字列やテキストを入力し,[送信] ボタンをクリックします.IE 用のインターフェイスを使用すれば,その他にもいろいろな操作が可能ですが,必要なインターフェイスを探し出すのは容易ではありません.MSDN の記事や,操作内容の英単語から想定して,MSHTML.pas 内を力ずくで調べていくしかないような気もします.

このページのサンプルでは,[タイプライブラリの取り込み] で説明している TShell コンポーネントを使用しています.必要であれば,この TShell コンポーネントをインストールしておいてください.
IE 7, IE 8 のようなタブ形式のブラウザでは,起動直後だけ操作が可能です.表示タブを切り換えて,再度対象のページのタブを表示して操作してもエラーとなります.
TShell を使用しないで IE を起動する方法,起動中の IE に接続する方法は,[940_TWebBrowser と IE] を参考にしてください.

なお,本ページのサンプルコードは全てフレームで構成されたウェブページには対応していません.フレームで構成されたページについては,[943_IE オブジェクトのイベントシンク] のコードを参考にしてください.

サイトあるいはページによっては,指定 URL 以外からの入力や操作を禁止する処理を行っている場合があります.その場合は,当然ですが,このページのサンプルは機能しないことになります.


以下のリンクは,HTML コードを操作する際に参考になるかも知れないサイトまたは記事です.





01_掲示板への文字列入力とボタンクリック -  name 属性使用


当サイトにテスト用の掲示板があります.この掲示板の入力欄に入力し,[送信する] ボタンをコードでクリックします.


図1
当サイトのテスト用掲示板

この掲示板のソースコードの入力とボタンクリックの部分は次のようになっています.HTML の操作部分のタグは多くの場合,form タグで囲まれた,input type と言うタグで定義されています.また,多くの場合,name や id 属性が定義されています.


  <td nowrap><b>おなまえ</b></td>
  <td><input type="text" name="name" id="id_name" size="28" value=""></td>

  <td nowrap><b>Eメール</b></td>
  <td><input type="text" name="email" id="id_email" size="28" value=""></td>

  <td nowrap><b>タイトル</b></td>
  <td>
    <input type="text" name="sub" id="id_sub" size="36" value="">
    <input type="submit" name="send" value="送信する">
    <input type="reset" name="allclear" value="リセット">
  </td>

  <td colspan="2" nowrap>
    <b>メッセージ</b><br>
    <textarea name="comment" id="id_comment" cols="56" rows="7"></textarea>
  </td>


以下のサンプルは,mame 属性の値を利用して操作する例です.
掲示板と同じような機能のコントロールを配置し,ここに入力してから [値のセットと送信] ボタンをクリックすると,掲示板に自動的に投稿されます.


図2
設計時画面
図3
実行時画面

リスト1
name 属性を利用してウェブページに入力してボタンをクリックする例
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, OleCtrls, SHDocVw, ExtCtrls, Shell32_TLB, OleServer;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Shell1: TShell;
    Memo1: TMemo;
    LabeledEdit1: TLabeledEdit;
    LabeledEdit2: TLabeledEdit;
    LabeledEdit3: TLabeledEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses  MSHTML, ShellAPI;

{$R *.dfm}

//=============================================================================
//  新規にIEを起動して,当サイトのテスト用掲示板を表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  AppStr : String;
  AppCmd : String;
begin
  //IEは関連付けのあるアプリなのでフルパスでなくても起動可能
  AppStr := 'IEXPLORE.EXE';
  AppCmd := 'http://mrxray.on.coocan.jp/Delphi/Others/aska/delphitest.cgi';
  ShellExecute(Handle, 'open', PChar(AppStr), PChar(AppCmd), nil, SW_SHOW);
end;

//=============================================================================
//  HTMLのname属性を使用して,ブラウザの入力欄に文字列を入力して,ボタンをクリ
//  ックする操作を実行するサンプル
//
//  ここでは同じnameの入力欄があったとしても,最初のid欄へ入力することなる
//  何番目の入力欄かはItemの第2引数で指定する
//
//  IE7,8ではブラウザに対象ページのタブあっても,ブラウザ起動後にタブの切換え
//  操作を行ってしまうとエラーとなる(IEObjの値が変化する仕様になっている)
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  SHWindows       : ShellWindows;
  IEObj           : InternetExplorer;
  Doc2            : IHtmlDocument2;
  iInputElement   : IHTMLInputElement;
  itextAreaElemnt : IHTMLTextAreaElement;
  StrMessage      : String;
begin
  if FindWindow('IEFrame', nil) = 0 then exit;

  //シェルウインドウのオブジェクトを取得
  SHWindows := Shell1.Windows as ShellWindows;

  //そのウィンドウの内,最後に起動したIEのオブジェクトを取得
  IEObj := SHWindows.Item(SHWindows.Count - 1) as InternetExplorer;
  //表示完了まで待つ
  while IEObj.ReadyState < READYSTATE_INTERACTIVE do begin
    Application.ProcessMessages;
  end;

  try
    //IHTMLDocument2インタフェイスのオブジェクトを取得
    Doc2 := IEObj.Document as IHTMLDocument2;

    //[おなまえ]欄への入力.[おなまえ]欄のname属性はname
    //Itemの第2引数はこの場合は最初のnameを対象とするので0とする(0ベースの順序値)
    iInputElement       := Doc2.All.Item ('name',0) as iHTMLInputElement;
    iInputElement.value := LabeledEdit1.Text;

    //[Eメール]欄への入力.[Eメール]欄のname属性はemail
    iInputElement       := Doc2.All.Item ('email',0) as iHTMLInputElement;
    iInputElement.value := LabeledEdit2.Text;

    //[タイトル]欄への入力.[タイトル]欄のname属性はsub
    iInputElement       := Doc2.All.Item ('sub',0) as iHTMLInputElement;
    iInputElement.value :=LabeledEdit3.Text;

    //[メッセージ]欄への入力.[メッセージ]欄のname属性はcomment
    //メッセージ欄は,HTMLのソースを見ると <textarea name="comment... となって
    //いるので,IHTMLTextAreaElementインターフェイスを使う
    itextAreaElemnt       := Doc2.All.Item ('comment',0) as IHTMLTextAreaElement;
    itextAreaElemnt.value := Memo1.Text;

    //[送信する]のボタンをクリック.[送信する]のname属性はsend
    //input type="submit となっているのでsubmitメソッドを実行する
    iInputElement := Doc2.all.item('send', 0) as iHTMLInputElement;
    iInputElement.form.submit;

    //[リセット]ボタンもあるが省略
    //[リセット]ボタンはform.resetメソッドを実行する
  except
    //細かいエラー処理は省略
    StrMessage := '操作できませんでした.';
    MessageBox(Handle, PChar(StrMessage), 'IEのテスト', MB_OK);
  end;
end;

end.




02_掲示板への文字列入力とボタンクリック -  id 属性使用 1


次のサンプルは,id 属性の値を利用した例です.


リスト2
id 属性の値を使用して,ウェブページに入力してボタンをクリックする例
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, OleCtrls, SHDocVw, ExtCtrls, Shell32_TLB, OleServer;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Shell1: TShell;
    Memo1: TMemo;
    LabeledEdit1: TLabeledEdit;
    LabeledEdit2: TLabeledEdit;
    LabeledEdit3: TLabeledEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses  MSHTML, ShellAPI;

{$R *.dfm}

//=============================================================================
//  新規にIEを起動して,当サイトのテスト用掲示板を表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  AppStr : String;
  AppCmd : String;
begin
  //IEは関連付けのあるアプリなのでフルパスでなくても起動可能
  AppStr := 'IEXPLORE.EXE';
  AppCmd := 'http://mrxray.on.coocan.jp/Delphi/Others/aska/delphitest.cgi';
  ShellExecute(Handle, 'open', PChar(AppStr), PChar(AppCmd), nil, SW_SHOW);
end;

//=============================================================================
//  HTMLのid属性を使用して,ブラウザの入力欄に文字列を入力して,ボタンをクリ
//  ックする操作を実行するサンプル
//
//  ここでは同じid属性の入力欄があったとしても,最初の入力欄に入力することなる
//  何番目の入力欄かはItemの第2引数で指定する
//
//  IE7,8ではブラウザに対象ページのタブあっても,ブラウザ起動後にタブの切換え
//  操作を行ってしまうとエラーとなる(IEObjの値が変化する仕様になっている)
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  SHWindows       : ShellWindows;
  IEObj           : InternetExplorer;
  Doc2            : IHtmlDocument2;
  iInputElement   : IHTMLInputElement;
  itextAreaElemnt : IHTMLTextAreaElement;
  StrMessage      : String;
begin
  if FindWindow('IEFrame', nil) = 0 then exit;

  //シェルウインドウのオブジェクトを取得
  SHWindows := Shell1.Windows as ShellWindows;

  //そのウィンドウの内,最後に起動したIEのオブジェクトを取得
  IEObj := SHWindows.Item(SHWindows.Count - 1) as InternetExplorer;
  //表示完了まで待つ
  while IEObj.ReadyState < READYSTATE_INTERACTIVE do begin
    Application.ProcessMessages;
  end;

  try
    //IHTMLDocument2インタフェイスのオブジェクトを取得
    Doc2 := IEObj.Document as IHTMLDocument2;

    //[おなまえ]欄への入力.[おなまえ]欄のid属性はid_name
    //Itemの第2引数はこの場合は最初のidを対象とするので0とする(0ベースの順序値)
    iInputElement       := Doc2.All.Item ('id_name',0) as iHTMLInputElement;
    iInputElement.value := LabeledEdit1.Text;

    //[Eメール]欄への入力.[Eメール]欄のid属性はid_email
    iInputElement       := Doc2.All.Item ('id_email',0) as iHTMLInputElement;
    iInputElement.value := LabeledEdit2.Text;

    //[タイトル]欄への入力.[タイトル]欄のid属性はid_sub
    iInputElement       := Doc2.All.Item ('id_sub',0) as iHTMLInputElement;
    iInputElement.value :=LabeledEdit3.Text;

    //[メッセージ]欄への入力.[メッセージ]欄のid属性はid_comment
    //メッセージ欄は,HTMLのソースを見ると <textarea name="comment... となって
    //いるので,IHTMLTextAreaElementインターフェイスを使う
    itextAreaElemnt       := Doc2.All.Item ('id_comment',0) as IHTMLTextAreaElement;
    itextAreaElemnt.value := Memo1.Text;

    //[送信する]のボタンをクリック
    //この掲示板にはid属性はないのでname属性で実行
    //input type="submit となっているのでsubmitメソッドを実行する
    iInputElement := Doc2.all.item('send', 0) as iHTMLInputElement;
    iInputElement.form.submit;
  except
    //細かいエラー処理は省略
    StrMessage := '操作できませんでした.';
    MessageBox(Handle, PChar(StrMessage), 'IEのテスト', MB_OK);
  end;
end;

end.




03_掲示板への文字列入力とボタンクリック -  id 属性使用 2


次も id 属性の値を使用する例ですが,ページに同じ属性値がない場合は,このコードで十分です.


リスト3
id 属性の値を使用して,ウェブページに入力してボタンをクリックする例
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, OleCtrls, SHDocVw, ExtCtrls, Shell32_TLB, OleServer;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Shell1: TShell;
    Memo1: TMemo;
    LabeledEdit1: TLabeledEdit;
    LabeledEdit2: TLabeledEdit;
    LabeledEdit3: TLabeledEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses  MSHTML, ShellAPI;

{$R *.dfm}

//=============================================================================
//  新規にIEを起動して,当サイトのテスト用掲示板を表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  AppStr : String;
  AppCmd : String;
begin
  //IEは関連付けのあるアプリなのでフルパスでなくても起動可能
  AppStr := 'IEXPLORE.EXE';
  AppCmd := 'http://mrxray.on.coocan.jp/Delphi/Others/aska/delphitest.cgi';
  ShellExecute(Handle, 'open', PChar(AppStr), PChar(AppCmd), nil, SW_SHOW);
end;

//=============================================================================
//  HTMLのid属性を使用して,ブラウザの入力欄に文字列を入力して,ボタンをクリ
//  ックする操作を実行するサンプル
//
//  このサンプルでは常ににページの最初id属性の入力欄に入力することなる
//
//  IE7,8ではブラウザに対象ページのタブあっても,ブラウザ起動後にタブの切換え
//  操作を行ってしまうとエラーとなる(IEObjの値が変化する仕様になっている)
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  SHWindows          : ShellWindows;
  IEObj              : InternetExplorer;
  Doc3               : IHtmlDocument3;
  Doc2               : IHtmlDocument2;
  TagName            : OleVariant;
  iElementCollection : IHTMLElementCollection;
  iInputElement      : IHTMLInputElement;
  i                  : integer;
  iDisp              : IDispatch;
  StrMessage         : String;
begin
  if FindWindow('IEFrame', nil) = 0 then exit;

  //シェルウインドウのオブジェクトを取得
  SHWindows := Shell1.Windows as ShellWindows;

  //そのウィンドウの内,最後に起動したIEのオブジェクトを取得
  IEObj := SHWindows.Item(SHWindows.Count - 1) as InternetExplorer;
  //表示完了まで待つ
  while IEObj.ReadyState < READYSTATE_INTERACTIVE do begin
    Application.ProcessMessages;
  end;

  try
    //getElementByIdが使用できるのはIHTMLDocument3インターフェイス
    Doc3 := IEObj.Document as IHTMLDocument3;

    Doc3.getElementById ('id_name').innerText    := LabeledEdit1.Text;
    Doc3.getElementById ('id_email').innerText   := LabeledEdit2.Text;
    Doc3.getElementById ('id_sub').innerText     := LabeledEdit3.Text;
    Doc3.getElementById ('id_comment').innerText := Memo1.Text;

    //[送信する]ボタンにname属性もidも定義されていないの場合の方法の1つ
    //ドキュメントュメントの中から探し当てる
    //以下のコードではAssignedで確認しているが,確実にあれば必要ない

    //この掲示板のsubmitはINPUTタグにある
    TagName := 'INPUT';
    Doc2    := IEObj.Document as IHTMLDocument2;
    IDisp   := Doc2.all.tags(TagName);

    if Assigned(IDisp) then begin

      //IHTMLElementCollectionオブジェクトのコレクションを取得(INPUTタグの)
      //このコレクションの要素を調べていく
      //第1引数はMSHTML.pas内を調べると.IHTMLElementCollectionのGUIDは
      //IID_IHTMLElementCollectionとなっているのでそれを与える
      IDisp.QueryInterface(IID_IHTMLElementCollection, iElementCollection);

      if Assigned(iElementCollection) then begin
        for i := 0 to iElementCollection.length - 1 do begin
          //i+1番目
          iDisp := iElementCollection.item(i, 0);

          //iInputElement(IHTMLInputElement)オブジェクトを取得
          iDisp.QueryInterface(IID_IHTMLInputElement, iInputElement);
          if Assigned(iInputElement) then begin
            if (iInputElement.type_= 'submit') then begin
              //見つかったのでsubmitメソッドを実行
              iInputElement.form.submit;
              //breakしなければ続けて検索する
              Break;
            end;
          end;
        end;
      end;
    end;
  except
    //細かいエラー処理は省略
    StrMessage := '操作できませんでした.';
    MessageBox(Handle, PChar(StrMessage), 'IEのテスト', MB_OK);
  end;
end;

end.




04_name 属性も id 属性もないボタンのクリック


当サイトの各ページには,下図のように,[Hide Index] というボタンがあります.Delphi のコードでこのボタンをクリックしてみます.
このボタンは,目次の表示と非表示を切り替えるボタンです.クリックすると目次が非表示となります.再度クリックすると表示します.


[備考]
2016年末を以って,当サイトの全てのページの [Hide Index] ボタンを削除しました.したがって,この下のサシンプルコードは実際には動作しません.


図4
[Hide Index] ボタン
  • このボタンは,目次の表示と非表示を切り替えるトグル動作

このボタンの input type のタグには,name 属性も id属 性も定義されていません.この場合は,前のサンプルでも使用しましたが,インターフェイスのオブジェクトから,HTMLコードを調べていくことができます.

<input type="button" value="Hide Index" onClick="ChangeDispIFrmae(this);" ...>

実際のサンプルです.Value 値 (ボタンのキャプションの文字列) で判定することもできますが,ここでは,最初に見つかったボタンをクリックします.
ボタンのキャプションが「ブラウザのボタンをクリック」となっていますが,実際には「ブラウザで表示しているウェブページのボタンをクリック」ということになります.


図5
設計時画面
図6
実行時画面
  • ボタンをクリックする度に,ボタンのキャプション (Value プロパティの値)を取得して表示

リスト4
name 属性も id 属性も定義されていないボタンをクリック
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, OleCtrls, SHDocVw, ExtCtrls, Shell32_TLB, OleServer;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Shell1: TShell;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses  MSHTML, ShellAPI;

{$R *.dfm}

//=============================================================================
//  新規にIEを起動して,操作対象のページを表示
//
//  ShellExecuteの使用にはusesにShellAPIが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  AppStr : String;
  AppCmd : String;
begin
  //IEは関連付けのあるアプリなのでフルパスでなくても起動可能
  AppStr := 'IEXPLORE.EXE';
  AppCmd := 'http://mrxray.on.coocan.jp/Delphi/plSamples/index.htm';
  ShellExecute(Handle, 'open', PChar(AppStr), PChar(AppCmd), nil, SW_SHOW);
end;

//=============================================================================
//  HTMLコードの中からButton要素を探し出してクリックするサンプル
//
//  IE7,8ではブラウザに対象ページのタブあっても,ブラウザ起動後にタブの切換え
//  操作を行ってしまうとエラーとなる(IEObjの値が変化する仕様になっている)
//
//  ShellWindows等の使用にはusesにShell32_TLBが必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  SHWindows          : ShellWindows;
  IEObj              : InternetExplorer;
  TagName            : OleVariant;
  Doc2               : IHtmlDocument2;
  iDisp              : IDispatch;
  iElementCollection : IHTMLElementCollection;
  i                  : integer;
  iButtonElement     : DispHTMLButtonElement;
  StrMessage         : String;
begin
  if FindWindow('IEFrame', nil) = 0 then exit;

  //シェルウインドウのオブジェクトを取得
  SHWindows := Shell1.Windows as ShellWindows;

  //そのウィンドウの内,最後に起動したIEのオブジェクトを取得
  IEObj := SHWindows.Item(SHWindows.Count - 1) as InternetExplorer;
  //表示完了まで待つ
  while IEObj.ReadyState < READYSTATE_INTERACTIVE do begin
    Application.ProcessMessages;
  end;

  //ドキュメントュメントの中から探し当てる
  //以下のコードではAssignedで確認しているが,確実にあれば必要ない

  try
    //INPUTタグを調べる
    TagName := 'INPUT';
    Doc2    := IEObj.Document as IHTMLDocument2;
    IDisp   := Doc2.all.tags(TagName);

    if Assigned(IDisp) then begin

      //IHTMLElementCollectionオブジェクトのコレクションを取得(INPUTタグの)
      //このコレクションの要素を調べていく
      //第1引数はMSHTML.pas内を調べると.IHTMLElementCollectionのGUIDは
      //IID_IHTMLElementCollectionとなっているのでそれを与える
      IDisp.QueryInterface(IID_IHTMLElementCollection, iElementCollection);

      if Assigned(iElementCollection) then begin
        for i := 0 to iElementCollection.length - 1 do begin
          //i+1番目
          iDisp := iElementCollection.item(i, 0);

          //i+1番目のButton属性を取り出す
          iDisp.QueryInterface(DIID_DispHTMLButtonElement, iButtonElement);
          if Assigned(iButtonElement) then begin
            //見つかったのでclickメソッドを実行
            iButtonElement.click;
            //確認用にボタンのValueプロパティを読み出して表示
            Memo1.Lines.Add(iButtonElement.value);

            //最初に見つかったButtonで終了
            //breakしないと続けて検索してしまう
            Break;
          end;
        end;
      end;
    end;
  except
    //細かいエラー処理は省略
    StrMessage := '操作できませんでした.';
    MessageBox(Handle, PChar(StrMessage), 'IEのテスト', MB_OK);
  end;
end;

end.


入力用の form を使用していて,input type が submit の場合は,後述の [07_その他の入力項目の設定と取得] のように,form オブジェクトの submit メソッドを実行する方法もあります.

また,ボタンをクリックするということは,何かを実行することです.したがって,ボタンクリックと同じコードを実行すれば,事実上ボタンをクリックしたことと同じになります.
上のサンプルコードでは,ChangeDispIFrmae(this) という JavaScript の関数を実行しています.そこで,execScript メソッドで JavaScrip を実行するするようにしたのが以下のコードです.
execScript メソッドは,IHTMLWindow2 オブジェクトのメソッドです.



リスト5
ボタンクリックで実行するコードを直接実行すれば,ボタンクリックと同じ
実行コードが JavaScript の例
//=============================================================================
//  新規にIEを起動して,操作対象のページを表示
//  
//  ShellExecuteの使用にはusesにShellAPIが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  AppStr : String;
  AppCmd : String;
begin
  //IEは関連付けのあるアプリなのでフルパスでなくても起動可能
  AppStr := 'IEXPLORE.EXE';
  AppCmd := 'http://mrxray.on.coocan.jp/Delphi/plSamples/370_ScreenCapture1.htm';
  ShellExecute(Handle, 'open', PChar(AppStr), PChar(AppCmd), nil, SW_SHOW);
end;

//=============================================================================
//  表示中のウェブページのボタンをクリックするサンプル
//  ボタンクリックで実行するコードがJavaScriptの場合
//
//  ShellWindows等の使用にはusesにShell32_TLBが必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LSHWindows  : ShellWindows;
  LIEObj      : InternetExplorer;
  LDoc2       : IHtmlDocument2;
  LHTMLWindow : IHTMLWindow2;
begin
  LSHWindows := Shell1.Windows as ShellWindows;
  LIEObj     := LSHWindows.Item(LSHWindows.Count - 1) as InternetExplorer;

  LDoc2 := LIEObj.Document as IHTMLDocument2;
  if Assigned(LDoc2) then begin
    LHTMLWindow := LDoc2.parentWindow as IHTMLWindow2;
    //JavaScriptのChangeDispIFrmae(this)という関数を実行
    LHTMLWindow.execScript('ChangeDispIFrmae(this)', 'JavaScript');
  end;
end;


もし,ボタンに id 属性が定義されていれば,次のようなコードでクリックできます.


リスト6
id 属性を使用してボタンをクリック
//=============================================================================
//  新規にIEを起動して,操作対象のページを表示
//  
//  ShellExecuteの使用にはusesにShellAPIが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  AppStr : String;
  AppCmd : String;
begin
  //IEは関連付けのあるアプリなのでフルパスでなくても起動可能
  AppStr := 'IEXPLORE.EXE';
  AppCmd := 'http://mrxray.on.coocan.jp/Delphi/plSamples/370_ScreenCapture1.htm';
  ShellExecute(Handle, 'open', PChar(AppStr), PChar(AppCmd), nil, SW_SHOW);
end;

//=============================================================================
//  表示中のウェブページのボタンをクリックするサンプル
//  id属性がある場合で,何番目かの指定も可能な方法
//
//  ShellWindows等の使用にはusesにShell32_TLBが必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  SHWindows      : ShellWindows;
  IEObj          : InternetExplorer;
  Doc2           : IHtmlDocument2;
  iButtonElement : DispHTMLButtonElement;
begin
  SHWindows := Shell1.Windows as ShellWindows;
  IEObj     := SHWindows.Item(SHWindows.Count - 1) as InternetExplorer;

  Doc2 := IEObj.Document as IHTMLDocument2;

  iButtonElement := Doc2.all.item('id_btnContent', 0) as DispHTMLButtonElement;
  iButtonElement.click;
end;

//=============================================================================
//  表示中のウェブページのボタンをクリックするサンプル
//  最初のid属性値のボタンに限定する場合
//
//  ShellWindows等の使用にはusesにShell32_TLBが必要
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  SHWindows      : ShellWindows;
  IEObj          : InternetExplorer;
  Doc3           : IHtmlDocument3;
  iButtonElement : DispHTMLButtonElement;
begin
  SHWindows := Shell1.Windows as ShellWindows;
  IEObj     := SHWindows.Item(SHWindows.Count - 1) as InternetExplorer;

  Doc3 := IEObj.Document as IHTMLDocument3;
  Doc3.getElementById ('id_btnContent').click;
end;

end.


次のように,JavaScript のコードとしてクリックすることもできます.
ID 値は文字列です.文字列の中に文字列として挿入するには ''' とします.JavaScript の場合は " で囲まれた部分は文字列として認識しますから," でも構いません.



リスト7
id 属性を使用して,JavaScript のコードとしてボタンをクリック
//=============================================================================
//  表示中のウェブページのボタンをクリックするサンプル
//  id属性値が設定されている場合
//
//  ShellWindows等の使用にはusesにShell32_TLBが必要
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  LSHWindows  : ShellWindows;
  LIEObj      : InternetExplorer;
  LDoc2       : IHtmlDocument2;
  LHTMLWindow : IHTMLWindow2;
  LText       : String;
  Lid         : String;
begin
  LSHWindows := Shell1.Windows as ShellWindows;
  LIEObj     := LSHWindows.Item(LSHWindows.Count - 1) as InternetExplorer;

  LDoc2 := LIEObj.Document as IHTMLDocument2;
  if Assigned(LDoc2) then begin
    LHTMLWindow := LDoc2.parentWindow as IHTMLWindow2;

    //Lid := '"id_btnContent"';でもよい
    Lid   := '''id_btnContent''';
    LText := 'document.getElementById(' + LId + ').click();';
    LHTMLWindow.execScript(LText, 'JavaScript');
  end;
end;




05_ウェブページの画像を全てダウンロード


name 属性も id 属性も定義されていないボタンをクリックするコードのように,HTML のインターフェイスのオブジェクトで解析して操作することができます.
ここでは,これを応用して,表示しているページの全画像をダウンロードしてみます.画像は img タグを解析します.
ダウンロードは,プロジェクトフォルダ直下の [Images] フォルダとします.


[備考]
ブラウザで表示中のウェブページの画像は,画像上のポップアップメニュー (マウスの右ボタンクリックで現れるメニュー) から [名前を付けて画像を保存] で保存できます.
また,画像をフォルダにドラッグ & ドラッグしても保存できます.


図7
設計時画面
図8
[画像をダウンロード]クリック
  • ダウンロード画像の URL 名を表示

リスト8
ページの画像を全てダウンロード
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, OleCtrls, SHDocVw, ExtCtrls, Shell32_TLB, OleServer;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Shell1: TShell;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses  MSHTML, ShellAPI, UrlMon, HTTPApp, WinInet;

{$R *.dfm}

//=============================================================================
//  新規にIEを起動して,操作対象のページを表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  AppStr : String;
  AppCmd : String;
begin
  //IEは関連付けのあるアプリなのでフルパスでなくても起動可能
  AppStr := 'IEXPLORE.EXE';
  AppCmd := 'http://mrxray.on.coocan.jp/Delphi/plSamples/370_ScreenCapture1.htm';
  ShellExecute(Handle, 'open', PChar(AppStr), PChar(AppCmd), nil, SW_SHOW);
end;

//=============================================================================
//  表示中のウェブページの画像を全てダウンロードするサンプル
//
//  IE7,8ではブラウザに対象ページのタブあっても,ブラウザ起動後にタブの切換え
//  操作を行ってしまうとエラーとなる(IEObjの値が変化する仕様になっている)
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  SHWindows          : ShellWindows;
  IEObj              : InternetExplorer;
  TagName            : OleVariant;
  Doc2               : IHtmlDocument2;
  iDisp              : IDispatch;
  iElementCollection : IHTMLElementCollection;
  i                  : integer;
  iImgElement        : IHTMLImgElement;
  SourceFilePath     : String;
  SaveFileName       : String;
  SaveFilePath       : String;
  StrMessage         : String;
begin
  if FindWindow('IEFrame', nil) = 0 then exit;

  //シェルウインドウのオブジェクトを取得
  SHWindows := Shell1.Windows as ShellWindows;

  //そのウィンドウの内,最後に起動したIEのオブジェクトを取得
  IEObj := SHWindows.Item(SHWindows.Count - 1) as InternetExplorer;
  //表示完了まで待つ
  while IEObj.ReadyState < READYSTATE_INTERACTIVE do begin
    Application.ProcessMessages;
  end;

  //ドキュメントュメントの中から探し当てる
  //以下のコードではAssignedで確認しているが,確実にあれば必要ない

  try
    //IMGタグを調べる
    TagName := 'IMG';
    Doc2    := IEObj.Document as IHTMLDocument2;
    IDisp   := Doc2.all.tags(TagName);

    if Assigned(IDisp) then begin
      //IHTMLElementCollectionオブジェクトのコレクションを取得(IMGタグの)
      //このコレクションの要素を調べていく
      iElementCollection := IDisp as IHTMLElementCollection;

        for i := 0 to iElementCollection.length - 1 do begin
          //i+1番目のImgタグオブジェクトを取り出す
          //その中からhref属性の値を取り出す
          iImgElement    := iElementCollection.item(i, 0) as IHTMLImgElement;
          SourceFilePath := iImgElement.href;
          SaveFileName   := ExtractFileName(UnixPathToDosPath(SourceFilePath));
          SaveFilePath   := ExtractFilePath(Application.ExeName) +
                            'Images\' +
                            SaveFileName;

          try
            //UrlDownloadToFile関数はIEのキャッシュを優先してDLするので
            //DeleteUrlCacheEntryであらかじめIEキャッシャ内の該当ファイルを削除
            //usesにWinInetが必要
            DeleteUrlCacheEntry(PChar(SourceFilePath));

            URLDownloadToFile(nil,
                              PChar(SourceFilePath),
                              PChar(SaveFilePath),
                              0,
                              nil);
            //ダウンロードしたファイル名を書き出す
            Memo1.Lines.Add(SourceFilePath);
         except
         end;
       end;
     end;
  except
    //細かいエラー処理は省略
    StrMessage := '操作できませんでした.';
    MessageBox(Handle, PChar(StrMessage), 'IEのテスト', MB_OK);
  end;
end;

end.


上のコードでは,特定のタグである IMG タグのコレクションを取得して,その要素の hreg 属性から画像のリンク元を所得しています.
もし,複数のタグの情報を取得するのであれば,all プロパティのコレクションを取得して操作すると便利です.取得したコレクションの中から,タグの名前を調べて,任意の属性の値を,getAttribute メソッドで取得することができます.
IHtmlDocument2 オブジェクトには,この他にも IHTMLElementCollection を取得するプロパティがあります.下の参考リンクの記事で確認してください.


    Doc2  := IEObj.Document as IHTMLDocument2;
    IDisp := Doc2.all;

    if Assigned(IDisp) then begin
      //IHTMLElementCollectionオブジェクトのコレクションを取得(IMGタグの)
      //このコレクションの要素を調べていく
      iElementCollection := IDisp as IHTMLElementCollection;

        for i := 0 to iElementCollection.length - 1 do begin
          //i+1番目のコレクションの要素を取り出す
          iElement := iElementCollection.item(i, 0) as IHTMLElement;

          //その中からタグ名がIMGのhref属性の値を取得する
          if iElement.tagName = 'IMG' then begin
            SourceFilePath := iElement.getAttribute('href', 0);
            SaveFileName   := ExtractFileName(UnixPathToDosPath(SourceFilePath));
            SaveFilePath   := ExtractFilePath(Application.ExeName) +
                              'Images\' +
                              SaveFileName;






06_TWebBrowser と IE オブジェクト


これまでのサンプルでは,IE のオブジェクトとして IEObj という変数を使用しています.
TWebBrowser を使用したプログラムでは,TWebBrowser のインスタンスが IE のオブジェクトとなります.次の例でのIEオブジェクトは WebBrowser1 となります.つまり,これまでのサンプルコード内の IEObj という変数を WebBrowser1 に置き換えれば,そのまま動作することになります.
これを実際に確認するためのサンプルです.最初のサンプル同様,当サイトのテスト用掲示板に投稿するためのプログラムとなっています.


図9
設計時画面
図10
実行時画面
  • [ページ表示] で掲示板表示

リスト9
TWebBrowser を使用したIEオブジェクトの操作例
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, OleCtrls, SHDocVw, ExtCtrls, OleServer;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    Button2: TButton;
    LabeledEdit1: TLabeledEdit;
    LabeledEdit2: TLabeledEdit;
    LabeledEdit3: TLabeledEdit;
    Memo1: TMemo;
    Panel2: TPanel;
    WebBrowser1: TWebBrowser;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses  MSHTML;

{$R *.dfm}

//=============================================================================
//  TWebBrowserに当サイトのテスト用掲示板を表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  AUrl : String;
begin
  AUrl := 'http://mrxray.on.coocan.jp/Delphi/Others/aska/delphitest.cgi';
  WebBrowser1.Navigate(AUrl);
end;

//=============================================================================
//  HTMLのid属性を使用して,ブラウザの入力欄に文字列を入力して,ボタンをクリ
//  ックする操作を実行するサンプル
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  Doc3          : IHtmlDocument3;
  Doc2          : IHtmlDocument2;
  iInputElement : IHTMLInputElement;
  StrMessage    : String;
begin
  //生成完了まで待つ
  while WebBrowser1.ReadyState < READYSTATE_INTERACTIVE do begin
    Application.ProcessMessages;
  end;

  try
    //getElementByIdが使用できるのはIHTMLDocument3インターフェイス
    Doc3 := WebBrowser1.Document as IHTMLDocument3;

    Doc3.getElementById ('id_name').innerText    := LabeledEdit1.Text;
    Doc3.getElementById ('id_email').innerText   := LabeledEdit2.Text;
    Doc3.getElementById ('id_sub').innerText     := LabeledEdit3.Text;
    Doc3.getElementById ('id_comment').innerText := Memo1.Text;

    Doc2 := WebBrowser1.Document as IHTMLDocument2;
    iInputElement := Doc2.all.item('send', 0) as iHTMLInputElement;
    iInputElement.form.submit;
  except
    //細かいエラー処理は省略
    StrMessage := '操作できませんでした.';
    MessageBox(Handle, PChar(StrMessage), 'IEのテスト', MB_OK);
  end;
end;

end.




07_その他の入力項目の設定と取得


チェックボックスやコンボボックスの入力と設定のサンプルです.

前のサンプルプログラムで,IEのオブジェクトは,IE でも,Delphi 付属の TWebBrowser でも同様に扱えることを示しました.そこでここからのサンプルでは,TEmbeddedWB コンポーネントを使用し,表示するページも,コードが直接確認できるように,ローカルな HTML ファイルとしています.
TWebBrowser で使用する場合の注意もコード内のコメントに書いておきました.

このサンプルでは,id 属性と name 属性ではなく,input タグのコレクションを取得し,その各々コレクション,つまり各々の項目の input タグの,Type 属性を操作するようにしています.
単一の項目の入力や取得であれは,id や name 属性は便利ですが,連続した入力の場合,[ページの画像を全てダウンロード] のように,特定のタグ,以下の場合は input タグですが,そのコレクションを取得して操作する方が便利です.



リスト10
テスト用に表示するHTMLのコード
このコードでは,valueの値と表示の内容 (innerText) を同じにしているが,その必然性はない
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=shift_jis">
<meta http-equiv="content-style-type" content="text/css">
</head>
<body>
<form name="sample" action="#">
  <table>
    <tr>
     <td>名前</td>
     <td><input type=text name="name"></td>
    </tr>
    <tr>
     <td>パスワード</td>
     <td><input type=password name="passwd"></td>
    </tr>
    <tr>
     <td>転送ファイル</td>
     <td><input type=file name="sendfile"></td>
    </tr>
    <tr>
     <td>出身地</td>
      <td>
        <select name="area" size="1">
        <option value="東京都">東京都  </option>
        <option value="埼玉県">埼玉県  </option>
        <option value="千葉県" selected="selected">千葉県  </option>
        <option value="群馬県">群馬県  </option>
        <option value="茨城県">茨城県  </option>
        <option value="栃木県">栃木県  </option>
        <option value="山梨県">山梨県  </option>
        <option value="長野県">長野県  </option>
        </select>
      </td>
    </tr>
    <tr>
     <td>性別</td>
     <td>
      <input type=radio name="seibetsu" value="男" checked>男
      <input type=radio name="seibetsu" value="女">女
     </td>
    </tr>
    <tr>
     <td>趣味</td>
     <td>
      <input type=checkbox name="lifework" value="登山">登山
      <input type=checkbox name="lifework" value="音楽鑑賞">音楽鑑賞
      <input type=checkbox name="lifework" value="読書">読書
     </td>
    </tr>
    <tr>
     <td></td>
     <td>
     <br>
      <input type="submit" value=" 送信 ">
      <input type=reset value=" 取消 ">
     </td>
    </tr>
  </table>
</form>
</body>
</html>


上の HTML コードを実際に表示してテストするプログラムです.
HTML,つまりウェブのページを表示した際,各入力値に値を設定するようにしています.ただし,転送ファイルだけはコードでは設定できません.これができてしまうと,悪意のある操作によって,大量のファイルが転送されかねません.実際に転送機能を実装するには,ユーザ認証等の処理も必要となってくるかも知れません.

ページ上の [送信] ボタンは実際には機能しませんが,submit コマンドを実行しているので,ページが再ロードされて,入力欄の値は,最初に設定した値に戻ります.また,[取消] は元の HTML コードで設定している値にクリアされることになります.



図11
設計時画面
  • 上はブラウザコントロール
  • ここでは TEmbeddedWB コンポを使用
図12
入力値を取得して表示した例
  • 表示の順番と,取得して表示している順番は違うので注意
図13
[submit] ボタンクリック
  • ページ上の [送信] ボタンのクリックをコードで実行
  • submit ボタン(表示の名前-value の値はサイトのページによって異なる)をクリックする参考コード例としてのテスト
  • 転送ファイルの自動設定はできない

リスト11
チェックボックスやコンボボックスの値の設定と取得のサンプル
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, OleCtrls, SHDocVw_EWB, EwbCore, EmbeddedWB,
  MSHTML_EWB;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    Button2: TButton;
    EmbeddedWB1: TEmbeddedWB;
    Splitter1: TSplitter;
    Memo1: TMemo;
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure EmbeddedWB1DocumentComplete(ASender: TObject;
      const pDisp: IDispatch; var URL: OleVariant);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses IEConst;

{$R *.dfm}

//=============================================================================
//  フォームを表示する時にテスト用のHTMLファイルを表示
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
  AURL : String;
begin
  //指定のURLを表示
  AURL := ExtractFilePath(Application.ExeName) + 'GetValueTest.html';
  EmbeddedWB1.Navigate(AURL);
end;

//=============================================================================
//  EmbeddedWBのOnDocumentCompleteイベント処理
//  各入力項目に値をセット
//=============================================================================
procedure TForm1.EmbeddedWB1DocumentComplete(ASender: TObject;
  const pDisp: IDispatch; var URL: OleVariant);
var
  iElementCol  : IHTMLElementCollection;
  iElement     : IHTMLElement;
  i            : Integer;
  AType        : OleVariant;
  Lifeework    : OleVariant;
  Area         : OleVariant;
  iSelElements : IHTMLSelectElement;
begin
  //inputタグのコレクションを取得
  //TWebBrowserでは以下のようにIHTMLDocument3オブジェクトを取得してから操作する
  //Doc3 := WebBrowser1.Document as IHTMLDocument3;
  //iElementCol := Doc3.getElementsByTagName('input');
  iElementCol := EmbeddedWB1.Doc3.getElementsByTagName('input');

  //それを1つづつセットしていく
  //ここではType属性で判定
  for i := 0 to iElementCol.length -1 do begin
    iElement := iElementCol.item(i, 0) as IHTMLElement;
    if Assigned(iElement) then begin
      AType := iElement.getAttribute('type', 0);

      //[名前]
      //[名前]のType属性はtext.text属性が複数ある場合はnameやid属性で判定する
      //あるいは何番目かで判定する.他の入力欄の値も同じ
      if AType = 'text' then begin
        iElement.setAttribute('value', '日本 太郎', 0);
      end else

      //[パスワード]
      if AType = 'password' then begin
        iElement.setAttribute('value', 'HogeHoge', 0);
      end else

      //[参照]のファイル名のセットは,セキュリティの面から不可となっている
      if AType = 'file' then begin
      end else

      //[性別]のラジオボタン
      //複数のラジオグループ入力があった場合を考慮して,name属性で入力項目を判定
      //他の項目も本来はそうすべきであるが省略
      if AType = 'radio' then begin
        if iElement.getAttribute('name', 0) = 'seibetsu' then begin
          //第2引数の0は大文字小文字の区別をしない検索
          if iElement.getAttribute('value', 0) = '女' then begin
            iElement.setAttribute('checked', 'True', 0);
          end;
        end;
      end else

      //[趣味]のチェックボックス
      if AType = 'checkbox' then begin
        Lifeework := iElement.getAttribute('value', 0);
        if (Lifeework = '登山') or (Lifeework = '読書') then begin
          iElement.setAttribute('checked', 'True', 0);
        end;
      end;
    end;
  end;

  //[出身地]のコンボボックス
  //コンボボックスの項目のコレクションを取得
  iSelElements := EmbeddedWB1.Doc3.getElementById('area') as IHTMLSelectElement;

  //そのコレクションを1つづつチェックして,対象の名前であれはselected属性を設定
  for i := 0 to iSelElements.length -1 do begin
    iElement := iSelElements.item(i, 0) as IHTMLElement;
    Area     := iElement.getAttribute('value', 0);
    if Area = '埼玉県' then begin
      iElement.setAttribute('selected', 'selected', 0);
    end;
  end;
end;

//=============================================================================
//  [入力値を取得]ボタン
//  このサンプルでは入力用のFormが1つだけなので,Formの検出処理はしていない
//  入力用のFormが複数ある場合は要注意
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  iElementCol  : IHTMLElementCollection;
  iElement     : IHTMLElement;
  i            : Integer;
  AType        : OleVariant;
  iSelElements : IHTMLSelectElement;
  AIndex       : Integer;
begin
  Memo1.Lines.Clear;

  //inputタグのコレクションを取得
  iElementCol := EmbeddedWB1.Doc3.getElementsByTagName('input');

  //それを1つづつ調べていく
  //ここではType属性で判定
  for i := 0 to iElementCol.length -1 do begin
    iElement := iElementCol.item(i, 0) as IHTMLElement;
    if Assigned(iElement) then begin
      AType := iElement.getAttribute('type', 0);

      //[名前]
      //[名前]のType属性はtext.text属性が複数ある場合はnameやid属性で判定する
      //あるいは何番目かで判定する.他の入力欄の値も同じ
      if AType = 'text' then begin
        Memo1.Lines.Add(iElement.getAttribute('value', 0));
      end else

      //[パスワード]
      if AType = 'password' then begin
        Memo1.Lines.Add(iElement.getAttribute('value', 0));
      end else

      //[転送ファイル]
      if AType = 'file' then begin
        Memo1.Lines.Add(iElement.getAttribute('value', 0));
      end else

      //[性別]のラジオボタン
      //複数のラジオグループ入力があった場合を考慮して,name属性で入力項目を判定
      //他の項目も本来はそうすべきであるが省略
      if AType = 'radio' then begin
        if iElement.getAttribute('name', 0) = 'seibetsu' then begin
          //第2引数の0は大文字小文字の区別をしない検索
          if iElement.getAttribute('checked', 0) = 'True' then begin
            Memo1.Lines.Add(iElement.getAttribute('value', 0));
          end;
        end;
      end else

      //[趣味]のチェックボックス
      if AType = 'checkbox' then begin
        if iElement.getAttribute('checked', 0) = 'True' then begin
          Memo1.Lines.Add(iElement.getAttribute('value', 0));
        end;
      end;
    end;
  end;

  //[出身地]のコンボボックス
  //選択中のインデックスを取得して,その値からエレメントの要素の値を取得
  iSelElements := EmbeddedWB1.Doc3.getElementById('area') as IHTMLSelectElement;
  AIndex       := iSelElements.selectedIndex;
  iElement     := iSelElements.item(AIndex, 0) as IHTMLElement;
  Memo1.Lines.Add(iElement.getAttribute('value', 0));
end;

//=============================================================================
//  [submit]ボタン
//  HTMLのinputタグのtype=submitのボタンをクリックする例
//  ボタンのOnClickというのもあるが,ここでは入力のFormタグのType属性がsubmit
//  なのでそのFormのsubmitを実行する
//  各入力値は,OnDocumentCompleteイベント処理での設定となる
//
//  Formにname属性がない場合は,何番目のFormというように操作することになる
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  iElementCol : IHTMLElementCollection;
  iElement    : IHTMLFormElement;
  i           : Integer;
begin
  iElementCol := EmbeddedWB1.Doc2.forms;
  for i := 0 to iElementCol.length - 1 do begin
    iElement := iElementCol.Item(i, 0) as IHTMLFormElement;
    if iElement.name = 'sample' then begin
      iElement.submit;
    end;
  end;

//  このサンプルプログラムの入力Formは1つだけなので,実際には以下のコードでもOK
//  iElementCol := EmbeddedWB1.Doc2.forms;
//  iElement := iElementCol.Item(0, 0) as IHTMLFormElement;
//  iElement.submit;
end;

end.


[送信] ボタンは,次のように,JavaScript のコードとしてクリックすることもできます.
ID 値は文字列です.文字列の中に文字列として挿入するには ''' とします.JavaScript の場合は " で囲まれた部分は文字列として認識しますから," でも構いません.



リスト12
JavaScript のコードとして submit を実行する例
//=============================================================================
//  [送信]ボタンをJavaScriptのコードでクリック
//  最初のformは0, 2番目は1
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LText : String;
begin
  LText := 'document.forms[0].submit()';
  EmbeddedWB1.ExecScript(LText, 'JavaScript');
end;

//=============================================================================
//  [送信]ボタンをJavaScriptのコードでクリック
//  formにid値が設定してある場合はid値で指定できる
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
  LText : String;
  Lid   : String;
begin
  //Lid := '"Hoge"';でもよい
  Lid   := '''Hoge''';
  LText := 'document.forms[' + Lid + '].submit()';
  EmbeddedWB1.ExecScript(LText, 'JavaScript');
end;




08_HTML コード内の JavaScript 関数の実行と戻り値の取得


項目の入力ではありませんが,HTML コード内の JavaScript 関数を実行する例です.
TWebBrowser で JavaScript を実行するサンプルが,下記の delphiDabbler.com にあります.

ここでは,TEmbeddedWB コンポーネントを使用するサンプルとしました.TEmbeddedWB コンポーネントには,ExecScriptEx という戻り値を取得できるメソッドがあります.これを使用しています.
実行する JavaScript のコードは,次のコードとしています.実行する関数は引数が 2 つあり,戻り値があります.この戻り値を Delphi 側で受け取ります.



[備考 1]
TEmbeddedWB コンポーネントを使用する時は,MSHTML の代わりに MSHTML_EWB を使用します.


[備考 2]
HTML コード内の JavaScript を実行するのではなく,表示中のウェブページに対して JavaScript のコードを挿入して実行する場合は以下の記事を参考にしてください.

[備考 3]
以下の記事では,JavaScript から Delphi のメソッドを実行するサンプルを掲載しています.


リスト13
テスト用に表示する HTML コード
関数rangeRandom は,引数の num1 から num2 の間の乱数を発生する関数
注: <font> </font> タグは,HTML5.0 では廃止された
<html>
<head>
<script language="javascript">
  function rangeRandom(num1, num2) {
    if((num1 - num2) > 0) {
      var vbig = num1
      var vsmall = num2
    } else  {
      var vbig = num2
      var vsmall = num1
    }
    var range = vbig - vsmall + 1
    var number = Math.floor (Math.random() * range) + vsmall
    return (number)
  }
</script>
</head>

<body>
<center>

<form>
  <input type="submit" value="乱数発生">
</form>

<script language="javascript">
  var num = rangeRandom (0, 100)
  document.write ("<font size = '+4'>" + num + "</font>")
</script>

</center>
</body>
</html>


図14
設計時画面
図15
ウェブ上のボタンで実行
  • 0~100 までの乱数を発生して表示

上の図では,ウェブ上のボタンをクリックすることで JavaScript の関数を実行しています.
以下の図では,これを Delphi のコードで実行した結果です.


図16
[乱数発生] クリックをクリック
  • ウェブページ上の [乱数発生] ボタンのクリックをコードで実行
図17
関数実行
  • JavaScript の関数を実行した結果の戻り値を表示 (赤枠内)
  • その値を元にHTMLのコードを変更してウェブページ上にも表示

リスト14
HTMLコード内の JavaScript の関数を実行して,戻り値を取得する例
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, OleCtrls, SHDocVw_EWB, EwbCore, EmbeddedWB;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    Button2: TButton;
    LabeledEdit1: TLabeledEdit;
    EmbeddedWB1: TEmbeddedWB;
    procedure FormShow(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses MSHTML_EWB, EwbTools;

{$R *.dfm}

//=============================================================================
//  フォームを表示する時にテスト用のHTMLファイルを表示
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
  AURL : String;
begin
  //指定のURLを表示
  AURL := ExtractFilePath(Application.ExeName) + 'JaveRandom.html';
  EmbeddedWB1.Navigate(AURL);
end;

//=============================================================================
//  HTMLで表示している[乱数発生]ボタンをDelphiのコードで実行
//
//  ボタンのOnClickというのもあるが,ここでは入力のFormタグのType属性がsubmit
//  なのでそのFormのsubmitを実行する
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  iElement : IHTMLFormElement;
begin
  LabeledEdit1.Text := '';

  //このサンプルプログラムの入力Formは1つだけなので,最初のだけ検出
  iElement := EmbeddedWB1.Doc2.forms.item(0, 0) as IHTMLFormElement;
  if iElement <> nil then begin
    iElement.submit;
  end;
end;

//=============================================================================
//  HTMLコード内のJavaScript関数を実行
//
//  TWebBrowser,TEmbeddedWBにはExecScriptというメソッドがあるが,これは実行結
//  果の戻り値は取得できない
//  TEmbedeedWBではExecScriptExという関数の戻り値を取得するメソッドがある,これ
//  を使用
//
//  HTMLで表示しているテキストの書き換えテストも兼ねている
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  Num1        : OleVariant;
  Num2        : OleVariant;
  vResult     : OleVariant;
  iElementCol : IHTMLElementCollection;
  iElement    : IHTMLElement;
begin
  Num1 := 0;
  Num2 := 100;

  //rangeRandomというJavaScript関数を実行
  //第2引数は関数名の文字列
  //第3引数は関数の引数の配列(いつくでも指定可能.必要なければ[]にしておく
  vResult := EmbeddedWB1.ExecScriptEx('rangeRandom', [Num1, Num2]);
  LabeledEdit1.Text := vResult;


  //関数の戻り値を使用して,HTMLの表示も変更
  //ここではfontタグに囲まれた値を変更する
  //このテストで扱っているHTMLのfontタグは1つだけなので,最初のだけ検出
  iElementCol := EmbeddedWB1.Doc3.getElementsByTagName('font') as
                                                     IHTMLElementCollection;
  iElement := iElementCol.item(0, 0) as IHTMLElement;
  iElement.innerText := vResult;
end;

end.


TEmbeddedWB コンポーネントに [14 - ExecScriptEx_Demo] というデモプログラムがあります.このデモプログラムは,そのままでは正しい結果を取得できません.
このデモプログラムのコードは以下のようになっています.

リスト15
このコードだと,結果が常に 0 になってしまう
procedure TForm1.Button1Click(Sender: TObject);
var
  vResult: OleVariant;
  Para1  : string;
begin
  Para1 := edPara.Text;
  vResult := EmbeddedWB1.ExecScriptEx('evaluate', [Para1]);
  ShowMessage('Result from the Script: ' + IntToStr(vResult));
end;

これを次の様に,引数の値の型を,Integer 型か OleVariant 型にすれば正しい結果が取得できるようになります.

リスト16
引数を Integer 型にする
procedure TForm1.Button1Click(Sender: TObject);
var
  vResult : OleVariant;
  Para1   : Integer;
begin
  Para1   := StrToInt( edPara.Text);
  vResult := EmbeddedWB1.ExecScriptEx('evaluate', [Para1]);
  ShowMessage('Result from the Script: ' + IntToStr(vResult));
end;

リスト17
または OleVariant 型にする

procedure TForm1.Button1Click(Sender: TObject);
var
  vResult : OleVariant;
  Para1   : OleVariant;
begin
  Para1   := edPara.Text;
  vResult := EmbeddedWB1.ExecScriptEx('evaluate', [Para1]);
  ShowMessage('Result from the Script: ' + IntToStr(vResult));
end;


TWebBrowser には ExecScriptEx メソッドはありません.TEmbeddedWB コンポが提供しているEwbTools 内の WBExecScript というメソッドを次のようにして利用できます.
uses の SHDocVw と MSHTML を SHDocVw_EWB と MSHTML_EWB に変更して,EwbTools を追加します.
このコードであれば,TWebBrosser コンポーネントでなくても,IEオブジェクトでも使用可能です.


リスト18
TWebBrowser で JavaScript の関数を実行する例
//=============================================================================
//  HTMLコード内のJavaScript関数を実行
//  TWebBrowserでEmbeddesWBが提供しているEwbTools内のメソッドを利用する
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  Num1        : OleVariant;
  Num2        : OleVariant;
  vResult     : OleVariant;
  dScript     : IDispatch;
  iElementCol : IHTMLElementCollection;
  iElement    : IHTMLElement;
  iDoc2       : IHTMLDocument2;
  iDoc3       : IHTMLDocument3;
begin
  Num1 := 0;
  Num2 := 100;

  iDoc2   := WebBrowser1.Document as IHTMLDocument2;
  dScript := iDoc2.Script;
  if Assigned(dScript) then begin
    vResult := EwbTools.WBExecScript(DScript, 'rangeRandom', [Num1, Num2]);
    LabeledEdit1.Text := vResult;

    iDoc3       := WebBrowser1.Document as IHTMLDocument3;
    iElementCol := iDoc3.getElementsByTagName('font') as
                                                       IHTMLElementCollection;
    iElement := iElementCol.item(0, 0) as IHTMLElement;
    iElement.innerText := vResult;
  end;
end;




09_入力フォームからサーバにファイルをアップロード


[その他の入力項目の設定と取得] のサンプルでは,入力した項目値は,実際にはサーバに送信はしていません.そこで,実際に送信してみることにします.ただし,ファイルだけとします.サーバにファイルを送信,アップロードします.以下の手順で行います.
  • (1) HTML の入力フォームから送られてきたデータを処理するための PHP のコードを作成
  • (2) PHP に送るデータを入力するための HTML コードを作成
  • (3) その HTML を表示するための Delphi のプログラムを作成

ここまでのサンプルは,すでにある HTML を Delphi から操作あるいは解析するものでした.しかし,本サンプルの機能を実現するためのコードは,実際には,HTML または PHP のコードにあります.
Delphi のコードは,HTML を表示するだけであって,ファイルのアップロードを行っているわけではあません.したがって,HTML と PHP コードのサンプルとなっています.

今回のテストでは,PHP のコードは次のようにしました.このコードを,ファイルをアップロードするサーバの任意のディレクトリに置きます.ファイル名を upload_form.php としました.添付のファイルでは,文字コードを EUC にして保存しています.
このコードは,

  • (1) サーバに送られてきたファイルを,この PHP ファイルがあるディレクトリ内の [data] といディレクトリ内に保存する (ディレクトリはあらかじめ作成しておく)
  • (2) ファイルサイズの制限を 1 MB 以下とする
  • (3) アップロードされたファイルのパーミッション (アクセス制限) を 644 に変更する
という操作を行います.


図18
upload_form.php をサーバの任意の場所に置く
  • 保存用のディレクトリを作成しておく
  • 今回は data という名前にした
  • この図は [774] [03_FTP サーバのディレクトリツリー] のサンプルで作成

リスト19
ブラウザから送られてきたファイルを処理する PHP のコード
<?php
  $upload_dir  = './data';
  $upload_name =  $_FILES["upfile"]["name"];
  $maxfilesize =  1024000;

  if (is_uploaded_file($_FILES["upfile"]["tmp_name"])) {
    if($_FILES["upfile"]['size'] <= $maxfilesize) { 
      if (move_uploaded_file($_FILES["upfile"]["tmp_name"], 
                             $upload_dir.'/'.$upload_name)) {
          chmod("$upload_dir/$upload_name", 0644);
          echo $upload_name . " をアップロードしました";
      } else {
        echo "ファイルのアップロードに失敗しました";
      }      
    } else {
      echo "ファイルのサイズが制限を超えています"; 
    }  
  } else {
    echo "ファイルが選択されていません";                
  }
?>


HTML コードは以下のようにしました.この HTML はファイルを選択するためのものです.
今回のテストでは,このファイルは,クライアント側の,Delphi のプロジェクトと同じフォルダに置きました.ファイル名は FormForPostTest.html としています.


リスト20
入力フォームを表示する HTML
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=shift_jis">
<meta http-equiv="content-style-type" content="text/css">
</head>
<body>
<form action="http://mrxray.on.coocan.jp/Others/UploadDir/upload_form.php" 
      method="post" 
      enctype="multipart/form-data">
  <table>
    <tr>
      <td>転送ファイル</td>
      <td>
        <input type=file name="upfile">
      </td>
    </tr>
    <tr>
      <td></td>
      <td>
      <br>
      <input type="submit" value=" 送信 ">
      </td>
    </tr>
  </table>
</form>
</body>
</html>


form タグの各属性には以下の意味があります.

action submit した時に実行するファイル名
ここでは,サーバにある PHP ファイルを絶対パスで指定
method ここでは post とする
enctype MIME タイプの指定.multipart/form-data とする


また,input タグの name 属性の意味は以下の通りとなっています.

name サーバ側で,受け取るデータの識別に使用する
PHP コード内の $_FILES["upfile"] の引数の値と同じにする
ここでは "upfile"


HTML を表示するためのサンプルコードと,設計時の画面です.


図19
設計時画面
  • 白いのは TEmbeddedWB コンポ

リスト21
FormForPostTest.html を表示するプログラム
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, OleCtrls, SHDocVw_EWB, EwbCore, EmbeddedWB,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    EmbeddedWB1: TEmbeddedWB;
    IdHTTP1: TIdHTTP;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  [アップロード]ボタン
//  入力用のHTMLを表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  AUrl : String;
begin
  //入力用のHTMLのフルパス
  AUrl := ExtractFilePath(Application.ExeName) + 'FormForPostTest.html';
  //そのHTMLを表示
  EmbeddedWB1.Navigate(AUrl);
end;

//=============================================================================
//  [ダウンロード]ボタン
//  確認のためにダウンロード
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  AUrl     : String;
  Stream   : TMemoryStream;
  SaveName : String;
begin
  EmbeddedWB1.Navigate('about:blank');

  //ダウンロードするファイル名
  SaveName := 'Test.txt';

  //ダウンロードするファイルの絶対パス
  AUrl   := 'http://mrxray.on.coocan.jp/Others/UploadDir/data/' + SaveName;
  Stream := TMemoryStream.Create;
  try
    //Streamにダウンロード
    IdHTTP1.Get(AUrl, Stream);
    //保存
    Stream.SaveToFile(ExtractFilePath(Application.ExeName) + SaveName);
  finally
    FreeAndNil(Stream);
  end;

  SaveName := ExtractFilePath(Application.ExeName) + SaveName;
  if FileExists(SaveName) then begin
    EmbeddedWB1.Navigate(SaveName);
  end;
end;

end.


実行結果です.
上の方のサンプルでは,ファイルのダウンロードに URLDownloadToFile を使用しましたが,本サンプルでは TIdHTTP コンポーネントを使用しています.

実際には,ユーザやパスワードの認証処理,あるいは他の入力項目等の処理も必要になってくると思われます.その他にも,サーバ側としての設定や制御も必要となってくるでしょう.これらは 完全に HTML と PHP のコーディングとなります.Web アプリケーション開発の領域になってきます.必要があればネット上や参考書で調べてください.このページの最初の方にも参考リンクがあります.



図20
入力時の画面
  • [参照] ボタンでファイルを選択し
  • [送信] ボタンをクリック
図21
アップロードしたファイル
  • ディレクトリ [data] に格納される
  • この図は [774] [03_FTP サーバのディレクトリツリー] のサンプルで作成

[備考]
当サイトの掲示板も名前等の入力欄があり,ファイルのアップロードができますが,Perl という言語を使用した CGI です.PHP でも Delphi でも CGI を作成できますが,Delphi の場合は,サーバの OS が Windows に限られます.
ネット上では多くの GGI が配布されています.KENT WEB というサイトが有名ですが,このサイトには以下のような,パスワード等の認証用の CGI も配布しています.


図22
パスワード制限用 CGI
  • ダイアログのデザインは,ブラウザによって異なる
  • この図は IE 8 の場合