LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
楼主: aiyi

写了一个从百度下载Mp3的python脚本

[复制链接]
 楼主| 发表于 2006-11-8 23:36:40 | 显示全部楼层
Post by pupilzeng
嗯,等待你内建多线程下载的版本。
另外有个建议,能不能对下载镜像根据速度进行排序?然后选取最快的进行下载?现在选取的有时太慢了。


多线程下载的改造基本上完成了,正在进行多线程URL测试的改造,没有意外的话大概明天中午能够发出来吧。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-11-9 12:46:35 | 显示全部楼层

脚本做了重大改进,敬请关注本帖第一楼

主要有三处改变:
1。脚本改名为getsong,简单些,呵呵。
2。内置多线程下载,不再依赖axel。
3。选择速度较快的站点进行下载,减少您的等待时间。

有需要这个脚本的朋友请查看本帖第一楼从附件中下载最新版本。
回复 支持 反对

使用道具 举报

发表于 2006-11-10 20:44:36 | 显示全部楼层
Post by aiyi
主要有三处改变:
1。脚本改名为getsong,简单些,呵呵。
2。内置多线程下载,不再依赖axel。
3。选择速度较快的站点进行下载,减少您的等待时间。

有需要这个脚本的朋友请查看本帖第一楼从附件中下载最新版本。
再传一下我的patch,改动有三处
1. 出现错误时,重新连接时,应该重新构造请求包,否则将使下载的文件出错;
2. 使用"\r"代替"\b"
3. 使用sys.stdin.encoding代替sys.getfilesystemencoding(),一般来说,这两个应该是一样的。但是从名字来说,应该使用stdin.encoding更准确,虽然我也不知道它能不能带来实际的好处。
  1. --- getsong        2006-11-09 13:09:59.000000000 +0800
  2. +++ getsong.py        2006-11-10 20:07:21.000000000 +0800
  3. @@ -68,16 +68,16 @@
  4.          except OSError:
  5.              self.downloaded = 0
  6.          self.percent = self.downloaded/float(self.totalLength)*100
  7. -        self.headerrange = (self.range[0]+self.downloaded, self.range[1])
  8.          self.bufferSize = 8192
  9. -        request = urllib2.Request(self.url)
  10. -        request.add_header('Range', 'bytes=%d-%d' %self.headerrange)
  11.          downloadAll = False
  12.          retries = 1
  13.          while not downloadAll:
  14.              if retries > 10:
  15.                  break
  16.              try:
  17. +                self.headerrange = (self.range[0]+self.downloaded, self.range[1])
  18. +                request = urllib2.Request(self.url)
  19. +                request.add_header('Range', 'bytes=%d-%d' %self.headerrange)
  20.                  conn = urllib2.urlopen(request)
  21.                  startTime = time.time()
  22.                  data = conn.read(self.bufferSize)
  23. @@ -163,10 +163,9 @@
  24.                  rate = downloadedThistime / float(etime)/1024
  25.              except:
  26.                  rate = 100.0
  27. -            progressStr = u'Filesize: %d(%.2fM)  Downloaded: %.2f%%  Avg rate: %.1fKB/s' %(length, mb, d, rate)
  28. +            progressStr = u'\rFilesize: %d(%.2fM)  Downloaded: %.2f%%  Avg rate: %.1fKB/s' %(length, mb, d, rate)
  29.              sys.stdout.write(progressStr)
  30.              sys.stdout.flush()
  31. -            sys.stdout.write('\b'*(len(progressStr)+1))
  32.              live = hasLive(ts)
  33.              time.sleep(0.2)
  34.          except KeyboardInterrupt:
  35. @@ -497,6 +496,6 @@
  36.          if o in ('-v', '--version'):
  37.              print 'v1.0 by Xupeng Yun <recordus@gmail.com>'
  38.      for title in titles:
  39. -        title = title.decode(sys.getfilesystemencoding(), 'ignore')
  40. -        artist = artist.decode(sys.getfilesystemencoding(), 'ignore')
  41. +        title = title.decode(sys.stdin.encoding, 'ignore')
  42. +        artist = artist.decode(sys.stdin.encoding, 'ignore')
  43.          DownloadSong(artist, title)
复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-11-10 21:12:48 | 显示全部楼层
Post by pupilzeng
再传一下我的patch,改动有三处
1. 出现错误时,重新连接时,应该重新构造请求包,否则将使下载的文件出错;
2. 使用"\r"代替"\b"
3. 使用sys.stdin.encoding代替sys.getfilesystemencoding(),一般来说,这两个应该是一样的。但是从名字来说,应该使用stdin.encoding更准确,虽然我也不知道它能不能带来实际的好处。


呵呵,真是太谢谢你了,高手出招果然不同凡响啊:)
今天我又学到了好用的“\r”,输出下载进度再也不用那么麻烦了。

我已经上传了新的文件,感谢pupilzeng。
回复 支持 反对

使用道具 举报

发表于 2006-11-11 00:49:29 | 显示全部楼层
不错啊,                 .
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-11-11 08:36:55 | 显示全部楼层
呵呵,承蒙夸奖,现在只能说是基本上可用,在搜索匹配精度上还有些问题,考虑从百度的搜索结果中进一步过滤。
回复 支持 反对

使用道具 举报

发表于 2006-11-11 11:46:52 | 显示全部楼层
呵呵,我哪是什么高手啊。小打小闹而已。而且还比较懒,本来前面是想自己写一下http多线程下载的,可是在完成之前,发现你的已经写好了,就懒得再写了。呵呵。
回复 支持 反对

使用道具 举报

发表于 2006-11-11 11:55:28 | 显示全部楼层
有个想法,就是有关多线程下载:
你现在的做法是把每一部分分别保持为单个的文件,最后合并。
可不可以这样:
使用一个数据文件,一个log文件。
每个线程都是向这一个数据文件操作,当然进行操作的时候,需要对文件进行锁定,并将相应的信息记录到log文件中,以便下次操作的进行。
这样的话,有一个好处,就是如果下载失败的话,下次可以“续传”。
续传的实现可以是这样:
1. 首先判断文件是否相同,由于不同的镜像上的文件可能是不同的,所以,只有是同一个镜像上的相同文件,才假定它是一样的(当然还可以进行一些额外的检测,比方说长度是否一样)。
2. 从log文件中,读取出本地文件的信息(即完成信息),然后进行下载。
回复 支持 反对

使用道具 举报

发表于 2006-11-11 17:44:03 | 显示全部楼层
需要帮忙,我从你那个多线程的脚本里”透“了点代码,但是没有完全理解,尤其是ranges的算法,帮我看看,多谢了。
一个多资源多线程的portage下载脚本,你肯定有用,我这里sync太慢了。

等等,我发现很多问题,地址我先删掉了,我先改改
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-11-12 12:15:30 | 显示全部楼层
Post by pupilzeng
有个想法,就是有关多线程下载:
你现在的做法是把每一部分分别保持为单个的文件,最后合并。
可不可以这样:
使用一个数据文件,一个log文件。
每个线程都是向这一个数据文件操作,当然进行操作的时候,需要对文件进行锁定,并将相应的信息记录到log文件中,以便下次操作的进行。
这样的话,有一个好处,就是如果下载失败的话,下次可以“续传”。
续传的实现可以是这样:
1. 首先判断文件是否相同,由于不同的镜像上的文件可能是不同的,所以,只有是同一个镜像上的相同文件,才假定它是一样的(当然还可以进行一些额外的检测,比方说长度是否一样)。
2. 从log文件中,读取出本地文件的信息(即完成信息),然后进行下载。


谦虚了,偶已经从你那里学到东西了,呵呵。
其实最初我也是用了logfile,就是为了能够断点续传,不过也是用的多个文件块最后合并,当时主要是图个实现方便,后来发现在这个mp3下载里用处不大就又去掉了。单独说多线程下载那一块儿现在的也可以续传,当然是在文件相同的情况下才有意义。

当然加上这个检测、续传可能会好一点,采用单个文件也会好一点,偶做做试试:)
回复 支持 反对

使用道具 举报

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

本版积分规则

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