Perl脚本查Google字典


这个Perl脚本其实并不能算我的原创,是师傅Perl帝拿出来分享的。本来拿的是iciba的翻译,我另外改了一个上Google字典拿翻译的版本。

要修改的原因:
1. Google字典的英中字典,有双语解释;
2. Google字典的例句和相关短语这些资源要丰富的多,可以帮助理解单词使用的语境,写英文材料时非常有用;
3. 我习惯用Google字典,我一个G粉。

先上截图
gdict

为什么要用一个脚本查单词?对于命令行控来说,离开当前工作终端,开个网页查单词是很痛苦的事情,他们甚至根本不想让手离开主键盘区!有这样的一个脚本,然后扔进/user/bin/,就不用大费周章的移动手臂了。

这个脚本用LWP::UserAgent抓取网页,HTML::TokeParser解析网页,获取单词的翻译。

脚本实现了一个抓取和解析google字典的类,整体的逻辑在en2chs函数中:
1. 生成网址
2. 用LWP取得结果网页
3. 解析网页

_parse_html找到翻译信息所在的代码块——一个id叫“pr-root”的标签,然后主要的体力活就全都扔给_get_close_mean啦。

要通过html标签来定位自己想要的内容,还真是个蛮累人的事情。但是Chrome的Deveploper Tools让事情简单了很多,实在是让人心神舒畅啊。

来看代码吧

下载: gdict.pl
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4.  
  5. my $robot = Translater->new;
  6. print $robot->en2chs( $ARGV[0] );
  7.  
  8. #
  9. # Class Translator
  10. #
  11. package Translater;
  12.  
  13. use strict;
  14. use warnings;
  15. use LWP::UserAgent;
  16. use HTML::TokeParser;
  17. use URI::Escape;
  18. use Carp qw(confess);
  19. use IO::Scalar;
  20.  
  21. sub new {
  22.     my $class = shift;
  23.     my $self = bless {}, $class;
  24.     $self->_init;
  25.     return $self;
  26. }
  27.  
  28. sub _init {
  29.     my $self = shift;
  30.     $self->{browser} = LWP::UserAgent->new;
  31.     $self->{browser}->timeout(60);
  32.     $self->{browser}->env_proxy;
  33.     $self->{_url} = "http://www.google.com.hk/dictionary?q=KEYW0RD&hl=zh-CN&langpair=en|zh-CN&spell=1&oi=spell";
  34. }
  35.  
  36. sub en2chs {
  37.     my ( $self, $word ) = @_;
  38.     my $buffer;
  39.  
  40.     $word = uri_escape($word);
  41.     $self->{_url} =~ s/KEYW0RD/$word/;
  42.     my $response = $self->{browser}->get( $self->{_url} );
  43.     confess "Cannot connect to Google Dictionary " . $self->{browser}->status_line
  44.         unless ( $response->is_success );
  45.     my $content = $response->content;
  46.  
  47.     $self->{_io} = IO::Scalar->new( \$buffer );
  48.     $self->_parse_html( \$content );
  49.     return $buffer;
  50. }
  51.  
  52. sub _parse_html {
  53.     my ( $self, $ctxt_ref ) = @_;
  54.  
  55.     my $stream = HTML::TokeParser->new($ctxt_ref);
  56.     while ( my $token = $stream->get_token ) {
  57.         if (    $token->[0] eq 'S'
  58.             and $token->[1] eq 'ul'
  59.             and exists $token->[2]{id}
  60.             and $token->[2]{id} eq 'pr-root' )
  61.         {
  62.             $self->_get_close_mean( $stream, $token );
  63.             $self->{_io}->print("\n\n");
  64.         }
  65.     }
  66. }
  67.  
  68. sub _get_close_mean {
  69.     my ( $self, $stream, $token ) = @_;
  70.     my $mean_counter = 1;
  71.     while ($token) {
  72.         if (    $token->[0] eq 'S'
  73.             and exists $token->[2]{class}
  74.             and $token->[2]{class} eq 'dct-tt' )
  75.         {    # find dictionary entry
  76.             $self->{_io}->print( $stream->get_trimmed_text('/span'), " " );
  77.         }
  78.         elsif ( $token->[0] eq 'S'
  79.             and $token->[1] eq 'div'
  80.             and exists $token->[2]{class}
  81.             and $token->[2]{class} eq 'dct-em' )
  82.         {
  83.             $self->{_io}->print("\n\n  $mean_counter");
  84.             $mean_counter++;
  85.         }
  86.         elsif ( $token->[0] eq 'S'
  87.             and exists $token->[2]{title}
  88.             and $token->[2]{title} eq 'Part-of-Speech' )
  89.         {    # find Part-of-Speech
  90.             $self->{_io}->print( "\n\n", $stream->get_trimmed_text('/span') );
  91.             $mean_counter = 1;
  92.         }
  93.         elsif ( $token->[0] eq 'S'
  94.             and $token->[1] eq 'div'
  95.             and exists $token->[2]{class}
  96.             and $token->[2]{class} eq 'dct-ee' )
  97.         {    # find example
  98.             $self->{_io}->print("\n      ~ ");
  99.         }
  100.         elsif ( $token->[0] eq 'S'
  101.             and $token->[1] eq 'span'
  102.             and exists $token->[2]{class}
  103.             and $token->[2]{class} eq "dct-tp" )
  104.         {    # find spell
  105.             my $spell = $stream->get_trimmed_text('/span');
  106.             if ( $spell =~ /([\/\[].+[\/\]])/ ) {
  107.                 $self->{_io}->print( " ", $1 );
  108.             }
  109.         }
  110.         elsif ( $token->[0] eq 'S'
  111.             and $token->[1] eq 'div'
  112.             and exists $token->[2]{class}
  113.             and $token->[2]{class} eq 'dct-er' )
  114.         {    # escape "See also" tag
  115.             while ("true") {
  116.                 $token = $stream->get_token;
  117.                 if (    $token->[0] eq 'E'
  118.                     and $token->[1] eq 'div' )
  119.                 {
  120.                     last;
  121.                 }
  122.             }
  123.         }
  124.         $token = $stream->get_token;
  125.         if (    $token->[0] eq 'S'
  126.             and $token->[1] eq 'h3' )
  127.         {
  128.             last;
  129.         }
  130.     }
  131.  
  132. }

, , ,

  1. #1 by 远走高飞 on March 22, 2011 - 6:59 pm

    google翻译倒常用,这个用得少


    ReplyReply
  2. #2 by bigCat on April 10, 2011 - 6:31 am

    = = 不能下载啊,看看神码错误。。。


    ReplyReply
  3. #3 by TheWaWaR on April 23, 2011 - 12:05 am

    我也不能下载
    500 Internal Server Error


    ReplyReply
  4. #4 by TheWaWaR on April 23, 2011 - 12:31 am

    各种Perl错误,放弃了…..


    ReplyReply
  5. #5 by twcai on May 25, 2011 - 6:35 pm

    @TheWaWaR
    你在什么环境下跑的这个Perl脚本


    ReplyReply
  6. #7 by zerob13 on July 14, 2011 - 2:04 am

    非常好用。。。


    ReplyReply
(will not be published)


想回复留言? 点击Reply按钮,或者直接@你想回复的人!够简单吧!