#!/usr/bin/env perl use strict; use warnings; use 5.012; binmode STDOUT, ':encoding(UTF-8)'; use Term::ReadLine; use Term::Size qw(chars); use Term::ANSIColor; use Text::Wrap; use List::Util qw(max min); use Number::Range; use WWW::Mechanize; use WWW::Mechanize::Plugin::Display; use HTML::TreeBuilder::XPath; # Author: Willy* # Spezialversion für perl-community.de my $print = 'w'; # w/v my $show_progress = 1; # 0/1 my $module_name = $ARGV[0]; my $term = Term::ReadLine->new( 'Text' ); $term->ornaments( ',,,' ); if ( not $module_name ) { $module_name = $term->readline( 'Suchen nach: ' ); exit unless $module_name; } die $! if $module_name !~ m|[\w\s:./-]+|; my $browser = WWW::Mechanize->new( show_progress => $show_progress ); $browser->get( 'http://search.cpan.org/' ); $browser->form_number( 1 ); $browser->field( 'query', $module_name ); $browser->click(); my $base = $browser->base; my $content = $browser->content; my @array; while ( 1 ) { my $tree= HTML::TreeBuilder::XPath->new; $tree->parse_content( $content ); my $root = $tree->elementify(); my @nodes = $tree->findnodes( '//h2[@class="sr"]/a[@href]/b[not(*)][text()]' ); for my $node ( @nodes ) { my $parent = $node->parent; my $url = $parent->attr_get_i( 'href' ); my $name = $node->as_trimmed_text; my( $text, $date, $rate, $rev, $autor ) = '' x 5; my $h2 = $parent->parent; my @text_array = $h2->findnodes( './following-sibling::small[1][not(*)][text()]' ); my $pos = 1; if ( @text_array == 1 ) { $text = $text_array[0]->as_trimmed_text; $pos = 2; } my @rev_array = $h2->findnodes( './following-sibling::small['.$pos.']/a[@href][not(*)][contains( text(), "Reviews")]' ); if ( @rev_array == 1 ) { $rev = $rev_array[0]->as_trimmed_text; } my @star_array = $h2->findnodes( './following-sibling::small['.$pos.']/img[@src]' ); if ( @star_array == 1 ) { $star_array[0] = $star_array[0]->attr_get_i( 'src' ); if ( $star_array[0] =~ /stars-(\d\.\d)\.gif$/ ) { $rate = $1; }; } my @date_array = $h2->findnodes( './following-sibling::small['.$pos.']/span[@class="date"][not(*)][text()]' ); if ( @date_array == 1 ) { $date = $date_array[0]->as_trimmed_text; } my @autor_array = $h2->findnodes( './following-sibling::small['.$pos.']/a[@href][position()=last()][not(*)][text()]' ); if ( @autor_array == 1 ) { $autor = $autor_array[0]->as_trimmed_text; } $rate .= ' stars' if $rate; push @array, [ $name, $url, $text, $date, $rate, $rev, $autor ]; } my $link = $browser->find_link( tag => 'a', text => 'Next >>' ); last if not $link; $browser->get( $link ); $content = $browser->content; } my ( $columns, $rows ) = chars; $Text::Wrap::columns = $columns ; my $pr = length scalar @array; my $tab = ' ' x ( $pr + 2 ); say "\n\n"; for my $link ( @array ) { state $count = 1; my $name = $link->[0]; my $text = $link->[2] ||= 'kein Text'; my $datum = $link->[3] ||= 'kein Datum'; my $rate = $link->[4] ||= ''; my $rev = $link->[5] ||= ''; my $autor = $link->[6] ||= 'kein Autor'; printf "%s %s %s %s %s %s\n", colored( sprintf( "%*.*s", $pr, $pr, $count ), 'yellow' ), colored( $name, 'bold' ), colored( $datum, 'blue' ), colored( $rate, 'blue' ), colored( $rev, 'blue' ), colored( $autor, 'blue' ) if $print eq 'v'; printf "%s %s\n", colored( sprintf( "%*.*s", $pr, $pr, $count ), 'yellow' ), colored( $link->[0], 'bold' ) if $print ne 'v'; say wrap ( $tab, $tab, colored( $link->[2], 'cyan' ) ); $count++; } if ( not @array ) { say 'nichts gefunden'; exit; } my $aw = $term->readline( "\nAuswahl Nummer(n): " ); # separator = , exit unless $aw; my $max = scalar @array; $aw =~ s/\s+//g; $aw =~ s/(?<=\d)-/../g; my $range = new Number::Range( $aw ); my @auswahl = sort { $a <=> $b } $range->range; die "Input greater than $max not allowed $!" if defined $max and max( @auswahl ) > $max; die "Input '0' or less not allowed $!" if min( @auswahl ) < 1; for my $aw ( @auswahl ) { my $url = $array[$aw-1]->[1]; $browser->get( $url ); $browser->display; } exit 0;