#!/usr/bin/perl use strict; use warnings; use Getopt::Long; use Term::ANSIColor qw(BOLD ON_YELLOW RED GREEN MAGENTA CYAN YELLOW RESET); use URI::Escape 'uri_escape'; use HTML::Entities 'decode_entities'; use LWP::UserAgent; use XML::LibXML; use constant { URL_BASE => 'http://www.google.com/codesearch/feeds/search', TIMEOUT => 3, DEFAULT_START_INDEX => 1, DEFAULT_MAX_RESULT => 5, DEFAULT_MAX_MATCH => 3, }; sub color { our $color; return $color ? $_[0] : ""; } sub cleanup_content { my ($str, $keyword) = @_; $str =~ s/^]+)?>|<\/pre\s*>//g; decode_entities($str); my $hilighted = color(BOLD) . color(ON_YELLOW) . color(RED) . $keyword . color(color(RESET)) ; $str =~ s/$keyword<\/b>/$hilighted/ig; return $str; } my (%opt); Getopt::Long::GetOptions( 'lang=s' => \$opt{'lang'}, "start=i" => \$opt{'start-index'}, "num=i" => \$opt{'max-results'}, "match=i" => \$opt{'max-match'}, "nocolor" => \$opt{'nocolor'}, ); $opt{'start-index'} ||= DEFAULT_START_INDEX; $opt{'max-results'} ||= DEFAULT_MAX_RESULT; $opt{'max-match'} ||= DEFAULT_MAX_MATCH; our $color = defined $opt{'nocolor'} ? 0 : 1; my $keyword = $ARGV[0]; if (!$keyword) { die "specify keyword!"; } my ($query); { # create query string my $lang = (defined $opt{'lang'} && $opt{'lang'} ? ' lang:' . $opt{'lang'} : ''); my $option = join '&', map { sprintf("%s=%s", $_, $opt{$_}) } qw/start-index max-results/; $query = sprintf("%s?q=%s&%s", URL_BASE , uri_escape($keyword . $lang), $option); } { # get and parse search results from Google. my $ua = new LWP::UserAgent(); $ua->timeout(TIMEOUT); my $res = $ua->get($query); if (!$res->is_success()) { die "search failed. request URI=[$query]"; } # parse response XML my ($xmldoc); eval { $xmldoc = XML::LibXML->new()->parse_string($res->content()); }; if ($@ || !defined $xmldoc) { die "parse failed. request uri=[$query] [$@]"; } my @entry_nodes = $xmldoc->findnodes('//*[local-name()="entry"]'); my $match_count = (scalar @entry_nodes); if (0 == $match_count) { print "result is empty.\n"; exit; } # print lines foreach my $entry_node (@entry_nodes) { my $title = $entry_node->findvalue( '*[local-name()="title"]/text()'); my $updated = $entry_node->findvalue( '*[local-name()="updated"]/text()'); my $alt_href = $entry_node->findvalue( '*[local-name()="link"]/@href'); print color(GREEN) . color(BOLD) . "$title" . color(RESET) . color(GREEN) . ' - ' . $updated . color(RESET) . "\n" . color(CYAN) . "$alt_href" . color(RESET) . "\n" ; my @match = $entry_node->findnodes('*[local-name()="match"]'); my $print_count = 0; MATCH_LOOP: foreach my $match (@match) { last MATCH_LOOP if ++$print_count > $opt{'max-match'}; my $content = $match->textContent() || ""; my $line = $match->find('@lineNumber'); print color(MAGENTA) . "line $line" . color(RESET) . "\n" . cleanup_content($content, $keyword) . "\n\n" ; } } } __END__ =head1 NAME google_code_search.pl - search google_code_search with keywords =head1 SYNOPSIS google_code_search.pl ap_table_do google_code_search.pl --lang=perl --num=3 --start=10 uri_escape =head1 DESCRIPTION this is the command line script to search Google Code Search. =head1 OPTIONS =over 4 =item --lang= language name (perl, python, lisp...) =item --start= start point of search results =item --num= =item --match= =item -nocolor not use ANSI colors =back =head1 AUTHOR bonar =cut