トップ回答者
WEB上のデータ取得時にエラーが発生

質問
-
おはようございます。
以下のような記述で、WEB上のデータを取得しようとしているのですが、かなりの頻度で
WEBページからソースが取得できません。
'Webページのソースを読み込むプロシージャ
Public Function GetWebPageSource(ByVal URL As String, ByRef source As String, _
ByVal charcode As String) As Boolean
Dim Request As WebRequest
Dim Response As HttpWebResponse
Dim DataStream As Stream
Dim Reader As StreamReaderTry
'指定されたURLへのリクエストを生成する
Request = WebRequest.Create(URL)'レスポンスを得る
Response = CType(Request.GetResponse(), HttpWebResponse)'データストリームを得る
DataStream = Response.GetResponseStream()'Webページのソースを読み出すためのストリームリーダーを生成する。
Reader = New StreamReader(DataStream, Encoding.GetEncoding(charcode))'WEBページのソースを読み出す
source = Reader.ReadToEnd'後始末をする
Reader.Close()
DataStream.Close()
Response.Close()'戻り値を返す
GetWebPageSource = TrueCatch ex As Exception
GetWebPageSource = False
End Try
End FunctionPublic Sub Get_New_Dailydata()
Dim Source As String = ""
Dim Result As Boolean
Dim r As Regex
Dim Regsource As String
Dim m As Match
Dim i As Integer 'ループ変数
Dim j As Integer
Dim Writer As New IO.StreamWriter("C:\DailyData.txt", True)
Dim StartCode As Integer
Dim EndCode As Integer
Dim Zenjituhi As Integer
Dim Zenjituhi_Temp As String'カウンター表示ラベルのテキストを削除
'lbl_Counter.Text = ""'銘柄数を格納する配列
Dim StockCode As String
StartCode = 1300
EndCode = 9999'1300~9999までのすべての銘柄をチェックし、該当するものをテキストファイルに書き込み
For i = StartCode To EndCode Step 50
StockCode = ""'取得する銘柄コードのリストを作成
For j = i To i + 49
If StockCode = "" Then
StockCode = j
Else
StockCode = StockCode & "+" & j
End IfIf j = EndCode Then
Exit For
End If
Next'株価データを読み込む
Result = GetWebPageSource("http://quote.yahoo.co.jp/q?s=" & StockCode & _
"&d=v2", Source, "EUC-JP")If Result = False Then
MsgBox("株価データの取得に失敗しました。")Exit Sub
End If'正規表現で株価等のデータを検索する。
Regsource = "<td nowrap align=left><a href=.*?>(.*?)</a></td><td nowrap align=left>" _"<small><img src=.*? alt=.*? width=20 height=15 align=absmiddle>" _
"<b>(.*?) </b></small></td><td nowrap align=center>(.*?)</td>" _
"<td nowrap><b>(.*?)</b></td><td nowrap>(.*?)</td><td nowrap>(.*?)</td>" _
"<td nowrap>(.*?)</td><td nowrap>(.*?)</td><td nowrap>(.*?)</td><td nowrap>(.*?)</td>"
r = New Regex(Regsource)
m = r.Match(Source)'テキストファイルに日足のデータを書き込みする。
While m.Success
Zenjituhi_Temp = Replace(m.Groups(5).Value, "<font color=ff0020>", "")
If Replace(Zenjituhi_Temp, "</font>", "") = "---" Then
Zenjituhi = 0
Else
Zenjituhi = Replace(Zenjituhi_Temp, "</font>", "")
End IfWriter.WriteLine(m.Groups(1).Value & " " & m.Groups(2).Value & " " & _
m.Groups(8).Value & " " & m.Groups(9).Value & " " & m.Groups(10).Value & " " & _
m.Groups(4).Value & " " & Zenjituhi & " " & m.Groups(7).Value)m = m.NextMatch
End While'現在の進行状況をカウンターに表示
My.Application.DoEvents()
frm_menu.lbl_Counter.Text = i & "件終了 / " & EndCode & "件中"
NextWriter.Close()
End Subこちらはモジュールに記述をしてあり、フォームのコマンドボタンクリックにて実行するようにしてあります。
できる場合もあるのですが、できないことが多く、できない場合は、「GetWebPageSource」で
起こっているようです。
自分でも、調べている最中ですが、何か原因となるようなことがありましたら、ご教授いただけませんでしょうか。
どうか、よろしくお願いします。
回答
-
私も以前、同じ問題にぶつかりました。定かではありませんが、短時間に多数のアクセスをするとサーバーから切断されるようです。どのような仕様になっているのかはわかりませんが、私の場合、全銘柄の4本値を正常に取得できる時もあれば、途中で切断されるケースも多々発生しました。
以下にもそのようなことが書いてありますね。
機能部品(DLL/ソース) 情報収集 Yahooファイナンス情報取得DLL
http://invest-prg.rich-prj.com/p_lib/dll_dg_yahoo.htmlYahoo!ファイナンスから株価を取得するということであれば、切断されることを前提にプログラミングするしかないでしょう。
もしくは一定のウエイトを置くなどの工夫が必要だと思います。
#ご存じのようにYahoo!ファイナンスから株価を取得するアプリは多数存在しますので、ひょっとすると何か逃げ手があるのかもしれないなぁとは思ったりしますが・・・。ただ、サーバーの対策はいつ変わるかわかりませんので・・・。全銘柄をスクリーンスクラッピングされることが多数発生すると、結構な負担がサーバーにかかるでしょうし。
すべての返信
-
TI-cb400s さん、こんにちは
ダッチです。
TI-cb400s さんからの引用 自分でも、調べている最中ですが、何か原因となるようなことがありましたら、ご教授いただけませんでしょうか。
どうか、よろしくお願いします。
なぜそうなったかの原因をつかむには、まず GetWebPageSource メソッドで例外をキャッチしたときの ex の中身を見ることで原因がわかるかもしれません。
ちなみに私の環境で数回ほど動かし見ましたが、例外は発生しませんでした。
-
外池と申します。
「取得できません」だけでは、情報が不足です。
どのような状況に遭遇して「できない」とご判断されているのでしょうか? エラーが発生する? それとも、エラーは発生しないものの長い時間処理が止まってしまう? 処理が終わるのに得られたデータがまったく意図したものではない?
GetWebPageSourceだけを拝見しましたが、
エラーの発生への対処として、Try Catchの作り方が大雑把すぎます。処理ごとにわけてTry Catchを作ってください。で、処理ごとに正常・エラーの確認をしましょう。エラーが発生したらどのようなエラーなのか出力するようにしましょう。
処理が止まってしまうような場合の対処として、まずは、非常に簡単なWebサイトで試してください。フレームに分かれていない単一のページ、文字数が少ないページで、正しくデータが得られることを確認してください。その上で、以下、重要なのですが、複雑なWebのページでは、1回の読み取り操作ですべてのソースが得られるとも限りません。私は、同様のプログラミングでは、非同期実行でしか書いたことがないので、そのときは、何回か読み取り操作が必要になるケースがありました。いわゆる「Chunked」なページの場合です。Chunkedなページの場合、同期実行の場合どうすればよいのか、ドキュメントで調べてください。
最後に、意図しないデータを得てしまうケースですが・・・、提示された後半のコードから推察するに、yahooのページですよね。非常に高度なサイトを相手に、この手のツールを開発するのは、大変なことです。と言うのも、yahoo側も特殊なツールを排除するような仕組みを持っているかもしれません。サーバー側ではアクセスしてきているクライアントがどのブラウザを使っているかを識別する機構があって、不明な場合は拒否の応答が返えすことも可能なのです。あるいは、yahooの適切なページからクリックしてあるページに移動しないと、つまり、ひとつ前に適切なページを一度ひらいていないと、やはり拒否の応答が返すようになっているかもしれません。
このあたり・・・、VBの知識というよりも、まずは、http通信の知識が必要で、その上で、.Net Frameworkのネット操作関連のクラスライブラリーに精通しないと難しいところです。
-
私も以前、同じ問題にぶつかりました。定かではありませんが、短時間に多数のアクセスをするとサーバーから切断されるようです。どのような仕様になっているのかはわかりませんが、私の場合、全銘柄の4本値を正常に取得できる時もあれば、途中で切断されるケースも多々発生しました。
以下にもそのようなことが書いてありますね。
機能部品(DLL/ソース) 情報収集 Yahooファイナンス情報取得DLL
http://invest-prg.rich-prj.com/p_lib/dll_dg_yahoo.htmlYahoo!ファイナンスから株価を取得するということであれば、切断されることを前提にプログラミングするしかないでしょう。
もしくは一定のウエイトを置くなどの工夫が必要だと思います。
#ご存じのようにYahoo!ファイナンスから株価を取得するアプリは多数存在しますので、ひょっとすると何か逃げ手があるのかもしれないなぁとは思ったりしますが・・・。ただ、サーバーの対策はいつ変わるかわかりませんので・・・。全銘柄をスクリーンスクラッピングされることが多数発生すると、結構な負担がサーバーにかかるでしょうし。
-
ご回答ありがとうございます。
エラー処理については、個人でしか私用しないものばかり作っていたため、
勉強を怠っており、現在勉強中ですので、未熟な部分については、ご容赦
ください。
エラーとしては、エラー処理としてある、「株価データが取得できませんでした。」
というものが帰ってくるのですが、URLも間違ってはおらず、ブレークポイントを
つけ、ひとつずつ処理を追っていくと、ホームページのソースが取得できず
上記のエラーとなります。
trapemiyaさんがご回答いただいたないようですと、納得がいきます。
できない状態で、しばらくしてから再度実行すると、うまく取得できたり
もします。
よい機会なので、エラー処理についても、しっかりと勉強したいと
思います。
ご回答いただきました、皆様、本当にありがとうございます。