下記のPerlスクリプトはpdfファイルか否か確認してpdfならダウンロード、それ以外なら簡易にファイル種類を表示させています。
しかし、このスクリプトには問題があり「my $res = $ua->get( $url );」で$urlのファイルの容量が大きいとOut of memory!と表示されスクリプトが停止してしまいます。
どのようにすれば解決しますでしょうか?
宜しくお願い致します。
perl
1$| = 1; 2use strict; 3use LWP::UserAgent; 4 5my @url = ('https://XXXXXXXXXXXXXXXXXXX/a.pdf', 6 'https://XXXXXXXXXXXXXXXXXXX/b.pdf' 7 ); 8my $count = 0; 9for my $url (@url){ 10 $count++; 11 my $ua = LWP::UserAgent->new; 12 $ua->timeout(10); 13 my $res = $ua->get( $url ); #★ここが問題点★ PDFファイルが大きすぎるとOut of memory!がでて止まる 14 my $source = $res->content; 15 if(substr($source,0,10) =~ m/pdf/i){ 16 print "PDF file-$url\n"; 17 open(F,">${count}.pdf"); 18 binmode F; 19 print F $source; 20 close F; 21 next; 22 } 23 if($source =~ m/<html/i){ 24 print "HTML-$url\n"; 25 next; 26 } 27 print "OtherFile-$url\n"; 28 29}
perl out of memory
で検索するとそれなりに解決策が出てきますが、それでは足りませんでしたか?
コメントいただきありがとうございます。
ファイルとして保存する方法までは見つかったのですが、データの一部をちょっとだけ確認してその後に保存したりしなかったりということができず困っている感じになります。質問がわかりにくくすみません。
どこまで把握しているかは質問内容に書いてあることが全てですので、調べたこと試したことを追記してください。
仮想メモリを増やしてから実行してみてはいかがでしょうか。
仮想メモリを増やせばなんとかなるかもしれません。
m.ts10806 さま
数日掛けて大量に調べていますのでどこまで書いて良いものか・・・
一応、このプログラムに直接関係して可能性があるものとしては、このようにして一時ファイルを作成。
これを解析して削除またはリネームで保存という方法がおそらく英語のサイトだったと思いますがとりあえず止まらずに動く方法としては見つかりました。その後ファイル判定して削除するものです。
$count++;
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
my $req = HTTP::Request->new( GET => $url);
my $res = $ua->request( $req, "temp${count}");
ただ、すべてのファイルをHDDに保存する必要があれば最適ですが、今回は必ずしもその必要性がなくできればもう少し良い方法がないか気になっています。
他にはHDDではなくすべてメモリにダウンロードしてそこでファイル解析してHDDへの保存可否を決める感じです。いろいろ調べているとpythonという言語では
img_bin = BytesIO()
img.save(img_bin , "PNG") #PNG圧縮されたバイト列としてメモリに保持
この様にHDDに保存せず一度メモリ上に保存できそれを解析することもできるそうです。
perlに同じ機能があれば便利ですが良い方法が見つかりませんでした。
他にも例えば、全てをダウンロードしなくても先頭の辺りだけ少し読んで中身をチェックしてその結果で判定してダウンロードなどあれば良いのですがこれも良い方法が見つからずという感じです。
回答1で教えていただいた方法はかなり良いと思っていますが、サーバの返してくるヘッダー情報はかならずしも正確ではないと思います(以前アップロードするものを作った時にヘッダーを作成したのですが間違えて書くことも可能でしたので)のでもう少し良い方法があればと思っています。
tatsu99 さま
Windows 10を使っているのですが、メモリ使用率を見る限りまだ十分に余裕がありますのでこれでは解決しませんでした。
代表的なもので結構ですので、おおよその方向性がわかれば良いです。
ただ、こちらのコメント欄ではデフォルト非表示で埋もれますので本文編集して追記願います
色々な実験していますので方向性はない感じです。強いて言えば数年以内にスパイダーみたいなものができればいいと思っていますが先はかなり長いです。また、上記のように色々やっていますので全て書くと流石に論点がぼやけますので、Out of memory!の部分に可能な限りフォーカスして質問するのが良いかと思いシンプルに書いたつもりです。今のところ、サンプロプログラムをコピーして、一つずつエラーを潰していくようなスタイルで勉強しています。
なお、こちらは公開されていないということであればちょっと気になるのが、
https://www.meti.go.jp/report/whitepaper/mono/2019/honbun_pdf/pdf/honbun_01_04_.pdf
にアクセスするとOut of memroy!になりました。
実際には膨大なPDFと想定できるユニークなドメインのファイルリンク集を使っています。
ただ、再現性無し、こちらはデータ容量も小さいはずですが様々なPDFやHTMLファイルにアクセスしていると
my $res = $ua->get( $url );
でOut of memroy!となっていました。また、エラーメッセージが表示されないため場所を特定するのに、
その上下にはprint __LINE__ . "\n";を記載して突き止めた感じです。
また、
$ua -> max_size(2000000);
というものを入れても
Out of memroy!
となり
my $res = $ua->get( $url );
で止まっていました。なお、URLは上記とは異なりました。
はじめのコメントのperl out of memoryについては一応見ており、当初は容量オーバーかと思い質問したのですが、容量オーバーというわけではないのかもしれません。また、今、perl out of memoryで検索すると私の質問が上位でヒットしました。こちらに質問すればこれへの対処法が容易にわかるかと思ったのですが、結構レアなエラーなのでしょうかね?
とりあえず、原因まで不明となりよく分からなくなっています。
evalでエラーをキャッチして飛ばす方法も見つけたのですが、out of memoryについてはそれも使えずデバッグ難しいですね。
こちらのコメント欄ではデフォルト非表示で埋もれますので本文編集して追記願います
そもそも、たかがpdfひとつダウンロードしただけでout of memoryというのがとても不自然な状況に思えます。perlを使わずにwgetなどで取得することは問題なくできるのでしょうか。その場合、そのpdfファイルのファイルサイズはどれぐらいですか。
なお上で提示されているURLはリンク切れしています。状況が再現できる正しいURLを提示していただければ助かります。
m.ts10806 さま
大量にコメントしており文章の下手な私が下手に編集すると意味がわからなくなりそうですので、今の質問説明文のほうが良いかと思っています。当方、こちらを利用するのはほぼ初めてで使い方をよくわかってないところがあるのですが、他の方の質問を見てもかなりシンプルであとからの利用がしやすく、できれば私の質問もあとから外国人を含め他の方が見てもすぐに分かるような質問になればいいと思っています。
KojiDoi さま
説明不足ですみません。リンク先が消失しているものも含めてアクセスしています。そのため、上記URLで正しいものとなります。
ただ、out of memoryとなりファイル内容を取得することができず内容がつかめずデバッグが進まない感じです。また、直後に同じURLにアクセスしても再現性がなく何が起こっているのか推測するしかない感じです。一応、こちらが正しいURLになります。
https://www.meti.go.jp/report/whitepaper/mono/2019/honbun_pdf/pdf/honbun_01_01.pdf
なお、PCの異常も考えたのですが、YahooAPIなどでは何日使っても一度も落ちたことがないため雑多なURLを大量にアクセスしていると落ちる事があるようです。
回答2件
あなたの回答
tips
プレビュー