Perlのマルチスレッドプロキシ、または便利なbooks.ruの購入方法

ウェブサイトblogs.perl.orgからの写真






私たちはかつて、 icozユーザーとbooks.ruで買い物をし、同じ本を誤って2回購入しないようにする方法についてしました。 対話はあまりうまくいきませんでしたが、解決策は便利になり、購入した本とそうでない本を示しました。 さらに、スクリプトにパラメーターは必要ありません。 スクリプトは、サイト自体とやり取りするためのユーザー名とパスワードを受け取ります。 何かを購入した場合は、books.ru Webサイトを終了して戻って、スクリプトが購入した本をピックアップできるようにします。











何が必要ですか?



Windowsでインストールされた真珠とUbuntuオペレーティングシステム(ただし、Linuxが適しています)がインストールされているマシンは、使用されるフォークのために問題がありますが、CPANを介してモジュールを強制的にインストールすることで無効にできます。 とにかく彼はテストに合格しませんが、必要な部分は機能します。



ステップ1:必要なライブラリをインストールします。 それらが既にインストールされている場合、恐れる必要はありません-2回目はインストールされません。 ActivePerlのファンにはppm.batがあります

sudo apt-get install liburi-encode-perl libwww-perl libhtml-tokeparser-simple-perl libwww-mechanize-perl libdatetime-perl libhttp-proxy-perl
      
      







ステップ2:必要なフィルターの設定を忘れずにプロキシサーバーを作成します。

 my $proxy = HTTP::Proxy->new( engine => 'Threaded', port=>8888, max_keep_alive_requests => 0, host=>'127.0.0.1', timeout=>120); my $filter = HTTP::Proxy::BodyFilter::simple->new(\&alter_page); $proxy->push_filter(mime => 'text/html', response => HTTP::Proxy::BodyFilter::complete->new(), response => $filter); $proxy->push_filter(method => 'POST', path =>'/member/login.php', request => HTTP::Proxy::HeaderFilter::simple->new(sub { my $booklog = uri_decode($1) if $_[2]->decoded_content =~ /login\=(.*?)(?:\&|$)/; my $bookpsw = uri_decode($1) if $_[2]->decoded_content =~ /password\=(.*?)(?:\&|$)/; my @new_books = init_proxy($booklog, $bookpsw, @OWN_BOOKS); {lock (@OWN_BOOKS); @OWN_BOOKS = @new_books;} }));
      
      





そしてそれを実行します:

 $proxy->start;
      
      





2つのフィルターが使用されます。



重要なポイント:





ステップ3:変更のフィルターを作成します。

 sub alter_page { my ( $self, $dataref, $message, $protocol, $buffer ) = @_; return unless ${$dataref}; return unless $message->headers->content_type; foreach my $haveid (@OWN_BOOKS) { my $str = $haveid.'/?show=1"'; my $spat = quotemeta $str; my $repl = $str." style=\"text-decoration: line-through;\""; ${$dataref} =~ s/$spat/$repl/sg; } }
      
      





ここではすべてが簡単です。置換に必要なテンプレートを作成し、所有しているすべての本を調べ、取り消し線で購入済みとしてマークします。



ステップ4:すべての注文を調べて、すでに購入したすべての書籍を収集する初期化を記述します。

  foreach my $order_id (@order_list) { $resp = $mech->get('http://www.books.ru/order.php?order='.$order_id); parse_hrefs($resp->decoded_content, sub {push @OWN_BOOKS, $1 if ($_[0] =~ /(\d+)\/download\/\?file_type\=\w{3}/);}); } my %seen = (); my @ubooks = grep { ! $seen{$_}++ } @OWN_BOOKS;
      
      





最後に、繰り返しがある場合は、リストからすべて削除します。



ステップ5:すべてが機能するように見えますが、次のように記述する必要があるため機能しません。

 my @OWN_BOOKS :shared;
      
      





そうでない場合、グローバル変数@OWN_BOOKSはスレッドごとに異なります。

ステップ6:サイトごとのプロキシを使用できるFoxyProxyまたはその他の拡張機能をインストールし、サイトbooks.ruで便利な作業を楽しんでください。



いつものように、私は完全なスクリプトを同封します
 #!/usr/bin/perl use WWW::Mechanize; use HTTP::Request::Common; use LWP; use LWP::UserAgent; use HTML::TokeParser; use DateTime; use Encode qw(decode encode); use HTTP::Proxy; use HTTP::Proxy::BodyFilter::simple; use HTTP::Proxy::Engine::Threaded; use HTTP::Proxy::BodyFilter::complete; use HTTP::Proxy::HeaderFilter::simple; use URI::Encode qw(uri_encode uri_decode); use threads; use threads::shared; use warnings; # initialisation binmode STDOUT, ":utf8"; my @OWN_BOOKS; share(@OWN_BOOKS); @OWN_BOOKS = (); my $proxy = HTTP::Proxy->new( engine => 'Threaded', port=>8888, max_keep_alive_requests => 0, host=>'127.0.0.1', timeout=>120); $proxy->engine()->max_clients(100); my $filter = HTTP::Proxy::BodyFilter::simple->new(\&alter_page); $proxy->push_filter(mime => 'text/html', response => HTTP::Proxy::BodyFilter::complete->new(), response => $filter); # $proxy->push_filter(method => 'POST', path =>'/member/login.php', request => HTTP::Proxy::HeaderFilter::simple->new(sub { my $booklog = uri_decode($1) if $_[2]->decoded_content =~ /login\=(.*?)(?:\&|$)/; my $bookpsw = uri_decode($1) if $_[2]->decoded_content =~ /password\=(.*?)(?:\&|$)/; my @new_books = init_proxy($booklog, $bookpsw, @OWN_BOOKS); {lock (@OWN_BOOKS); @OWN_BOOKS = @new_books;} print "You already has ".scalar @OWN_BOOKS." books.\n"; })); # this is a MainLoop-like method $proxy->start; sub init_proxy { my $mail = shift; my $password = shift; my @OWN_BOOKS = @_; my $mech = WWW::Mechanize->new(); $mech->agent_alias("Linux Mozilla"); 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(20, 55), 'y' => rand_from_to(10, 19), 'token' => '' ]); $resp = $mech->get('http://www.books.ru/member/orders/'); my @order_list = $resp->decoded_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); parse_hrefs($resp->decoded_content, sub {push @OWN_BOOKS, $1 if ($_[0] =~ /(\d+)\/download\/\?file_type\=\w{3}/);}); } my %seen = (); my @ubooks = grep { ! $seen{$_}++ } @OWN_BOOKS; return @ubooks; } sub parse_hrefs { my ($data, $functor) = @_; my $stream = HTML::TokeParser->new(\$data); $stream->empty_element_tags(1); while (my $token = $stream->get_token) { if ($token->[0] eq 'S' && $token->[1] eq 'a') { my $href = $token->[2]{'href'}; $functor->($href); } } } sub alter_page { my ( $self, $dataref, $message, $protocol, $buffer ) = @_; return unless ${$dataref}; return unless $message->headers->content_type; #print scalar @OWN_BOOKS."!!!!!\n"; foreach my $haveid (@OWN_BOOKS) { my $str = $haveid.'/?show=1"'; my $spat = quotemeta $str; my $repl = $str." style=\"text-decoration: line-through;\""; ${$dataref} =~ s/$spat/$repl/sg; } } sub rand_from_to { my($from, $to) = @_; return int(rand($to - $from)) + $from; }
      
      









PS:これが社会の望みであれば、私は自分のサーバーに修正版を置くことができますが、私自身は都合の悪いことに制御していないプロキシを使用しません。



All Articles