Board logo

标题: [原创代码] [Perl][LWP]获取中行外汇牌价的历史记录 [打印本页]

作者: 523066680    时间: 2015-8-24 23:07     标题: [Perl][LWP]获取中行外汇牌价的历史记录

本帖最后由 523066680 于 2018-10-30 18:43 编辑

2018-10 补充
项目地址:https://github.com/vicyang/Exchange-Rates
git clone git@github.com:vicyang/Exchange-Rates.git





环境配置
推荐 Strawberry Perl Portable PDL Edition

在 Strawberry Perl 的基础上需要添加的模块
Font::FreeType
HTML::TableExtract
Math::Geometry::Delaunay
作者: 523066680    时间: 2015-8-24 23:13

数据展示,我已做成动图

作者: 523066680    时间: 2015-8-29 09:44

补上动态图的对应代码
  1. =info
  2.     滚动显示外汇牌价某一项的变动
  3.     额外依赖的模块:OpenGL
  4.     依赖的文件:Year_USD.txt (中行外汇牌价的历史记录)
  5.    
  6.     编写:523066680
  7.     日期:2015-08
  8.     使用:按 w a s d 调整观察角度,按字母q退出
  9.     备注:左下角显示年/月,左侧显示汇率轴,每条线左侧显示日期
  10. =cut
  11. use Encode;
  12. use utf8;
  13. use v5.16;
  14. use IO::Handle;
  15. use OpenGL qw/ :all /;
  16. use OpenGL::Config;
  17. use Time::HiRes 'sleep';
  18. use feature 'state';
  19. STDOUT->autoflush(1);
  20. our $file = "Year_USD.txt";
  21. our $hash = {};
  22. our @dates;
  23. our $rx = 0.0;
  24. our $ry = 0.0;
  25. our $movex = 0;
  26. our @arr;
  27. loading();
  28. &Main();
  29. sub printstr
  30. {
  31.     for my $i ( split("", $_[0]) )
  32.     {
  33.         glutBitmapCharacter(GLUT_BITMAP_9_BY_15, ord($i));
  34.     }
  35. }
  36. sub display
  37. {
  38.     our $movex;
  39.     state $step = 120;
  40.     our $ry;
  41. our $rx;
  42.     our @array;
  43.     our @dates;
  44.     our @color_idx;
  45.     our %hash;
  46.    
  47.     my $scale = 1.2;
  48.     if ( ($movex + 15) > $#dates )
  49.     {
  50.         $movex = $#dates - 15;
  51.     }
  52.    
  53.     if ( $movex < 0 )
  54.     {
  55.         $movex = 0;
  56.     }
  57. my $i;
  58. my ($x, $y, $z);
  59.     glClear(GL_COLOR_BUFFER_BIT);
  60.     glPushMatrix();
  61.     glTranslatef(60.0, 60.0, 0.0);
  62.     glRotatef($rx, 1.0, 0.0, 0.0);
  63.     glRotatef($ry, 0.0, 1.0, 0.0);
  64.     glColor3f(1.0, 1.0, 1.0);
  65.     #汇率轴
  66.     for (my $i = 600.0; $i<=645.0; $i+=1.0)
  67.     {
  68.         glColor3f(  @{$color_idx[ int ( ($i-600)*100*0.02 ) ]}{'R','G','B'} );
  69.         glRasterPos3f( -20.0, ($i-600)*10*$scale, 0.0);
  70.         printstr( sprintf("%.1f", $i) );
  71.     }
  72.     glColor3f(1.0, 1.0, 1.0);
  73.     glRasterPos3f(0, 0 , 0.0);
  74.     $dates[$movex] =~ /^(\d+\.\d+)/;
  75.     printstr( $1 );
  76.     $z=0.0;
  77.     for my $day ((0+$movex) .. (15+$movex))
  78.     {
  79.         my $d = $dates[ $day ];
  80.         glBegin(GL_LINE_STRIP);
  81.         for my $i (sort keys %{$hash{ $d }} )
  82.         {
  83.             $i =~/(\d+):(\d+)/;
  84.             $x = int("$1$2")/10;
  85.             $y = ${$hash{ $d }{$i}}[0];
  86.             
  87.             glColor3f(  @{$color_idx[ int ( ($y-600)*100*0.02 ) ]}{'R','G','B'} );
  88.         glVertex3f( $x, ($y-600)*10*$scale , $z);
  89.         }
  90.         glEnd();
  91.         glRasterPos3f(-10.0, ($y-600)*10*$scale+10.0 , $z);
  92.         glColor3f(0.0, 0.0, $z/5000.0);
  93.         $d=~/(\d+)\.(\d+)\.(\d+)/;
  94.         printstr(  int($3) );
  95.         $z += 20.0;
  96.     }
  97. glPopMatrix();
  98.     glutSwapBuffers();
  99.    
  100.     #sleep 1.0;
  101.     #OVER();
  102. }
  103. sub OVER
  104. {
  105.     our $WinID;
  106.     glutDestroyWindow($WinID);
  107.     exit;
  108. }
  109. sub init {
  110.     glClearColor(0.0, 0.0, 0.0, 1.0);
  111.     glPointSize(1.0);
  112.     glLineWidth(1.0);
  113. }
  114. sub idle
  115. {
  116.     sleep 0.05;
  117.     $movex += 1;
  118.     glutPostRedisplay();
  119. }
  120. sub Reshape
  121. {
  122.     my $half = 200.0;
  123.     glViewport(0.0,0.0,800.0,800.0);
  124.     glMatrixMode(GL_PROJECTION);
  125.     glLoadIdentity();
  126.     glOrtho(-30.0, 800.0,-30.0, 800.0,0.0, 5000.0);
  127.     glMatrixMode(GL_MODELVIEW);
  128.     glLoadIdentity();
  129.     gluLookAt(0.0,0.0, 2500.0,0.0,0.0,0.0, 0.0, 1.0,2500.0);
  130. }
  131. sub hitkey
  132. {
  133. our $rx;
  134.     our $movex;
  135.     our $WinID;
  136.     my $keychar = lc(chr(shift));
  137.     given ($keychar)
  138.     {
  139.         when ('q')
  140.         {
  141.             glutDestroyWindow($WinID);
  142.         }
  143.         when ('w')
  144.         {
  145.          $rx+=2.0;
  146.             glutPostRedisplay();
  147.         }
  148.         when ('s')
  149.         {
  150.             $rx-=2.0;
  151.             glutPostRedisplay();
  152.         }
  153.         when ('a')
  154.         {
  155.             $ry+=2.0;
  156.             glutPostRedisplay();
  157.         }
  158.         when ('d')
  159.         {
  160.             $ry-=2.0;
  161.             glutPostRedisplay();
  162.         }
  163.         when ('o')
  164.         {
  165.             $movex-=1;
  166.             glutPostRedisplay();
  167.         }
  168.         when ('p')
  169.         {
  170.             $movex+=1;
  171.             glutPostRedisplay();
  172.         }
  173.         when ('r')
  174.         {
  175.             $movex=0;
  176.             glutPostRedisplay();
  177.         }
  178.     }
  179. }
  180. sub Main
  181. {
  182.     glutInit();
  183.     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE |GLUT_MULTISAMPLE );
  184.     glutInitWindowSize(800, 800);
  185.     glutInitWindowPosition(1,1);
  186.     our $WinID = glutCreateWindow("title");
  187.     &init();
  188.     glutDisplayFunc(\&display);
  189.     glutReshapeFunc(\&Reshape);
  190.     glutKeyboardFunc(\&hitkey);
  191.     glutIdleFunc(\&idle);
  192.     glutMainLoop();
  193. }
  194. sub loading
  195. {
  196.     our @dates;
  197.     our $file;
  198.     our %hash;
  199.     my @data;
  200.     open READ,"<:raw", $file or die "$!";
  201.     for my $line (<READ>)
  202.     {
  203.         next if ($line =~/^\r?\n$/);
  204.         @data = split(/\s/, $line);
  205.         $hash{ $data[7] }{ $data[8] } = [ @data[1..6]  ];
  206.     }
  207.     for my $d (sort keys %hash)
  208.     {
  209.         push @dates, $d;
  210.     }
  211.     close READ;
  212. }
  213. BEGIN
  214. {
  215.     my $size = 100 - 1;
  216.     our @color_idx;
  217.     #初始化RGB
  218.     for my $i (0 .. $size)
  219.     {
  220.         push @color_idx, {
  221.             'R' => 0.0,
  222.             'G' => 0.0,
  223.             'B' => 0.0,
  224.         };
  225.     }
  226.     #填充颜色(线性延伸)
  227.     fill_color(30, 30, 1.0, 0.0, 0.0);
  228.     fill_color(50, 40, 0.0, 1.0, 0.0);
  229.     fill_color(70, 40, 0.0, 0.0, 1.0);
  230.     fill_color(100, 30, 1.0, 0.2, 0.2);
  231.     sub fill_color
  232.     {
  233.         my %insert;
  234.         @{insert}{'offset', 'length', 'R', 'G', 'B'} = @_;
  235.         my $site;
  236.         my $ref;
  237.         my $tc;
  238.         for my $i (  -$insert{length} .. $insert{length} )
  239.         {
  240.             $site = $i + $insert{offset};
  241.             next if ($site < 0 or $site > $size);
  242.             $ref = $color_idx[$site];
  243.             for my $c ('R', 'G', 'B')
  244.             {
  245.                 $tc = $insert{$c} - abs( $insert{$c} / $insert{length} * $i),  #等量划分 * step
  246.                 $ref->{$c} = $ref->{$c} > $tc ? $ref->{$c} : $tc  ;
  247.             }
  248.         }
  249.     }
  250. }
  251. __END__
  252. 参考
  253. 货币名称        美元
  254. 现汇买入价      637.72
  255. 现钞买入价      632.61
  256. 现汇卖出价      640.28
  257. 现钞卖出价      640.28
  258. 中行折算价      639.75
  259. 发布日期        2015-08-16
  260. 发布时间        10:30:00
复制代码

作者: 523066680    时间: 2017-10-13 16:21

本帖最后由 523066680 于 2017-10-13 16:23 编辑

多线程版,提取速度比以前快很多。代码怎么写都觉得难看 。。。
  1. =info
  2.     获取中行外汇牌价-美元栏目的信息
  3.     Auth: 523066680
  4.     Date: 2017-10
  5.     https://github.com/vicyang/Exchange-Rates
  6. =cut
  7. use Encode;
  8. use threads;
  9. use threads::shared;
  10. use Time::HiRes qw/sleep/;
  11. use Time::Local;
  12. use File::Slurp;
  13. use Data::Dump qw/dump/;
  14. use Data::Dumper;
  15. use LWP::UserAgent;
  16. use HTML::TableExtract;
  17. use IO::Handle;
  18. STDOUT->autoflush(1);
  19. $Data::Dumper::Indent = 1;
  20. $Data::Dump::INDENT = " ";
  21. our $URL = "http://srh.bankofchina.com/search/whpj/search.jsp";
  22. our $ua = LWP::UserAgent->new(
  23.             timeout => 5, keep_alive => 1, agent => 'Mozilla/5.0',
  24.           );
  25. our %hash :shared;
  26. our @task :shared;
  27. $hash = shared_clone( {} );
  28. my $from = time_to_date(time() - 24*3600*1);
  29. my $to   = time_to_date(time());
  30. my $pageid = 1;
  31. my @ths;
  32. grep { push @ths, threads->create( \&func, $from, $to, $_ ) } ( 0 .. 5 );
  33. #循环插入任务,等待线程结束
  34. while ( threads->list( threads::running ) )
  35. {
  36.     grep
  37.     {
  38.         $task[$_] = $pageid++ if ( $task[$_] == 0 );
  39.     }
  40.     (0..5);
  41. }
  42. #分离线程
  43. grep { $_->detach() } @ths;
  44. write_file( "hash.perldb", { binmode => ":raw" }, Dumper \%hash );
  45. printf("Done\n");
  46. sub func
  47. {
  48.     my ($from, $to, $idx) = @_;
  49.     my $content;
  50.    
  51.     while (1)
  52.     {
  53.         if ( $task[$idx] == 0 ) { sleep 0.1; next; }
  54.         $content = get_page( $from, $to, $task[$idx] );
  55.         $content =~/var m_nCurrPage = (\d+)/;
  56.         last if ( $1 != $task[$idx] );
  57.         printf "[%d] mission: %d\n", $idx, $task[$idx];
  58.         get_info( $content );
  59.         #归零
  60.         $task[$idx] = 0;
  61.     }
  62. }
  63. sub get_info
  64. {
  65.     our %hash;
  66.     my $html_str = shift;
  67.     # count => 1 表示选择第二个表格。
  68.     my $obj = HTML::TableExtract->new( depth => 0, count => 1 );
  69.     $obj->parse($html_str);
  70.     my $table;
  71.     grep { $table = $_ } $obj->tables;
  72.     my $timestamp;
  73.     for my $row ( $table->rows )
  74.     {
  75. =info
  76.         去掉第一行抬头
  77.         去掉第一列货币类型
  78.         表格最后一行为空
  79. =cut
  80.         shift @$row;
  81.         next if ( $row->[1] eq '' );
  82.         next if ( not $row->[1] =~/\d/ );
  83.         $timestamp = pop @$row;
  84.         $hash{ $timestamp } = shared_clone([ @$row ]);
  85.     }
  86. }
  87. sub get_page
  88. {
  89.     our $ua;
  90.     my ($from, $to, $pageid) = @_;
  91.     my $res;
  92.     $res = $ua->post(
  93.         $URL,
  94.         [
  95.             erectDate => $from,
  96.             nothing   => $to,
  97.             pjname    => "1316",
  98.             page      => $pageid
  99.         ]
  100.     );
  101.     return $res->content();
  102. }
  103. sub time_to_date
  104. {
  105.     my ($sec, $min, $hour, $day, $mon, $year) = localtime( shift );
  106.     $mon += 1;
  107.     $year += 1900;
  108.     return sprintf "%d-%02d-%02d", $year,$mon,$day;
  109. }
复制代码

作者: 523066680    时间: 2017-10-22 21:45     标题: 高清重置版

本帖最后由 523066680 于 2017-10-22 21:50 编辑

高清重置版 。。。俗称“炒冷饭”。






作者: happy886rr    时间: 2017-10-23 21:50

回复 5# 523066680
还是统计图好看。 你设计天赋很强,总是能找到最佳的呈现方式,去打动坛友。
作者: 523066680    时间: 2017-10-24 18:09

本帖最后由 523066680 于 2017-10-24 20:41 编辑





只为花俏。要说直观,我工作中用了几天还是单纯的线条图更通透。




欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2