ฉันจะทำให้โปรแกรมรวบรวมข้อมูลเว็บ Perl ของฉันทำงานเร็วขึ้นได้อย่างไร

เมื่อสองวันที่ผ่านมาฉันได้ทำโปรเจ็กต์สัตว์เลี้ยงเล็กๆ น้อยๆ ซึ่งประกอบด้วยการสร้างโปรแกรมรวบรวมข้อมูลในภาษา Perl

ฉันไม่มีประสบการณ์จริงในภาษา Perl (เฉพาะสิ่งที่ฉันได้เรียนรู้ในช่วงสองวันที่ผ่านมา) สคริปต์ของฉันเป็นดังนี้:

ACTC.pm:

#!/usr/bin/perl
use strict;
use URI;
use URI::http;
use File::Basename;
use DBI;
use HTML::Parser;
use LWP::Simple;
require LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
$ua->env_proxy;
$ua->max_redirect(0);


package Crawler;
sub new {
    my $class = shift;
    my $self = {
        _url => shift,
        _max_link => 0,
        _local => 1,
    };
    bless $self, $class;
    return $self;

}
sub trim{
    my( $self, $string ) = @_;
    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    return $string;
}
sub process_image {
    my ($self, $process_image) = @_;
    $self->{_process_image} = $process_image;
}
sub local {
    my ($self, $local) = @_;
    $self->{_local} = $local;
}
sub max_link {
    my ($self, $max_link) = @_;
    $self->{_max_link} = $max_link;
}
sub x_more {
    my ($self, $x_more) = @_;
    $self->{_x_more} = $x_more;
}
sub resolve_href {
    my ( $self, $base, $href) = @_;
    my $u = URI->new_abs($href, $base);
    return $u->canonical;   
}
sub write {
    my ( $self, $ref, $data ) = @_;
    open FILE, '>c:/perlscripts/' . $ref . '_' . $self->{_process_image} . '.txt';
    foreach( $data ) {
        print FILE $self->trim($_) . "\n";
    }
    close( FILE );
}
sub scrape {
    my ( @m_error_array, @m_href_array, @href_array, $dbh, $query, $result, $array );
    my ( $self, $DBhost, $DBuser, $DBpass, $DBname ) = @_;
    if( defined( $self->{_process_image} ) && ( -e 'c:/perlscripts/href_w_' . $self->{_process_image} . ".txt" ) ) {
        open  ERROR_W, "<c:/perlscripts/error_w_" . $self->{_process_image} . ".txt";
        open  M_HREF_W, "<c:/perlscripts/m_href_w_" . $self->{_process_image} . ".txt";
        open  HREF_W, "<c:/perlscripts/href_w_" . $self->{_process_image} . ".txt";
        @m_error_array = <ERROR_W>;
        @m_href_array = <M_HREF_W>;
        @href_array = <HREF_W>;
        close ( ERROR_W );
        close ( M_HREF_W );
        close ( HREF_W );
    }else{
        @href_array = ( $self->{_url} );
    }
    my $z = 0;
    while( @href_array ){
        if( defined( $self->{_x_more} ) && $z == $self->{_x_more} ) {
            print "died";
            last;
        }
        my $href = shift( @href_array );
        if( defined( $self->{_process_image} ) && scalar @href_array ne 0 ) {
            $self->write( 'm_href_w', @m_href_array );
            $self->write( 'href_w', @href_array );
            $self->write( 'error_w', @m_error_array );
        }
        $self->{_link_count} = scalar @m_href_array;
        my $info = URI::http->new($href);
        if( ! defined( $info->host ) ) {
            push( @m_error_array, $href );
        }else{
            my $host = $info->host;
            $host =~ s/^www\.//;
            $self->{_current_page} = $href;
            my $redirect_limit = 10;
            my $y = 0;
            my( $response, $responseCode );
            while( 1 && $y le $redirect_limit ) {
                $response = $ua->get($href);
                $responseCode = $response->code;
                if( $responseCode == 200 || $responseCode == 301 || $responseCode == 302 ) {
                    if( $responseCode == 301 || $responseCode == 302 ) {
                        $href = $self->resolve_href( $href, $response->header('Location') );
                    }else{
                        last;
                    }
                }else{
                    last;
                }
                $y++;
            }
            if( $y != $redirect_limit && $responseCode == 200 ) {
                print $href . "\n";
                if( ! defined( $self->{_url_list} ) ) {
                    my @url_list = ( $href );
                }else{
                    my @url_list = $self->{_url_list};
                    push( @url_list, $href );
                    $self->{_url_list} = @url_list;
                }

                my $DNS = "dbi:mysql:$DBname:$DBhost:3306";
                $dbh = DBI->connect($DNS, $DBuser, $DBpass ) or die $DBI::errstr;

                $result = $dbh->prepare("INSERT INTO `". $host ."` (URL) VALUES ('$href')");
                if( ! $result->execute() ){
                    $result = $dbh->prepare("CREATE TABLE `". $host ."` ( `ID` INT( 255 ) NOT NULL AUTO_INCREMENT , `URL` VARCHAR( 255 ) NOT NULL , PRIMARY KEY ( `ID` )) ENGINE = MYISAM ;");
                    $result->execute();
                    print "Host added: " . $host . "\n";
                }


                my $content = $response->content;
                die "get failed: " . $href if (!defined $content);
                my @pageLinksArray = ( $content =~ m/href=["']([^"']*)["']/g );
                foreach( @pageLinksArray ) {
                    my $link = $self->trim($_);
                    if( $self->{_max_link} != 0 && scalar @m_href_array > $self->{_max_link} ) {
                        last;
                    }
                    my $new_href = $self->resolve_href( $href, $link );
                    if( $new_href =~ m/^http:\/\// ) {
                        if( substr( $new_href, -1 ) ne "#" ) {
                            my $base = $self->{_url};
                            my %values_index;
                            @values_index{@m_href_array} = ();
                            if( ! $new_href =~ m/$base/ ) {
                                if( $self->{_local} eq "true" && ! exists $values_index{$new_href} ) {
                                    push( @m_href_array, $new_href );
                                    push( @href_array, $new_href );
                                }
                            }elsif( $self->{_local} eq "true" && ! exists $values_index{$new_href} ) {
                                push( @m_href_array, $new_href );
                                push( @href_array, $new_href );
                            }
                        }
                    }
                }            
            }else{
                push( @m_error_array, $href );
            }
        }
    }
}
1;

new_spider.pl:

#!/usr/bin/perl
use strict;
use warnings;
use ACTC;

my ($object, $url, $uri);
print "Starting Poing: (url): ";
chomp($url = <>);

$object = new Crawler( $url );
$object->process_image('process_image_name');
$object->local('true');
$object->max_link(0);
$object->x_more(9999999);
$object->scrape( 'localhost', 'root', '', 'crawl' );

#print $object->{_url} . "\n";
#print $object->{_process_image};

ตอนนี้ยังไม่สมบูรณ์ฟังก์ชั่นบางอย่างทำงานไม่ถูกต้อง แต่หลังจากรันสคริปต์แล้วฉันได้จัดทำดัชนี 1,500 หน้าในเวลาประมาณหนึ่งชั่วโมงซึ่งฉันคิดว่าค่อนข้างช้า

สคริปต์เริ่มแสดงผลลัพธ์ แต่ตอนนี้ค่อนข้างช้าโดยส่ง URL หนึ่งรายการทุก ๆ วินาที

ใครสามารถให้คำแนะนำเกี่ยวกับวิธีการเพิ่มประสิทธิภาพได้หรือไม่?


person Phil Jackson    schedule 22.09.2010    source แหล่งที่มา
comment
ดูเหมือนคำถามเกี่ยวกับการเพิ่มประสิทธิภาพแบบเปิด อาจเป็น Community Wiki ใช่ไหม   -  person pascal    schedule 22.09.2010
comment
คุณช่วยเจาะจงกว่านี้ได้ไหม? CPU ของคุณอยู่ที่ 100% หรือไม่? หรือการเชื่อมต่อเครือข่ายของคุณ?   -  person pascal    schedule 22.09.2010
comment
เพิ่งตรวจสอบและใช่ว่าเป็น 100%   -  person Phil Jackson    schedule 22.09.2010
comment
เมื่อมีการรวบรวมข้อมูล href มันจะค้นหาลิงก์ (ขาเข้าหรือขาออก) ใด ๆ จากนั้นจึงเพิ่มลงในอาร์เรย์ที่จะประมวลผล จัดเก็บลิงก์ขาออกในฐานข้อมูลแทนอาร์เรย์จะมีประสิทธิภาพมากกว่าหรือไม่ จากนั้นเมื่อไซต์ในระบบถูกกำจัดให้ดึง URL อื่นออกจากฐานข้อมูลแล้วเริ่มใหม่อีกครั้ง หรือบางทีเมื่อพบ URL ขาออกอื่น ให้เปิดหน้าต่าง cmd อื่นแล้วดำเนินการทันที แค่คิดออกไป   -  person Phil Jackson    schedule 22.09.2010
comment
ดึงข้อมูลเพจพร้อมกัน ซึ่งควรเพิ่มปริมาณงานอย่างมาก และตรวจสอบปริมาณการใช้หน่วยความจำ คิว url สามารถขยายได้มาก   -  person n0rd    schedule 22.09.2010
comment
เป็นไปได้ที่ซ้ำกันของ เยี่ยมชม Half Million Pages ด้วย Perl   -  person brian d foy    schedule 22.09.2010


คำตอบ (2)


โดยส่วนใหญ่ โปรแกรมของคุณอาจกำลังรอการตอบกลับจากเครือข่าย เวลารอคอยส่วนใหญ่ไม่ช่วยอะไร (นอกเหนือจากการวางคอมพิวเตอร์ไว้ข้างคอมพิวเตอร์ที่คุณต้องการคุยด้วย) แยกกระบวนการเพื่อดึงข้อมูลแต่ละ URL เพื่อให้คุณสามารถดาวน์โหลดได้พร้อมกัน คุณอาจพิจารณาสิ่งต่างๆ เช่น Parallel::ForkManager, POE หรือ เหตุการณ์ใดๆ

person brian d foy    schedule 22.09.2010

ดูคำตอบของ Brian

เรียกใช้สำเนาจำนวนมากของมัน ใช้ระบบจัดเก็บข้อมูลที่ใช้ร่วมกันเพื่อเก็บข้อมูลขั้นกลางและข้อมูลสุดท้าย

อาจเป็นประโยชน์ถ้านำส่วนที่ต้องใช้หน่วยความจำมากขึ้นของโปรแกรมรวบรวมข้อมูล (การแยกวิเคราะห์ HTML ฯลฯ) และจัดส่วนเหล่านั้นไว้ในชุดกระบวนการที่แยกจากกัน

ดังนั้นให้มีกลุ่มตัวดึงข้อมูลซึ่งอ่านจากคิวของหน้าที่จะอ่าน และวางไว้ในพื้นที่จัดเก็บข้อมูลที่ใช้ร่วมกัน และกลุ่มของกระบวนการแยกวิเคราะห์ที่อ่านหน้าและเขียนผลลัพธ์ลงในฐานข้อมูลผลลัพธ์ และจัดคิวหน้าใหม่ลงในคิว อ่าน.

หรือบางสิ่งบางอย่าง. ขึ้นอยู่กับวัตถุประสงค์ของโปรแกรมรวบรวมข้อมูลของคุณจริงๆ

ท้ายที่สุดแล้ว หากคุณกำลังพยายามรวบรวมข้อมูลหน้าเว็บจำนวนมาก คุณอาจต้องใช้ฮาร์ดแวร์จำนวนมากและไปป์ที่ยุ่งยากมาก (ไปยังศูนย์ข้อมูล/โคโลของคุณ) ดังนั้น คุณจะต้องมีสถาปัตยกรรมที่ช่วยให้สามารถแยกส่วนของโปรแกรมรวบรวมข้อมูลออกเป็นหลายเครื่องเพื่อปรับขนาดได้อย่างเหมาะสม

person MarkR    schedule 24.09.2010