質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

3回答

5404閲覧

webBrowserコントロールのDocumentCompletedについて

退会済みユーザー

退会済みユーザー

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2018/11/27 04:31

編集2018/11/30 01:23

初心者的質問で申し訳ございませんが、回答していただければ幸いです。
https://teratail.com/questions/160352
上記の質問で無限ループ処理はよくないと回答をいただき、一般的にはDocumentCompletedを利用すればよいことを知りました。
そこで下記のようなDocumentCompletedを利用したものを記述しているのですが、
思った動作をしていません。
理想動作は、
接続先URL1にアクセス→接続先URL1が表示が完了してから
else if (label1.Text == "接続先URL1接続完了")
の部分を実行させたいです。
しかし、完了していない状態のところで動き、
HtmlElement id = elements.GetElementsByName("userName")[0];の部分で下記エラー発生しています。
System.ArgumentOutOfRangeException: ''0' の値は 'index' に対して有効ではありません。'index' は 0 と -1 の間でなければなりません。
パラメーター名:index'
ページによっては複数回DocumentCompletedが発生するものがあると聞きましたが、
その場合の記述例を教えていただけないでしょうか。
また、その他良い記述方法等ございましたらアドバイスお願いいたします。

C#

1using System; 2using System.Collections.Generic; 3using System.ComponentModel; 4using System.Data; 5using System.Drawing; 6using System.Linq; 7using System.Net; 8using System.Net.Security; 9using System.Runtime.InteropServices; 10using System.Security.Cryptography.X509Certificates; 11using System.Text; 12using System.Threading; 13using System.Threading.Tasks; 14using System.Windows.Forms; 15namespace WindowsFormsApp8 16{ 17 public partial class Form1 : Form 18 { 19 public Form1() 20 { 21 InitializeComponent(); 22 } 23 private void button1_Click(object sender, EventArgs e) 24 { 25 label1.Text = "接続先URL1"; 26 label1.Refresh(); 27 string testurl = "接続URL"; 28 webBrowser1.Navigate(testurl); 29 } 30 string URL_ST = "検索したいURL1"; 31 string URL_TH = "検索したいURL2"; 32 string URL_NE = "検索したいURL3"; 33 string URL_SE = "検索したいURL4"; 34 private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 35 { 36 try 37 { 38 if (e.Url.ToString() == URL_ST) 39 { 40 //label1の表示変更 41 label1.Text = "ログイン処理"; 42 label1.Refresh(); 43 //1番目フレーム内のNameを取得 44 HtmlWindow iframe = webBrowser1.Document.Window.Frames[0]; 45 HtmlElementCollection elements = iframe.Document.All; 46 HtmlElement id = elements.GetElementsByName("userName")[0]; 47 HtmlElement pw = elements.GetElementsByName("pwd")[0]; 48 //ID・passを入力 49 id.InnerText = "admin"; 50 pw.InnerText = "password"; 51 //Submitボタンをクリック 52 HtmlElement login = elements.GetElementsByName("Submit")[0]; 53 login.InvokeMember("click"); 54 } 55 else if (e.Url.ToString() == URL_NE) 56 { 57 webBrowser1.Navigate("接続URL2"); 58 } 59 else if (e.Url.ToString() == URL_TH) 60 { 61 string filepath = (保存先); 62 // クッキーを取得する。 63 string cookieStr = webBrowser1.Document.Cookie; 64 // WebClientを生成する。 65 WebClient wc = new WebClient(); 66 Encoding enc = Encoding.UTF8; 67 // WebClientのヘッダ設定を行う。 68 wc.Headers[HttpRequestHeader.Cookie] = cookieStr; 69 label1.Text = "ダウンロード中"; 70 label1.Refresh(); 71 wc.DownloadFile("段ロードURL", filepath); 72 wc.Dispose(); 73          label1.Text = "ダウンロード完了"; 74 label1.Refresh(); 75 } 76 } 77 catch (Exception) 78 { 79 label1.Text = "例外の発生"; 80 label1.Refresh(); 81 } 82 } 83 } 84}

追記

追記

上記に変更したところ、ダウンロードは出来るようになりました。
このソースで記述的におかしい・こうしたほうが良いなどありましたらアドバイスお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/11/27 04:49

理由が分かりません。URL3 だけに Navigate すれば済む話のように思えますが、何か URL1, URL2 にも Navigate したいという理由があるのですよね。それな何ですか?
退会済みユーザー

退会済みユーザー

2018/11/27 04:57

今回は簡単に例文として記載させていただいているのですが、実際にはURL1(ログイン画面)→URL2(ログイン後しか見れないページにアクセス)といった感じになります。そういった関係上タブで新規で開くような動作は出来ないと想定して何か良い方法があればと思っています。
退会済みユーザー

退会済みユーザー

2018/11/27 05:18

では、URL1 ~ URL3 すべて DocumentCompleted の発生を待って順に処理を進めるべきだと思いますけど。特にログイン画面はそう。
退会済みユーザー

退会済みユーザー

2018/11/27 05:24

説明が下手で申し訳ありません。URL3のDocumentCompletedだけは特定の動作をしてURL1と2は待つだけの動作にしたいです。
退会済みユーザー

退会済みユーザー

2018/11/27 06:47

あなたの言っている意味が分かりません。何か思い違いがあるような気がします。とにかく、先の「URL1 ~ URL3 すべて DocumentCompleted の発生を待って順に処理を進めるべき」という私の意見は変わりません。そうしなくても良いという理由があれば説明してください。
退会済みユーザー

退会済みユーザー

2018/11/28 06:51 編集

諸事情により削除させていただきます。
退会済みユーザー

退会済みユーザー

2018/11/27 07:50

最初の話と変わってきているのでは? URL1 に Navigate したらイベントの発生を待って必要な処理をし、終わったら次のURL2 にNavigate ・・・というようにしてはいかがですか? 状況によっては(サーバーダウンとか)いつまで待ってもイベントが発生しないこともありますが、タイマーを使って何秒か待ってもダメな場合は中断するとか考えてみてください。
Zuishin

2018/11/28 06:48

できるようになったなら解決済みにしてください。リファクタリング作業を依頼するところではありません。親切でサービスすることはあっても基本的に自分でしてください。
Zuishin

2018/11/28 06:54

何の事情か知りませんが、削除しないでください。自分だけの質問ではありません。同じような問題を抱える他の人のための質問と回答でもあります。
guest

回答3

0

前回の質問の回答で、以下のことを書きましたが、これはフレーム構成でなくとも、外部ファイルの読込等で発生します。
(説明不足でしたね。ゴメンナサイ。)

ただし、そのページがフレーム構成(インラインフレームを含む)の場合、DocumentCompletedイベントが何度も発生する場合があります。

その場合、私はイベントハンドラの第2引数(WebBrowserDocumentCompletedEventArgs e)のUrlプロパティのUrl情報がナビゲートしたUrl(提示例ではWebBrowser1.Url)のそれと同じ場合、読込完了と判断しています。

恐らく、Webページ本体の読み込みが完了していないため、まだ読み込まれていない要素を参照しようとして今回のエラーになっている可能性があります。

試しに、DocumentCompletedイベントハンドラの第2引数(e)のe.Urlにどのような値がセットされているかウォッチしてみるといいかも知れません。

今回の回避策として試してほしいのは、DocumentCompletedイベントハンドラ内で、例えばif(e.Url.Tostring == WebBrowser1.Url.ToString)のような条件を付けることです。
(専門がVBのため、おかしなところがあるかも知れません。)
※関係演算子の誤りを修正しました。

C#

1 private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 2 { 3 if(e.Url.Tostring != WebBrowser1.Url.ToString) return; 4 5 // 後はやりたい処理を以下に書く 6 7 8 9 label1.Text = "接続先URL1接続完了"; //追記:ここでようやくラベル変更可能 10 }

追記

button1_Clickで、webBrowser1.Navigateの後にlabel1.Textを"接続先URL1接続完了"に書き換えていますが、これでは読込完了前にlabel1.Textが"接続先URL1接続完了"になってしまいます。
正しくは、DocumentCompletedイベントで対象のURLの読み込みが確認できてから、label1.Textを"接続先URL1接続完了"にすればよいです(上記コードの追記コメント参照)。

投稿2018/11/28 05:51

編集2018/11/28 06:20
kenshirou

総合スコア772

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2018/11/28 05:59 編集

`==` ですか? `!=` ではなく?
kenshirou

2018/11/28 06:04

ご指摘の通りです。何ともお恥ずかしい...(*μ_μ)
退会済みユーザー

退会済みユーザー

2018/11/28 06:51 編集

諸事情により削除させていただきます。
guest

0

ベストアンサー

DocumentCompleted はページだけでなく画像やスクリプトのダウンロードでも発生します。ラベルテキストで分岐すると、画像のダウンロードで name が userName となるタグが無い(html ではないので無くて当然です)ことになり、例外が発生します。

e.Url を見て何がダウンロードされたのか識別してください。

投稿2018/11/28 05:25

Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2018/11/28 05:57

あと、webBrowser1.Navigate が終わってもページの読み込みは終わっていないので接続完了と思ってはダメです。
退会済みユーザー

退会済みユーザー

2018/11/28 06:51 編集

諸事情により削除させていただきます。
guest

0

DocumentCompletedイベント内でURL2、URL3へNavigateすればいいのではないでしょうか?
どのURLへNabigateした時なのかはフラグでも設ければいいのではないかと

投稿2018/11/27 11:35

YAmaGNZ

総合スコア10258

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問