免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3629 | 回复: 2
打印 上一主题 下一主题

[threads]多线程批量下载数独题库 [复制链接]

论坛徽章:
12
子鼠
日期:2014-10-11 16:46:482016科比退役纪念章
日期:2018-03-16 10:24:0515-16赛季CBA联赛之山东
日期:2017-11-10 14:32:142016科比退役纪念章
日期:2017-09-02 15:42:4715-16赛季CBA联赛之佛山
日期:2017-08-28 17:11:5515-16赛季CBA联赛之浙江
日期:2017-08-24 16:55:1715-16赛季CBA联赛之青岛
日期:2017-08-17 19:55:2415-16赛季CBA联赛之天津
日期:2017-06-29 10:34:4315-16赛季CBA联赛之四川
日期:2017-05-16 16:38:55黑曼巴
日期:2016-07-19 15:03:112015亚冠之萨济拖拉机
日期:2015-05-22 11:38:5315-16赛季CBA联赛之北京
日期:2019-08-13 17:30:53
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2017-09-11 17:53 |只看该作者 |倒序浏览
本帖最后由 523066680 于 2017-09-11 18:03 编辑

数独网站:免费的在线数独

获取题库的地址规律是/printable.php?nd=难度&y=年&m=月&d=日
起点日期是2008-1-1,终点日期是当天,难度分为 0 1 2 3 4
如果$level 设为 0,运行后文件保存在 sudoku_nd0.txt,如果程序中断,再次运行时会加载上次的结果继续下载。

      =info
          523066680 2017-09
          https://zhuanlan.zhihu.com/PerlExample
      =cut

      use threads;
      use threads::shared;
      use IO::Handle;
      use File::Slurp;
      use Data::Dumper;
      use Time::HiRes qw/sleep time/;
      STDOUT->autoflush(1);

      $Data::Dumper::Indent = 1;
      $Data::Dumper::Sortkeys = 1;

      use Date::Format;
      use Time::Local;
      use LWP::UserAgent;

      our $level = 0;
      our $dbfile;
      our $main = "http://www.cn.sudokupuzzle.org";
      our $ua = LWP::UserAgent->new(
                  agent => "Mozilla/5.0", keep_alive => 1, timeout => 5,
               );

      our $db    :shared;
      our @tasks :shared;
      my @ths;

      while ( $level <= 4 )
      {
          $dbfile = "sudoku_nd${level}.txt";
          $db = undef;
          @tasks = ();

          #结构初始化,设置任务列表
          initdb( \$db, \@tasks, $dbfile );

          @ths = ();
          grep { push @ths, threads->create( \&getSudoku, $_ ); } (0..4);

          #等待并结束线程
          while ( threads->list( threads::running ) ) { sleep 1.0 }
          grep { $_->detach() } @ths;

          #最终数据输出
          write_file( $dbfile, Dumper $db );
          print "Done $dbfile\n";

          $level++;
      }

      sub getSudoku
      {
          our ($main, $ua, $level, $db, @tasks);
          my $id = shift;
          my $html;
          my $link;
          my $res;
          my $timestamp;
          my ($year, $mon, $day);

          while ( $#tasks >= 0 )
          {
              $timestamp = shift @tasks;
              ($year, $mon, $day) = split( " ", time2str( "%Y %L %e", $timestamp ) );
              $link = "$main/printable.php?nd=$level&y=$year&m=$mon&d=$day";
              GET: while (1)
              {
                  $res  = $ua->get($link);
                  $html = $res->content();

                  if ($html=~/(\d{162})/)
                  {
                      $db->{ $timestamp } = $1;
                      printf "[%d %d-%02d-%02d Done\n", $id, $year, $mon, $day;
                      last GET;
                  }
              }

              #遇到偶数月份零一日的时候保存数据,避免程序中断前功尽弃
              if ( ($day == 1) and ($mon % 2 == 0) )
              {
                  write_file( $dbfile, Dumper $db );
              }
          }
      }

      sub initdb
      {
          our ($main, $level);
          my ( $db, $tasks, $dbfile ) = @_;

          my $iter = timelocal(0, 0, 0, 1, 0, 2008 );  #起点日期,月份从0开始
          my $last = time();                           #最后日期为今天
          my %new_db;

          my $old_db;
          $old_db = eval read_file( $dbfile ) if ( -e $dbfile );

          while ( $iter < $last )
          {
              if ( defined $old_db->{$iter} )
              {
                  $new_db{$iter} = $old_db->{$iter};
              }
              else
              {
                  $new_db{$iter} = undef;
                  push @$tasks, $iter;
              }

              $iter += 24*3600;
          }

          $$db = shared_clone( \%new_db );
      }

求职 : 软件工程师
论坛徽章:
3
程序设计版块每日发帖之星
日期:2015-10-07 06:20:00程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2016-05-05 06:20:00
2 [报告]
发表于 2017-09-11 17:58 |只看该作者
从代码风格看,代码质量很高。

论坛徽章:
0
3 [报告]
发表于 2017-09-13 23:52 |只看该作者
这种也可以用Mojo::UserAgent做单线程异步。

我写了个简单的例子,虽然没有实现楼主的完全功能,就算抛砖引玉吧。
  1. #!/usr/bin/env perl

  2. use 5.010;
  3. use strict;
  4. use warnings;

  5. use Mojo::UserAgent;
  6. use DateTime;

  7. my $baseurl = "http://www.cn.sudokupuzzle.org";

  8. my $ua = Mojo::UserAgent->new;

  9. my $start_date = DateTime->new( year => 2017, month => 1, day => 1 );
  10. my $end_date = DateTime->today;

  11. my @queue;
  12. my $level = 0;
  13. while ( $start_date <= $end_date ) {
  14.     push @queue,
  15.       sprintf( "$baseurl/printable.php?nd=%d&y=%d&m=%d&d=%d",
  16.         $level, $start_date->year, $start_date->month, $start_date->day );
  17.     $start_date->add( days => 1 );
  18. }

  19. get_url();

  20. sub get_url {
  21.     state $workers = 4;

  22.     while ( $workers > 0 and my $url = shift @queue ) {
  23.         $workers--;

  24.         $ua->get(
  25.             $url => sub {
  26.                 my ( $ua, $tx ) = @_;
  27.                 $workers++;

  28.                 say "got $url";

  29.                 # work on $tx to get data...
  30.                 # e.g.
  31.                 say $tx->result->dom->at('title')->text;

  32.                 get_url();
  33.             }
  34.         );
  35.     }

  36.     Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
  37. }
复制代码

评分

参与人数 1信誉积分 +5 收起 理由
523066680 + 5 感谢分享

查看全部评分

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP