2017年07月 / 06月≪ 12345678910111213141516171819202122232425262728293031≫08月

インフォメーション

FC2ブログで画像等を一括アップロードするソフトを地味に配布してます。
FC2ブログ用ファイルアップロードの最新版はこちら
(ベクター)FC2ブログ用ファイルアップロード

--.--.-- (--)

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。


 |  --:--  |  スポンサー広告  |  Top↑

2009.08.01 (Sat)

WebBrowser

サイトを巡回して自動でクリックしたいなんてときに便利なWebBrowser。
主な使い方

// URLを開く
webBrowser1.Navigate("http://www.google.co.jp/");

// 更新
webBrowser1.Refresh();

// 読み込み完了まで待つ
try
{
while (webBrowser1.IsBusy || webBrowser1.ReadyState != WebBrowserReadyState.Complete)
{
System.Threading.Thread.Sleep((int)(0.5 * 1000));
Application.DoEvents();
}
}
catch (Exception) { }


Googleを開いて検索ボックスに「相模原」をいれて検索する処理だとこんな感じ

private void button1_Click(object sender, EventArgs e)
{
// URL(Google)を開く
webBrowser1.Navigate("http://www.google.co.jp/");

// 読み込み完了まで待つ
try
{
while (webBrowser1.IsBusy || webBrowser1.ReadyState != WebBrowserReadyState.Complete)
{
System.Threading.Thread.Sleep((int)(0.5 * 1000));
Application.DoEvents();
}
}
catch (Exception) { }

// DocumentはHtmlDocumentというオブジェクト型
HtmlDocument doc = webBrowser1.Document;

// 検索(テキスト)ボックス(name="q")を取得
// Document以下のエレメントはHtmlElementというオブジェクト型
HtmlElement elem = webBrowser1.Document.All["q"];

// GetElementByIdで検索ボックスを取得する場合
HtmlElement ielem = webBrowser1.Document.GetElementById("q");

// GetElementsByNameで検索ボックスを取得する場合、
// HtmlElementCollection型になる。
// ※GetElementsByNameはAll以下に存在する
HtmlElementCollection elems = webBrowser1.Document.All.GetElementsByName("q");
// コレクション型なので先頭を取得
HtmlElement celem = elems[0];

// elemもielemもcelemも同じエレメントが取得できてる はず。

// 取得した検索ボックスに「相模原」をセット
// エレメントのプロパティにセットする場合はSetAttributeを使用
elem.SetAttribute("value", "相模原");

// プロパティを取得する際はGetAttributeを使用
MessageBox.Show("title=" + elem.GetAttribute("title"));

// ラジオボタン「日本語のページを検索」(name="lr"の2個目)にチェックを入れる
webBrowser1.Document.All.GetElementsByName("lr")[1].SetAttribute("checked", "true");

// 「Google 検索」ボタンを探す
foreach (HtmlElement el in webBrowser1.Document.All)
{
// typeとvalueプロパティを取得してみる
string type = el.GetAttribute("type");
string value = el.GetAttribute("value");

// 両方取得できた場合
if (type != null && !type.Equals(string.Empty)
&& value != null && !value.Equals(string.Empty))
{
// typeが「submit」でvalueが「Google 検索」であればクリック
if (type.Equals("submit") && value.Equals("Google 検索"))
{
// メソッドを実行する場合はInvokeMemberでメソッド名を指定
el.InvokeMember("click");
// 抜ける
break;
}
}
}
}



ステータスバーを設置して、普通のIEのように現在のステータス文字をステータスバーに表示させる場合、
ステータスバーにラベル項目を追加してStatusTextChangedイベントで変化させる。
// コンストラクタ
public Form1()
{
InitializeComponent();

// webbrowserのステータスが変化した時のイベント追加
webBrowser1.StatusTextChanged += new EventHandler(webBrowser1_StatusTextChanged);
}

void webBrowser1_StatusTextChanged(object sender, EventArgs e)
{
// ステータスバーのラベルに現在のステータスを表示
toolStripStatusLabel1.Text = webBrowser1.StatusText;
}


フレームの場合は
webBrowser1.Document.Window.Frames[0].Document;
webBrowser1.Document.Window.Frames[1].Document;
等で各フレームのドキュメントが取得できるようだ。

クッキーは
webBrowser1.Document.Cookie
に入ってるみたいだがこれといった使い方がわからない。


 |  17:02  |  C#.NET  |  トラックバック(0)  |  コメント(10)  |  Top↑

Comment

●はじめまして!

C#を初めて1週間の初心者です。
僕のような初心者にもすごくわかりやすく勉強になります!

質問です!
フレームを使用しているサイトに自動ログインできるようなプログラム例を教えてもらうことはできないでしょうか?
webBrowser1.Document.Window.Frames[0].Document;
をどのように使えばいいのかわかりません・・・。
おしゃれ番町 |  2010.11.07(日) 15:22 |  URL |  【コメント編集】

●Re: はじめまして!

コメントありがとうございます。
フレームを使用してるサイトにログインということですが、どんなサイトかわからないので適当で申し訳ないのですが、
例えばフレーム1枚目にloginidという名前のテキストボックスがあったとしたら
webBrowser1.Document.Window.Frames[0].Document.All["loginid"].SetAttribute("value", "xxxx");
みたいな感じで値を入れるとか・・・
webBrowser1.Document.Window.Frames[0].DocumentはwebBrowser1.Documentと同じようなHtmlDocumentオブジェクトなので、あとはフレームじゃないサイトを開いた場合のwebBrowser1.Documentと同じ感じで操作できると思います。
上野メモ |  2010.11.07(日) 18:56 |  URL |  【コメント編集】

上野メモさん、早速のご返事ありがとうございます!
教えていただいた方法でさっそく試したところ、これまでは
「ArgumentOutOfRangeExceptionはハンドルされませんでした。」
のエラーだったのが
「UnauthorizedAccessExceptionはハンドルされませんでした。」
になりました!

教えていただいた方法でフレームに書き込みまで出来るようになったようなのですが、管理者権限ではじかれてしまったようです><

今、自動ログインしようとしているサイトはコチラとなります。
http://www.gameyarou.jp/?d_url=https%3A%2F%2Fsecure.gameyarou.jp%2FMember%2FLogin%2F__Common_Login_Form.asp%3Fr_url%3Dhttp%3A%2F%2Fsuddenattack.gameyarou.jp

HTTPSにログインしているから現状ではだめなのか?と仮設を立ててみましたが・・・違うようです。
(YahooメールのHTTPSにログインできるプログラムを見つけたのですが、特殊なことはやっていないような気がしました。)

なぜログインできないのかおわかりになるでしょうか?
おしゃれ番町 |  2010.11.08(月) 21:50 |  URL |  【コメント編集】

●Re: タイトルなし

こちらでも試してみたところ、同じエラーが出ました。
どうやらインラインフレームにアクセスするのはセキュリティ的に厳しいらしく、
ドキュメントを取得する際にエラーが出ていたようです。
そのページじゃなくて、TOPページ(http://www.gameyarou.jp/)であれば普通のフレームなのでログイン処理も問題なく出来たのですが、どうしてもインラインフレームのページでログインしたい・・・となると手間がかかりそうです。
ちなみにTOPページでのログインであればこれでいけました。
HtmlDocument doc = webBrowser1.Document.Window.Frames[1].Document;
doc.All["ID_user_id"].SetAttribute("value", "userid");
doc.All["ID_user_pwd"].SetAttribute("value", "pass");
HtmlElementCollection inputs = doc.All["LoginLeftForm"].GetElementsByTagName("input");
foreach (HtmlElement elem in inputs)
{
if (elem.GetAttribute("type").ToLower().Equals("image") &&
elem.GetAttribute("src") != null &&
elem.GetAttribute("src").IndexOf("btn_login.gif") > -1)
{
elem.InvokeMember("click");
}
}
上野メモ |  2010.11.09(火) 00:59 |  URL |  【コメント編集】

●ありがとうございます!!

上野メモさん、本当にありがとうございます!
たしかにログインする方法は一通りではないので、他の方法を試してみるという視点が欠けていました><
さすがです!

プログラミング超初心者の私に親切に対応していただきありがとうございました!
おしゃれ番町 |  2010.11.09(火) 04:03 |  URL |  【コメント編集】

●Re: ありがとうございます!!

インラインフレームの中身をとりたい場合はwindowでなく、「contentWindow」からアクセスしないとダメっぽいので、どうしてもという場合はこれも含めて調べてみてください。
動きの少ないブログですので質問はむしろありがたいくらいですw
上野メモ |  2010.11.09(火) 20:15 |  URL |  【コメント編集】

●アドバイスを頂けないでしょうか

上野さん、こんばんは。

keiです。
先日は質問にお答えいただき、ありがとうございます。


実は、今c#でツールを作ろうとしているのですが、
初期の初期でつまづいてしまい、
全く先に進めなくなってしまいました。


もう1週間以上も検索しまくっているのですが、
一向に解決方法が見つからず…。orz


大変図々しいお願いなのですが、
出来ましたら、アドバイスを頂けないでしょうか?




1,対象サイトにログイン

2,フォームに入力して送信

この流れを完全に自動化するツールを作りたいと思っています。



で、1のログイン処理はうまく行ったので、2のフォーム入力処理を加えたところ
エラーが出てしまいました。


どうやら、ログイン後ページではなく、
ログイン前ページのから書き込み対象フォームを探しているため、
見つからずエラーが出ているようです。
(1と2の処理を別のボタンに分けると、問題なく処理できます。)


ログイン後ページの情報を取得してから、
2,フォームに入力して送信の処理
をするにはどのようにしたらいいのでしょうか?





//1,対象サイトにログイン
private void Login()
{
webBrowser1.Navigate("http://www.abc.com");

this.Wait(this.webBrowser1);
webBrowser1.Document.All.GetElementsByName("SiteID")[0].InnerText = "id";
webBrowser1.Document.All.GetElementsByName("Password")[0].InnerText = "pass";

HtmlElementCollection all = webBrowser1.Document.All;
HtmlElementCollection forms = all.GetElementsByName("Submit");
forms[0].InvokeMember("click");

this.Wait(this.webBrowser1);



//2,フォームに入力して送信(※追加部分)
webBrowser1.Document.All.GetElementsByName("comment")[0].SetAttribute("value", "hogehoge");

HtmlElementCollection all = webBrowser1.Document.All;
HtmlElementCollection forms = all.GetElementsByName("Submit");
forms[0].InvokeMember("click");

}



//webページが読み込まれるまで待機
private void Wait(WebBrowser webBrowser1)
{
try
{
while (webBrowser1.IsBusy || (webBrowser1.ReadyState != WebBrowserReadyState.Complete))
{
Thread.Sleep(500);
Application.DoEvents();
}
}
catch (Exception)
{
}
}



public Form1()
{
InitializeComponent();

}


//実行ボタンをクリック
private void button1_Click(object sender, EventArgs e)
{
Login();
}



よろしくお願いいたします。
kei |  2010.11.28(日) 04:45 |  URL |  【コメント編集】

●Re: アドバイスを頂けないでしょうか

keiさんこんばんは。

この辺は実際に動かしてみないとわからないので特定は出来ないんですけど、
コードだけ見て怪しそうなところといえば

> 1,対象サイトにログイン
の処理でやっている
> HtmlElementCollection all = webBrowser1.Document.All;
> HtmlElementCollection forms = all.GetElementsByName("Submit");
> forms[0].InvokeMember("click");
>
> this.Wait(this.webBrowser1);

ここが気になるところですね。
> forms[0].InvokeMember("click");
ここでボタンかなんかクリックしてるんだと思いますが、
もしかしたらクリック直後のwebBrowser1.IsBusyやwebBrowser1.ReadyStateが変更される前にWaitに入ってしまい、
そのまますぐWaitを抜けてしまってる可能性があります。
今自分のコードを見たところ、Waitの前にDoEventsを入れているので、自分も同じところではまってたのかもしれないです。

> forms[0].InvokeMember("click");
>
> this.Wait(this.webBrowser1);

forms[0].InvokeMember("click");
Application.DoEvents();
this.Wait(this.webBrowser1);

と変えてみてください。
それでもダメだったらDoEvents();のあたりにsleepも追加してみたり。
試してみてもしそれが原因だと確定したら、常にDoEventsをするために
Wait処理の先頭にDoEventsを入れたほうがいいかも。
想定なのでダメかもしれませんが、試しにやってみてください。
上野メモ |  2010.11.28(日) 20:34 |  URL |  【コメント編集】

●ありがとうございますっ!!!!!!!

上野さん、おはようございます。

keiです。

アドバイスありがとうございます。

> もしかしたらクリック直後のwebBrowser1.IsBusyやwebBrowser1.ReadyStateが変更される前にWaitに入ってしまい、
> そのまますぐWaitを抜けてしまってる可能性があります。

なるほど、なるほど。

で、早速DoEventsを加えてみると…


お、お、お、おおおおおおおっっっっっ!!!!!
うまくいきました(爆喜)

ワッショイヽ(゚∀゚)メ(゚∀゚)メ(゚∀゚)ノワッショイ

もうずーと悩んでたんで、めっちゃ嬉しいです。(つД`)
本当に、本当にありがとうございました。^^
kei |  2010.11.29(月) 04:43 |  URL |  【コメント編集】

●Re: ありがとうございますっ!!!!!!!

keiさん報告ありがとうございます。
無事に動いてよかったです。
NavigateだとC#.NET側の操作だったからDoEvents入れなくても大丈夫だったんですけど、
フォーム内のInvokeMember等はブラウザ内に命令を送る操作なので、DoEventsが必要っぽいですね。
自分のソフトもWaitの処理分けてるので、先頭にDoEventを入れるようにしておきます。
上野メモ |  2010.11.29(月) 16:51 |  URL |  【コメント編集】

コメントを投稿する

URL
コメント
パス  編集・削除するのに必要
非公開  管理者だけにコメントを表示
 

Trackback

この記事のトラックバックURL

この記事へのトラックバック

 | BLOGTOP | 
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。