- ベストアンサー
URLから任意の数字を取得して演算後、一定の条件をもとにグラフ化するプログラムを作りたいです。
みなさん、はじめまして。僕は最近あるプログラムを作りたいためにプログラミングを始めました。C言語からプログラミング始めたのですがC言語の途中(本によって進行の違いが若干ありますが条件分岐くらいまでやりました。)で、「本当に自分の好きなプログラムがつくれるようになるのかな?」と疑問に感じ、いろいろ調べていくうちにどうやらやりたい事はPerlのほうが適しているとわかりましたのでPerlの勉強に変えようと思いました。 しかし、いざPerlの勉強をしようと思ったのはいいものの実際に何をすれば(どんな書籍を購入して勉強すれば)思うようなプログラムを作れるのかが全然わかりません。努力は決して惜しみませんが方法をお教えして頂けますと非常に助かるのですがどうでしょうか。よろしくお願い致します。 ※申し訳ありません。なんか次数制限でひっかかっちゃったのでやりたい動作についてはタイトルに一様あるのですがタイトルではやはり言葉足らずかと思いますのでどなたかのなんらかの回答の後に補足の欄に追記させて頂きます。ほんとに申し訳ありません。恐縮です。。
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
まず問題を整理しましょう。 omni2さんがANo.3 で書かれたサンプルコードは、目的のURLからHTMLソースを取ってきてファイルに保存するものです。 私がANo.5 で書いたサンプルコードは、HTMLソースが行ごとに格納された配列から、セルに分割して別の二次元配列に格納するものです。 まずはこの2つを連結させると、「目的のURL→二次元配列」というものができるわけです。 で、どうやって連結させるか、すなわちデータを受け渡すかですが、 渡す方、つまりomni2さんが書かれたサンプルコードのほうは、最終的にファイルに書き出して(ファイルに渡して)います。 受け取る方、つまり私が書いたサンプルコードのほうは、配列 @html_line に全行が入っている前提に(配列が受け取り口)なっています。 ということは、omni2さんのコードのほうで、ファイルに書き出さずに配列 @html_line に入れるだけ、というように変更し、私のコードのほうはそれを受け取るだけ、というようにつなげればいいことになります。 (omni2さんのANo.6 ではファイルに一度書き出して再び読み込む方法ですが、私はファイルを介する必要はないように思います。) 具体的には、ファイルに書き出す部分は単に削除すればいいだけですが、取ってきたデータを行ごとに分割して配列に入れるためには、「改行」で区切って配列に入れます。 $data = get($url); ↑これで $data に「全行がつながった文字列」が入りますが、これを、 @html_line = split(/\n/, get($url)); ↑このように変更すれば、取ってきたデータが改行で区切られて @html_line という配列に格納されます。これでOKです。 まとめると以下のようになります。実行させてみてください。 ------------------------- use LWP::Simple; # HTMLデータを取得 $url = 'http://table.yahoo.co.jp/t?s=7202.t&g=d'; @html_line = split(/\n/, get($url)); # 二次元配列に格納 foreach (@html_line) { if (/^align=right bgcolor="#ffffff"><td>(.*)(?:<\/td><\/tr><tr|<\/td><\/tr><\/table><\/td><\/tr><\/table>)$/) { $data_found = 1; push(@data_table, [map { s/<[^>]*>//g; $_; } split(/<\/td><td>/, $1)]); } elsif ($data_found) { last; } } print "上から 1 番目の「出来高」は $data_table[0][5] です。\n"; print "上から 3 番目の「終値」は $data_table[2][4] です。\n"; print "上から 10 番目の「始値」は $data_table[9][1] です。\n"; ------------------------- HTMLソースをファイルに書き出さない理由は、それが不要であることと、ファイルに書き出すのは二次元配列に分割した後にすれば、CSV として書き出せばそのままエクセルで開くことができるなど、何かと便利だから、ということもあります。
その他の回答 (6)
- omni2
- ベストアンサー率53% (33/62)
use LWP::Simple; $url="http://table.yahoo.co.jp/t?s=7202.t&g=d"; $data=get($url); my $filename = 'test1.txt'; if(open(WRITE,"> $filename")) { print WRITE $data; close(WRITE); } if(open(READ,"< $filename")){ @html_line = <READ>; close(READ); } foreach (@html_line) { if (/^align=right bgcolor="#ffffff"><td>(.*)(?:<\/td><\/tr><tr|<\/td><\/tr><\/table><\/td><\/tr><\/table>)$/) { $data_found = 1; push(@data_table, [map { s/<[^>]*>//g; $_; } split(/<\/td><td>/, $1)]); } elsif ($data_found) { last; } } print $data_table[0][5]; こうしてみればどうでしょう?
お礼
できました!自分の書いたコードでは不足部分があったようですね。ご指摘有り難うございました。
- taseki
- ベストアンサー率66% (155/233)
LWPに関してはomni2さんが回答されているので、その取得したHTMLソースから目的のデータを得る方法について。 目的の個所を検索してそのデータだけ取得、とするよりも、tableを解析して配列に分割していく、という方法が良いかと思います。 その理由は、 ●効率的であること ●汎用性が上がる、たとえば将来的に「出来高」以外の項目も取得したくなったときそのまま使えたり、表をCSVに出力する、など応用が利くこと ●Yahoo側で表示形式などを変更した場合に、対応しやすいこと ●解析しやすいこと などがあると思います。 大まかな流れとしては、 1.メインのtableを見つける 2.行を抜き出し、セルに分割して配列に格納する 3.上記2を最終行まで繰り返す という感じです。 具体的な処理は、以下のようになります。 1の「メインのtableを見つける」方法ですが、HTMLソースを見る限り、少なくとも現時点では「“align=right…”で始まって“…</tr><tr”で終わる行」が、目的のtableのデータ行のようです。3の「最終行まで繰り返す」という判断も、「この形式の行の連続が切れたら終了」としてよさそうです。ただし最終行だけ形式が若干異なります。 そしてセルの分割ですが、 ★</td><td>★</td><td>★</td><td>★ というように「</td><td>」によって区切られていると判断すれば良いでしょう。<td>の中にさらにタグがあっても、とりあえず無視してセル単位で分割しておいて、その後で不要なタグを削除すればいいと思います。 以下がサンプルコードです。 (LWPで取得したデータをファイルに保存する必要はありません。@html_lineに全行が入っているとします。) ------------------ foreach (@html_line) { if (/^align=right bgcolor="#ffffff"><td>(.*)(?:<\/td><\/tr><tr|<\/td><\/tr><\/table><\/td><\/tr><\/table>)$/) { $data_found = 1; push(@data_table, [map { s/<[^>]*>//g; $_; } split(/<\/td><td>/, $1)]); } elsif ($data_found) { last; } } ------------------ これで、表がすべて @data_table 配列の中に格納されます。 $data_table[行][列] で参照できます。 「出来高」は5番目なので添え字は 4 になります。たとえば上から1つ目の「出来高は」 $data_table[0][4] 2つ目なら $data_table[1][4] 8つ目なら $data_table[9][4] というように参照できます。 後は好きなように計算してください。 グラフ化については、時系列なので折れ線グラフになると思いますが、折れ線グラフはGDなどのグラフィックモジュールを使う必要があります。棒グラフならHTMLだけで表現できますが。
補足
誠に具体的かつ親切なご回答心から感謝致します。正規表現以外の方法でデータが得られるとは夢にも思いませんでした。新しい驚きと発見を有り難うございます。そして正規表現以外で具体的に任意のデータを取得する方法は、メインのtableを見つけ、行を抜き出しセルに分割して配列に格納するとの事ですが、本当に"なるほどー"の一言です。 が、しかし一番重要な問題にぶつかってしまいました。。そうです、、実力が無いのです。。(親切にサンプルコード書いて頂きましたが、これをどう活用すればよいのかも分からないほど。。汗) 大変、大変恐縮なのですが自分でいろいろやってみただけでは (試したほんの一例ですが、 =============================================== use LWP::Simple; $url="http://table.yahoo.co.jp/t?s=7202.t&g=d"; $data=get($url); # ここでURLのデータを全て取得 foreach (@html_line) { if (/^align=right bgcolor="#ffffff"><td>(.*)(?:<\/td><\/tr><tr|<\/td><\/tr><\/table><\/td><\/tr><\/table>)$/) { $data_found = 1; push(@data_table, [map { s/<[^>]*>//g; $_; } split(/<\/td><td>/, $1)]); } elsif ($data_found) { last; } } #ここでURLのデータから好きなデータ(出来高)だけを取り出す。 my $filename = 'test1.txt'; if(open(WRITE,"> $filename")) { print WRITE $data; close(WRITE); } #ここでtest1に書き出す =============================================== というのでもできませんでしたが、だめ押しで最後の行にprint "$data_table[0][4]";と入れてみてもやはりただURLのデータをtest1に書き出すだけでした。) やはり取得してきたデータ同士を計算して書き出す(CSV形式などに)という事がどうしてもわからないのですが、よろしければサンプルコードをもっと具体的に(書いて頂いたのだけでも本来は十分なのですが)書いて頂けないでしょうか。本当に何から何まで申し訳ありません。
- ex-aes
- ベストアンサー率20% (1/5)
私はperl初心者ですので、的確なアドバイスではないかもしれません。 私は少し前、大量のデータを集め(このデータはHTMLのFORMを使って利用者から集めた。)、perlにて計算したあとに計算結果をHTMLのTABLEを使ってグラフ化するページを作りました。 具体的には・・・ (1)集めたデータをperlの配列などに格納して計算し、その結果をファイルに書き出して保存しておく。 (2)書き出したデータをの値をTABLEのセルの大きさに対応させてグラフ化する。 って感じです。プログラム自体は簡単です。また、スタイルシートなどを使えばグラフはエクセルよりもきれいにできるはずです。 質問者さんの期待するような回答ではないかもしれませんが、やりたいことを実現するためには様々な方法があると思います。参考になれば幸いですし、参考にならなければ聞き流して下さい。
補足
ご回答誠に有り難うございます。僕がやりたいと思っていることはまさにex-aesさんが過去に行ったものと非常に似ている物かと思います。プログラムを作る方法は何通りもあると聞いているのですが、ex-aesさんの方法も是非ともお教えして頂けますと大変ありがたいと思います。よろしければお願い致します。
- omni2
- ベストアンサー率53% (33/62)
$data=get($url); これで、$data変数の中に取得したデータが入っていますから、ファイルに書き出してやればいいだけです。 my $filename = 'test1.txt'; if(open(WRITE,"> $filename")) { print WRITE $data; close(WRITE); } を書き加えてみましょう。 実行している.cgiもしくは.plファイルと同じ位置に"test1.txt"が作成されているはずです。 ただ、LWPはもっと便利になっていて、 データを取得して、同時にファイルに書き出すことができます。以下、test2.txtファイルに書き出してます。 #################################### #!/Perl/bin/perl print "Content-type: text/html\n\n"; use LWP::Simple; if(mirror('http://table.yahoo.co.jp/t?s=7202.t&g=d','test2.txt') == RC_OK){ print "取得に成功<BR>\n"; } else{print "取得に失敗<BR>\n";} #################################### こんな感じでしょうか? まちがってたら、他の方がなおしてくれます。 LWP::UserAgentをつかうなら、こんな感じかな? test3.txtファイルに書き出してます。 #################################### #!/Perl/bin/perl print "Content-type: text/html\n\n"; use LWP::UserAgent; my $ua = LWP::UserAgent->new; my $response = $ua->mirror('http://table.yahoo.co.jp/t?s=7202.t&g=d','test3.txt'); if( $response->is_success){ print "取得に成功しました<BR>\n"; } else{ print "取得に失敗しました<BR>\n"; die $response->status_line; } #################################### 以上ここまでは、わかりましたか?
お礼
忙しくて返事が遅れてしまいました。大変申し訳ありません。結果のほうなのですが、test1もtest2も無事書き出せました。(ただしなぜかtest1とtest2は違ったものとなりましたが)有り難うございます。
- omni2
- ベストアンサー率53% (33/62)
1、http://table.yahoo.co.jp/t?s=7202.t&g=dここから出来高だけの値を取得。 上のページを取得するには、PerlのLWPを使用すればできます。 LWP::Simple、または、LWP::UserAgent を検索すれば使用方法が出てくるとおもいます。 わからなければ、また、きいてください。 取得できたら、正規表現で出来高のデータだけを取得すればいいと思います。 2、取得した値同士を足したり掛けたりして計算をします。 1で値が取得できてますから、perlでもご自由に計算できます。ただし、複雑な計算または、データ量が膨大だとperlだと時間がかかると思いますけど。。試してください。 3、出てきた値が例えば20以下なら(条件を20以下とした場合)出来高の値をグラフ化します。 エクセルで、グラフ化を、perlで自動的にできるかどうかは私にはわかりません。他の方が答えてくれます。 この質問で回答が得られないときは、perlでエクセルのグラフを書く方法??とかいう題名で再度質問されてはいかがでしょうか? CSV形式のファイル等に、処理したデータを書き出して、手動でエクセルにデータを流し込むってことはできそうですが。 perlにはGDというグラフを書いたりできるものもあるので、そちらがよければ勉強してみてください。 「perl GD」とかで検索すれば出てくると思います。 4、そしてグラフ化した場合はWindows起動時に知らせる、メールで知らせるなどをしてユーザーに知らせてくれるようにするというものです。 グラフ化したら、ということは値が20以下になったらってことですよね。グラフ化したら、メールを送るというよりは、計算結果が20以下なら、メールを送るにすればいいのではないでしょうか? 20以下の値がでたら、 sendmailなどで、会員に?メール送信しましょう! 「sendmail」 とか 「perl メール送信」とかで、 サンプルも出てくるとおもいます。
お礼
omni2さん、おはようございます。 LWP::Simpleはとてもシンプルにデータを取得でき、LWP::UserAgentは動作的なものまで取得したい場合にどうやら適しているらしいですね^^ 出来高だけを取得したい場合は正規表現でふるいにかければOKという事ですがちょっと調べただけではやはり理解できませんでしたので今日も時間を作って調べたいと思います。 取得してきた値を計算するについてなのですがデータが膨大だと時間がかかるのですかぁ。でも、逆にいいますと時間さえかければやってくれるという考えでいこうと思います。 エクセルについては確かにエクセルに関して質問するのが最適だったと今少し悔やんでおります。申し訳ありませんでした。GDというのがあるのですかぁ。これまた情報ありがとうございます。 ユーザーに知らせる機能についてなのですが、あれからいろいろ考えた結果、perlで計算し終えたら任意でWindowsを終了し(WinRarの圧縮後PCの電源を切るというような機能です)次回起動時に条件を満たしグラフを作成した場合にユーザー知らせるという機能にしたほうがよいかなと思ったりもしました。もっとよく考えて発言するべきでしたのに、メールでしらせる機能があれば便利かなと思い軽はずみでそういう事をするためにはどうしたらよいかなどと聞いてしまい、本当にすみません。しかし今後メールに送りたい場合にsendmailはとても有効な手段となると思いますのでしっかり頭にいれたいと思います。 omni2さんのおかげで大分流れが分かってきました。つまり、 1、LWP::Simpleでデータを取得して正規表現でふるいわけ。 2、perlでそれを計算。 3、エクセルについてはまだわかりませんが、GDというやつを使えばできそう。 4、注文を変更してしまいましたので (perlで計算し終えたら任意でWindowsを終了し(WinRarの圧縮後PCの電源を切るというような機能です)次回起動時に条件を満たしグラフを作成した場合にユーザー知らせるという機能) 完全に自分が悪くかつ申し訳ないのですが、これについては調べたり質問させて頂いたりしたいです。 以前、どうやったらやりたい事ができるのかともがいていた時期がありましたが具体的な流れが今現実として認識できて本当に嬉しくありがたいことだなぁ。と思っています。本当に有難うございます。
補足
あれからLWP::Simpleについて調べましたら、どうも use LWP::Simple; $url="http:// ここに好きなURLを入れる "; $data=get($url); これだけでLWP::Simpleが使える事がわかりやってみたのですが、どこに取得したデータが保存されているのか分かりません。CドライブにそれらしきXMLファイルが現れましたがうまく表示されませんでしたので拡張子をtxtに変えて表示しましたら、 <?xml version='1.0' encoding='ISO-8859-1'?> と書いてありました。しかし、なんのことやらさっぱり。。もしよろしければLWP::Simpleの使い方をお教えして頂けないでしょうか。 正規表現についてなのですがhttp://table.yahoo.co.jp/t?s=7202.t&g=dのソースを見る限りでは、出来高だけ取得するという事は困難かと思うのですがどうしたらできるのでしょうか。なんか出来高だけマッチさせる方法があるのでしょうか。いろいろ自分なりに調べたのですがどうしてもわかりませんでしたので質問させて頂きました。もしよろしければご回答お願い致します。
- ABC_CBA
- ベストアンサー率0% (0/1)
僕は最近プログラミングはじめようと思っているのですが、どの言語やろうか迷っていています。 タイトルからの大よその判断ですが、Dblさんが言うような事をperlという言語はできるのですかぁ。なんかperlって凄いですね。
補足
実はperlでやりたい事が完全にできるという事はまだ僕もプログラミング始めたばかりで断定できません。(すみません、全くの初心者です。。)ただなんかperlを使うとURLから値を取得できるらしいので、やりたい事もできるかな?と思って質問させて頂いています。申し訳ありません。 以下に作りたいプログラムの詳しい動作を書かせて頂きます。 1、URLから任意の文字列を取得。 2、取得した値同士を自由に計算。 3、計算結果の値に条件を作り、グラフを作る(エクセル等で)か作らないかを決める。 ※この場合のグラフは取得してきた数字をグラフ化するものであります。 4、グラフを作った場合にユーザーに知らせる。 抽象的なものなので言いたい事が伝わりにくいかと思いますので、具体的に申しあげさせて頂きますと例えば 1、http://table.yahoo.co.jp/t?s=7202.t&g=dここから出来高だけの値を取得。 2、取得した値同士を足したり掛けたりして計算をします。 3、出てきた値が例えば20以下なら(条件を20以下とした場合)出来高の値をグラフ化します。 4、そしてグラフ化した場合はWindows起動時に知らせる、メールで知らせるなどをしてユーザーに知らせてくれるようにするというものです。 こんな事をやりたいのですが、皆様ご指導のほど何卒よろしくお願い致します。
お礼
非常に詳細な説明有り難うございます。お陰様でなぜ自分のコードでは駄目かがよくわかりました。しかし理由がわかると大変気持ちがよいものですね。できた喜びももちろんですが、コードの意味を理解できた喜びも大きいです。本当に有り難うございました。