LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1002|回复: 3

baidu top500 MP3 下载脚本perl

[复制链接]
发表于 2006-11-3 23:19:46 | 显示全部楼层 |阅读模式
看到有人用python写了一个,作为perl的用户,我们也不能落后。
把下面的代码存成baidu.pl,在同样的目录下面建一个mp3子目录。
chmod +x baidu.pl
./baidu.pl
这个程序会crawl baidu top500 mp3,然后自动下载mp3格式大于4M的音乐。Enjoy:2cool
注: 需要安装以下perl module
sudo apt-get install liburi-perl
sudo apt-get install libwww-perl

TIPs: 很短时间写的,暂时界面比较混乱,如果要监视下载进程可以
cd mp3
watch -d ls -lth
  1. #!/usr/bin/perl -w
  2. use strict;
  3. use URI;
  4. use LWP::UserAgent;
  5. use HTTP::Response;
  6. use URI::Heuristic;
  7. use File::stat;
  8. use Symbol;
  9. use POSIX;
  10. my $PREFORK                = 5;        # number of children to maintain
  11. my %children               = ( );       # keys are current child process IDs
  12. my $children               = 0;        # current number of children
  13. sub REAPER {
  14.       $SIG{CHLD} = \&REAPER;
  15.       my $pid = wait;
  16.       $children --;
  17.       delete $children{$pid};
  18. }
  19. sub HUNTSMAN {
  20.       local($SIG{CHLD}) = 'IGNORE';
  21.       kill 'INT' => keys %children;
  22.       exit;
  23. }
  24. # explore the initial link
  25. my $url = URI->new('http://list.mp3.baidu.com/topso/mp3topsong.html');
  26. $url->query_form(
  27.         'id'    => '1#top2',
  28.         );
  29. my $ua = LWP::UserAgent->new();
  30. my $response = $ua->get($url);
  31. my @content;
  32. if ($response->is_error()) {
  33.         printf " %s\n", $response->status_line;
  34.         exit;
  35. } else {
  36.         @content = split("\n", $response->content());
  37. }
  38. my @raw_index = grep /http:\/\/mp3\.baidu\.com\/m\?tn=baidump3/i, @content;
  39. my @url_l1;
  40. my @song;
  41. for (my $i=0; $i<@raw_index; $i++) {
  42.         if ($raw_index[$i] =~ /<a href="(.+)(\+(.+))+" target=_blank>(.+)<\/a>/) {
  43.                 push @url_l1, $1.$2;
  44.                 push @song, $4;
  45.         }
  46. }
  47. my @url_rev = reverse @url_l1;
  48. my @song_rev = reverse @song;
  49. # Fork off our children.
  50. for (1 .. $PREFORK) {
  51.       make_new_child( pop(@url_rev), pop(@song_rev) );
  52. }
  53. # Install signal handlers.
  54. $SIG{CHLD} = \&REAPER;
  55. $SIG{INT}  = \&HUNTSMAN;
  56. # And maintain the population.
  57. while (1) {
  58.         sleep;
  59.         for (my $i=$children; $i<$PREFORK; $i++) {
  60.                 if (@url_l1 < 1) {
  61.                         # We are done
  62.                         exit;
  63.                 }
  64.                 make_new_child( pop(@url_rev), pop(@song_rev) );
  65.         }
  66. }
  67. sub make_new_child {
  68.         my ($url_proc, $song_name) = @_;
  69.         my $pid;
  70.         my $sigset;
  71.         # block signal for fork
  72.         $sigset = POSIX::SigSet->new(SIGINT);
  73.         sigprocmask(SIG_BLOCK, $sigset)
  74.                 or die "Can't block SIGINT for fork: $!\n";
  75.         die "fork: $!" unless defined ($pid = fork);
  76.         if ($pid) {
  77.                 # Parent records the child's birth and returns.
  78.                 sigprocmask(SIG_UNBLOCK, $sigset)
  79.                         or die "Can't unblock SIGINT for fork: $!\n";
  80.                 $children{$pid} = 1;
  81.                 $children++;
  82.                 return;
  83.         } else {
  84.                 # Child can *not* return from this subroutine.
  85.                 $SIG{INT} = 'DEFAULT';      # make SIGINT kill us as it did before
  86.                 # unblock signals
  87.                 sigprocmask(SIG_UNBLOCK, $sigset)
  88.                         or die "Can't unblock SIGINT for fork: $!\n";
  89.                 # explore the baby
  90.                 $response = $ua->get($url_proc);
  91.                 if ($response->is_error()) {
  92.                         printf " %s\n", $response->status_line;
  93.                         exit;
  94.                 } else {
  95.                         @content = split("\n", $response->content());
  96.                 }
  97.                 @raw_index = grep /<a target="_blank"/i, @content;
  98.                 my @size_index = grep /M<\/td>|<td>未知<\/td>/, @content;
  99.                 for (my $i=0; $i<@raw_index; $i++) {
  100.                         my @tmp = split (',', $raw_index[$i]);
  101.                         # filter file type other than .mp3
  102.                         next if ($tmp[2] !~ /(.+)\.mp3$/i);
  103.                         # filter file size less than 3 M
  104.                         next if ($size_index[$i] !~ /<td>(\d+)\.(\d+) M<\/td>/);
  105.                         if ($1 >= 5) {
  106.                                 $raw_index[$i] =~ /href="(.+)" onclick=/i;
  107.                                 $response = $ua->get($1);
  108.                                 if ($response->is_error()) {
  109.                                         #printf " %s\n", $response->status_line;
  110.                                         next;
  111.                                 } else {
  112.                                         @content = split("\n", $response->content());
  113.                                 }
  114.                                 my @link_index = grep /"http:\/\/(.+)\.mp3"/i, @content;
  115.                                 next if (@link_index < 1);
  116.                                 next if ($link_index[0] !~ /href="http:\/\/(.+)\/(.+)\.mp3">/i);
  117.                                 print "Downloading http:\/\/$1\/$2\.mp3 \t $song_name\n";
  118.                                 sleep(rand(30));
  119.                                 $song_name = time();
  120.                                 my @args = ("wget", "-T 300", "http://$1/$2.mp3", "-O./mp3/$song_name.mp3");
  121.                                 system(@args) == 0 or next;
  122.                                 if (stat("./mp3/$song_name.mp3")->size < 4000000) {
  123.                                         system("rm", "-f", "./mp3/$song_name.mp3");
  124.                                         next;
  125.                                 }
  126.                                 # TODO maybe we can choose the largest file
  127.                                 last;
  128.                         }
  129.                 }
  130.                 # tidy up gracefully and finish
  131.                 exit;
  132.         }
  133. }
  134. exit;
复制代码
 楼主| 发表于 2006-11-3 23:21:19 | 显示全部楼层
改这个就可以增加并发下载线程数

my $PREFORK                = 5;        # number of children to maintain

:)
回复 支持 反对

使用道具 举报

发表于 2006-11-3 23:37:03 | 显示全部楼层
短小精悍,厉害,呵呵
不过下载后的文件名好像有点难以辨认:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-11-3 23:58:47 | 显示全部楼层
hehe, 搞不定文件名的encoding, 在我的系统里面是乱码。其实真实的文件名都存在$song_name 里面了,没办法只好又暂时该成了epoch time。希望mp3的tag能解决问题。最近也要学习python,你的程序可以给我很好的参考:)
回复 支持 反对

使用道具 举报

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

本版积分规则

快速回复 返回顶部 返回列表