免费注册 查看新帖 |

Chinaunix

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

songtaste 多线程下载 以及遇到的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-08-26 23:13 |只看该作者 |倒序浏览
先贴一下代码  周末闲着无聊 做了一个多线程下载songtaste音乐的脚本

如下
  1. #!/usr/bin/python
  2. #coding:utf-8
  3. import re
  4. import urllib
  5. import urlparse
  6. import httplib
  7. import time
  8. import sys
  9. import os
  10. from threading import Thread

  11. songtype = {'7d99bb4c7bd4602c342e2bb826ee8777':'.wma','25e4f07f5123910814d9b8f3958385ba':'.Wma',
  12.         '51bbd020689d1ce1c845a484995c0cce':'.WMA','b3a7a4e64bcd8aabe4cabe0e55b57af5':'.mp3',
  13.         'd82029f73bcaf052be8930f6f4247184':'.MP3','5fd91d90d9618feca4740ac1f2e7948f':'.Mp3'}

  14. outputdir = '/home/pxiaohai/Music/'

  15. class MultiThreadDown(Thread,urllib.FancyURLopener):

  16.     def __init__(self,threadname,url,filename,ranges):
  17.         Thread.__init__(self,name=threadname)
  18.         urllib.FancyURLopener.__init__(self)
  19.         self.name = threadname
  20.         self.url = url
  21.         self.filename = filename
  22.         self.ranges = ranges
  23.         self.downloaded = 0

  24.     def run(self):

  25.         try:
  26.             self.downloaded = os.path.getsize(self.filename)
  27.             print self.filename
  28.         except OSError:
  29.             self.downloaded = 0

  30.         self.startpoint = self.ranges[0] + self.downloaded

  31.         if self.startpoint >= self.ranges[1]:
  32.             print 'part %s has been downloaded over.' % self.filename
  33.             return
  34.         self.oneTimeSize = 16384

  35.         print 'task %s will download from %d to %d' % (self.name,self.startpoint,self.ranges[1])
  36.         self.addheader("Range","bytes=%d-%d" % (self.ranges[0],self.ranges[1]))
  37.         self.urlhandle = self.open(self.url)
  38.         data = self.urlhandle.read(self.oneTimeSize)

  39.         while data:

  40.             filehandle = open(self.filename,'ab+')
  41.             filehandle.write(data)
  42.             filehandle.close()

  43.             self.downloaded +=len(data)
  44.             data = self.urlhandle.read(self.oneTimeSize)

  45. class DownSong():
  46.     def __init__(self,ms):
  47.         self.ms = ms

  48.     def down(self):
  49.         global outputdir
  50.         global songtype

  51.         for song in ms:
  52.             suburl = 'http://www.songtaste.com/song/%s/' % (song[0])
  53.             songname = song[1]
  54.             m = re.compile('playmedia1\((.+?)\)')
  55.             f = urllib.urlopen(suburl)
  56.             data = f.read()
  57.             s = []
  58.             s = m.findall(data)[-1].replace('\'','').replace('"','').replace(' ','').split(',')
  59.             print s
  60.             print s[1]
  61.             songname = songname + songtype.get(s[5])
  62.             songurl = s[6] + s[2] + songtype.get(s[5])

  63.             try:
  64.                 url1=urllib.urlopen(songurl)
  65.             except:
  66.                 show = u'\r %s can not be downloaded' % (songname)
  67.                 print show
  68.                 continue

  69.             blocks = 4
  70.             filesize = self.GetUrlFileSize(songurl)
  71.             ranges = self.SpliteBlocks(filesize,blocks)

  72.             print ranges

  73.             threadname = ["thread_%d" % i for i in range(0,blocks)]
  74.             filename =  ["tmpfiles_%d" % i for i in range(0,blocks)]

  75.             tasks = []
  76.             for i in range(0,blocks):
  77.                 task = MultiThreadDown(threadname[i],songurl,filename[i],ranges[i])
  78.                 task.setDaemon(True)
  79.                 task.start()
  80.                 tasks.append(task)
  81.             time.sleep(1)
  82.             songname = songname.decode('gb18030','replace').strip()
  83.             songname = ''.join(songname.split())
  84.             show = u'\r %s is starting download' % (songname)
  85.             print show

  86.             while self.islive(tasks):
  87.                 downloaded = sum([task.downloaded for task in tasks])
  88.                 process = downloaded/float(filesize)*100
  89.                 show = u'\rFilesize:%d Downloaded:%d Completed:%.2f%%' % (filesize,downloaded,process)
  90.                 sys.stdout.write(show)
  91.                 sys.stdout.flush()
  92.                 time.sleep(0.5)

  93.             show = u'\r %s  completed' % (songname)
  94.             print show
  95.             songname = outputdir + songname
  96.             filehandle = open(songname,'wb+')
  97.             for i in filename:
  98.                 f = open(i,'rb')
  99.                 filehandle.write(f.read())
  100.                 f.close()

  101.                 try:
  102.                     os.remove(i)
  103.                     print ""
  104.                 except:
  105.                     pass

  106.             filehandle.close()

  107.     def GetUrlFileSize(self,url):
  108.         urlHandler = urllib.urlopen(url)
  109.         headers = urlHandler.info().headers
  110.         length = 0
  111.         for header in headers:
  112.             if header.find('Length') != -1:
  113.                 length = header.split(':')[-1].strip()
  114.                 length = int(length)
  115.         return length

  116.     def SpliteBlocks(self,totalsize, blocknumber):
  117.         blocksize = totalsize/blocknumber
  118.         ranges = []
  119.         for i in range(0, blocknumber-1):
  120.             ranges.append((i*blocksize, i*blocksize +blocksize - 1))
  121.         ranges.append(( blocksize*(blocknumber-1), totalsize -1 ))

  122.         return ranges

  123.     def islive(self,tasks):
  124.         for task in tasks:
  125.             if task.isAlive():
  126.                 return True
  127.         return False

  128. if __name__ == '__main__':
  129. #    if len(sys.argv) < 1:
  130. #        print u'please input the url'
  131. #    else:
  132. #        if not re.match("^https?://[^ ]+",sys.argv[0]):
  133. #            print u'please input the url like "http://www.songtaste.com/music/catsong/cat2/"'

  134.     m = re.compile(r'(.+?)')
  135.     #
  136.     url = 'http://www.songtaste.com/music/catsong/cat2/'
  137.     f = urllib.urlopen(url)
  138.     data = f.read()

  139.     ms = []
  140.     ms = m.findall(data)
  141.     ds = DownSong(ms)
  142.     ds.down()
复制代码
用到了多线程下载   但是遇了问题

比如 我开4个线程   一个音乐文件大小为 4M  这样一个线程只下载1M 就可以了  

但事实不是这样的   下载下来的文件 是  tmpfile_1 为 1M   
tmpfile_2 为 2M
tmpfile_3 为 3M
tmpfile_4 为 4M

最终合成的一个音乐文件 变成了 10M

一开始以为自己的代码有问题 经过一一排查之后发现代码没有问题   

我又写了一个测试文件用的
  1. #!/usr/bin/python

  2. import urllib
  3. import time

  4. handler = urllib.FancyURLopener()
  5. handler.addheader("Range",'bytes=3000000-11356207')
  6. urlhandle = handler.open('http://224.cachefile20.rayfile.com/1871/zh-cn/download/f92b79ffbd15686f65aa203d305823af/preview.MP3')

  7. data = urlhandle.read(16384)
  8. while data:
  9.         filehandle = open("a.mp3",'ab+')
  10.         filehandle.write(data)
  11.         filehandle.close()
  12.         data = urlhandle.read(16384)
复制代码
文件总大小为 11356207    'bytes=3000000-11356207'  这里的 Range  是设置 为  3000000-11356207  

和 5000000-11356207  的时候 下载下来的文件大小都是  11356207

这说明  bytes=startpoint-endpoint      startpoint 没有起作用  而 endpoint  起作用了  

我也从其他的地方下载文件 都没问题    但是 下载songtase 上的音乐文件就会这样   

实在不知什么原因  不知道是不是  rayfile 搞了什么鬼
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP