![注目を集める絵](https://habrastorage.org/files/a55/67e/76e/a5567e76ea09433fa53943bc7fc103ed.png)
本があればいいです
そして反対が悪いとき
エピグラフの代わりに
誰もが知っているように、最近、books.ru で多数の電子書籍を適正な価格で取得できる可能性があるアクションがありました 。 ユーザーicozはバッチダウンロード用のスクリプトを作成しましたが、本は不快な名前で保存されており、手動でダウンロードする必要があるため、スクリプトはあまり便利ではありません。
一般的に、私はすべてが便利で自動であるべきだと自分に言いました。それは「明日行われる」ことで知られているように、明日行われる販売に照らして特に重要です。
ステップ1 必要なモジュールを接続します。
必要になります
use WWW::Mechanize; use HTTP::Request::Common; use LWP; use LWP::UserAgent;
モジュール自体と、それが依存するいくつかのサービスモジュール。 私がUbuntuを使用しているように、WWW :: CPANからのMechanizeのダウンロードは禁忌ですが、代わりに言う方が良いです
sudo apt-get install libwww-mechanize-perl
ステップ2 機械化オブジェクトを作成し、コマンドラインからスクリプトパラメーターを取得します:ログインとパスワード。
my $mech = WWW::Mechanize->new(); $booklog = $ARGV[0]; $bookpsw = $ARGV[1];
ステップ3 サイトにログインする
my $resp = $mech->get('http://www.books.ru/member/login.php'); $mech->cookie_jar->set_cookie(0, 'cookie_first_timestamp',DateTime->now->epoch, '/', 'www.books.ru'); $mech->cookie_jar->set_cookie(0, 'cookie_pages', '1', '/', 'www.books.ru'); $resp = $mech->post('http://www.books.ru/member/login.php',[ 'login' => $mail, 'password' => $password, 'go' => 'login', 'x' => rand_from_to(40, 50), 'y' => rand_from_to(1, 20), 'token' => '' ]);
2行目と3行目に注目します。元のコードでは、これらのCookieはJavaScriptを使用して生成されますが、2つのパラメーターを計算するためだけに、JavaScriptの接続は合理的ではなく、簡単に書き換えることができます。
ステップ4 注文の一般的なリストを取得し、イテレータを作成します:
$resp = $mech->get('http://www.books.ru/member/orders/'); my @order_list = mkGunz($resp->content) =~ /\<a\shref=\"http:\/\/www\.books\.ru\/order.php\?order\=(\d+)\"\>/gi; foreach my $order_id (@order_list) {...}
サーバーがgzipを使用してデータを圧縮すると、自動的にデータを解凍するmkGunz関数に注目します。
ステップ5 次に、ページから本の著者とそのタイトルを抽出する必要があります。 HTML :: TokeParserモジュールを使用してページを解析するため、URLを使用して必要なデータをストリーミングするのが最も簡単です。
my $fname = ''; my $authors = ''; while (my $token = $stream->get_token) { if ($token->[0] eq 'S' && $token->[1] eq 'a') { my $href = $token->[2]{'href'}; $authors .= $stream->get_trimmed_text('/a').',' if ($href =~ /\/author\//); if ($href =~ /show\=1/) { $fname = $stream->get_trimmed_text('/a'); $fname =~ s/\(\sPDF\)//gi; } if ($href =~ /download\/\?file_type\=pdf/) { chop($authors); $fname = trim($authors.','.$fname); $fname =~ tr/\//_/; $fname .= '.pdf'; .... } }
ステップ6 PDFを取得して保存します。 一度にいくつかの興味深い点があります。クローンを作成しないと、1冊の本だけがダウンロードされます。明らかにbooks.ruのバグです。 IO :: Fileモジュールを使用してロシア語の文字でファイルを保存することはできません。パールバージョンv5.14.2のモジュールのバグです。 さて、binmode呼び出しは、PDFファイルを壊さないようにします。
my $gbm = $mech->clone(); $resp = $gbm->get($href); $resp = $gbm->submit_form(with_fields => {'agreed' => 'Y', 'go' => 1}); my $pdfFile = $resp->content; $pdfFile = mkGunz($resp->content) unless ($resp->content =~ /^\%PDF/); print "Saving ".$fname." as ".length($pdfFile)." bytes.\n" ; open(my $fh, ">", $fname); if (defined $fh) { binmode($fh); print $fh $pdfFile; close($fh); }
そして最後に、すべてが完了しました。
#!/usr/bin/perl use WWW::Mechanize; use HTTP::Request::Common; use LWP; use LWP::UserAgent; use URI::Escape; use HTML::TokeParser; use DateTime; use Compress::Raw::Zlib; use Encode qw(decode encode); use warnings; sub trim($); my $mech = WWW::Mechanize->new(); $booklog = $ARGV[0]; $bookpsw = $ARGV[1]; #die "Usage: books.su.pl <login> <password> \n" if (scalar @ARGV < 2); $mail = $booklog; $password = $bookpsw; $mech->agent_alias("Linux Mozilla"); #$mech->proxy('https', 'http://127.0.0.1:8888/'); #$mech->proxy('http', 'http://127.0.0.1:8888/'); my $resp = $mech->get('http://www.books.ru/member/login.php'); $mech->cookie_jar->set_cookie(0, 'cookie_first_timestamp',DateTime->now->epoch, '/', 'www.books.ru'); $mech->cookie_jar->set_cookie(0, 'cookie_pages', '1', '/', 'www.books.ru'); #print mkGunz($resp->content)."\n"; $resp = $mech->post('http://www.books.ru/member/login.php',[ 'login' => $mail, 'password' => $password, 'go' => 'login', 'x' => rand_from_to(40, 50), 'y' => rand_from_to(1, 20), 'token' => '' ]); #print mkGunz($resp->content)."\n"; $resp = $mech->get('http://www.books.ru/member/orders/'); my @order_list = mkGunz($resp->content) =~ /\<a\shref=\"http:\/\/www\.books\.ru\/order.php\?order\=(\d+)\"\>/gi; foreach my $order_id (@order_list) { $resp = $mech->get('http://www.books.ru/order.php?order='.$order_id); my $hcont = mkGunz($resp->content); my $stream = HTML::TokeParser->new(\$hcont); $stream->empty_element_tags(1); my $fname = ''; my $authors = ''; while (my $token = $stream->get_token) { if ($authors eq '' && $fname ne "" && $token->[0] eq 'S' && $token->[1] eq 'br') { $authors .= cnv($stream->get_trimmed_text('/p')).','; } if ($token->[0] eq 'S' && $token->[1] eq 'a') { my $href = $token->[2]{'href'}; if ($href =~ /show\=1/) { $fname = cnv($stream->get_trimmed_text('/a')); $fname =~ s/\(\sPDF\)//gi; } if ($href =~ /download\/\?file_type\=pdf/) { chop($authors); $fname = trim($authors.','.$fname); $fname =~ tr/\//_/; $fname .= '.pdf'; my $gbm = $mech->clone(); $resp = $gbm->get($href); $resp = $gbm->submit_form(with_fields => {'agreed' => 'Y', 'go' => 1}); my $pdfFile = $resp->content; $pdfFile = mkGunz($resp->content) unless ($resp->content =~ /^\%PDF/); print "Saving ".$fname." as ".length($pdfFile)." bytes.\n" ; open(my $fh, ">", $fname); if (defined $fh) { binmode($fh); print $fh $pdfFile; close($fh); } else { die "Unable to open:".$fname."\n"; } $authors = ''; $fname = ''; } } } } sub cnv {return shift;}#encode('cp1251', decode('UTF-8', shift));} sub rand_from_to { my($from, $to) = @_; return int(rand($to - $from)) + $from; } sub mkGunz { my ($ind) = @_; return $ind if($ind =~ /html/); my $gun = new Compress::Raw::Zlib::Inflate(WindowBits => WANT_GZIP); { my $out; my $status = $gun->inflate($ind, $out); if ($status == Z_OK || $status == Z_STREAM_END) { return $out; } else { die $status.":".$ind; } }; } sub trim($) { my $string = shift; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; }
Windows愛好家への注意 :
ほとんどの場合、行を変更する必要があります$ fname =〜tr / \ // _ /; on $ fname =〜tr / \ / \:\ * \?\\ / _ /; NTFSには、ext4やcnv関数が提供されているエンコーディングを変更するよりも禁じられている文字があるためです。
読者への必須の願い : 販売を逃さず、多くの本を購入し、タブレットにダウンロードして、週末にインターネットのないコテージで静かに読んでほしい。
法的免責事項 :ライセンス契約では、ダウンロード後にファイルの名前を変更することは禁止されているため、このスクリプトが行う正しい便利な名前ですぐにダウンロードする必要があります!