(转)写了一个简单的下载程序(23/07/2006更新)

#这是一个简单的单线程下载程序,下载的是我网站里的一个小游戏,挖金子。PYTHON刚刚接触,书刚看到函数那里,看不下去了,太枯燥了,就试着自己做一个小玩意提提兴趣。
#其中肯定有很多问题,比如说比较笨的处理方法,请大家给我指出。


# _*_ coding:cp936 _*_
#Sample downloads Program use httplib
#Programer:rikioy
#email:rikiy at gmail.com
#date:2006-07-21
#introduction:
#这是一个简单的单线程下载程序,下载的是我网站里的一个小游戏,挖金子。PYTHON刚刚接触,书刚看到函数那里,看不下去了,太枯燥了,就试着自己做一个小玩意提提兴趣。
#其中肯定有很多问题,比如说比较笨的处理方法,请大家给我指出。
#用到的知识主要有:
#1、httplib库的使用,会用就简单多啦。
#2、设置引用页,有些网站下载需要,类似FLASHGET中的设置引用页。其实也是httplib中的知识。
#3、下载进度的计算,这个难道我一个下午,没经验的结果。虽然现在设计的也不好,不能用于多线程,不过以后在改吧。
#4、输出百分比,这个也小难了一会,不过后来找到方法了。用退格。呵呵。
#遗憾:
#1、rMsg是要下载文件的总大小,在计算进度的时候 percent = round(totle/fsize*100) 中 fsize 直接用 rMsg是不行的,弄了一下午才找到是这个问题,为什么,还不知道。
#2、文件变量用的比较乱,太晚了,不想整理了。
#3、没有任何异常处理,太脆弱了。
#改进:
#1、改成多进程的。
#2、下载任务考文本文件来配置
#3、整理程序中的变量与结构,使之更合理。
#4、加入异常处理
#感谢:
#BAIDU,我在百度搜索到了很多有用的东西。
#GOODNAME008,看了他写的一个简单的关于下载文件的文章,并且不厌其烦地回答我弱智的问题。BLOG,http://blog.csdn.net/goodname008
#
#


#引入HTTPLIB的库,URLLIB2也可以做个事情,但PY文档里面HTTPLIB介绍的比较多,所以就用这个了
import httplib
#单线程
import threading
#在最后计算下载百分比的时候用到了时间库
import time

class download(threading.Thread):
    def __init__ (self,threadname):
        threading.Thread.__init__(self,name=threadname)
    def run(self):
        #设置HTTP连接实例
        conn = httplib.HTTPConnection("www.wowor.org")
        #发送GET请求,在httplib中有putrequest和request两种,在MANUALS中有,不能混用。
        conn.putrequest('GET','/wjz.exe')
        #PUT头,Referer也是设置引用页的地方。
        conn.putheader('Referer','http://bbs.pingshu8.com')
        #PUT header结束,不结束后面进行不了。
        conn.endheaders()
        #得到服务器回应
        rMsg = conn.getresponse()
        #建立文件 fwrite
        fwrite = open('wjz.exe','wb+')
        #total后面计算进度用的,已下载量。
        totle = 0.00
        #全局变量 percent = 百分比
        global percent
        #取得服务器返回的文件大小,length 文档中好像没有,我在LIB代码中查到的。
        fsize = rMsg.length
        #输出最后加逗号,不换行。
        print "Thread download start...",
        #每次读取一千字节放到 ftmp 中
        ftmp = rMsg.read(1000)
        #开始循环读,并且 用percent = round(totle/fsize*100)计算百分比
        while len(ftmp):
            fwrite.write(ftmp)
            totle = totle + len(ftmp)
            percent = totle/fsize*100
            ftmp = rMsg.read(1000)
        print "Done!\b\b",
        #关闭文件与连接 
        fwrite.close()
        conn.close()
    
percent = 0
#建立并启动线程
downThread = download("downThread")
downThread.start()

#输出百分比
while percent < 100:
    if percent == 0:
        pass
    elif percent < 10:
        print "%i%%" % percent,
        print "\b\b\b\b",
    else:
        print "%i%%" % percent,
        print "\b\b\b\b\b", 
    time.sleep(0.05)


[ 本帖最后由 rikioy 于 2006-7-23 18:53 编辑 ]



 wolfg 回复于:2006-07-22 14:30:06

鼓励!

两个建议:
1. 定义一个main函数,比如:

def main():
  downThread = download("downThread")
  downThread.start()

  #输出百分比
  while percent < 100:
      if percent == 0:
          pass
      elif percent < 10:
          print "%i%%" % percent,
          print "\b\b\b\b",
      else:
          print "%i%%" % percent,
          print "\b\b\b\b\b",
      time.sleep(0.05)
if __name__=='__main__': 
  main()

这样,万一你的模块被import时,不会启动线程
2. 使用命令行参数,比如指定要下载的页面,文件保存位置什么的

Python cookbook 有一个进度条的例子,你看看
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/299207

[ 本帖最后由 wolfg 于 2006-7-22 14:34 编辑 ]


 rikioy 回复于:2006-07-23 18:42:33

改进了一些东西,算是第二版吧。希望前辈能提出改进意见。为了在这里显示的好,我在这里改了一下格式。我的PY编辑器用的是NEWEDIT


代码下载
[url=http://www.wowor.org/code/httpdown02.zip]http://www.wowor.org/code/httpdown02.zip



httpdown code

# _*_ coding:cp936 _*_
"""
Name:Sample downloads Program use httplib
Version:0.2
Programe:rikioy
Email:rikiy AT gmail DOT com
Date:2006-07-23
Introduction:这是一个简单的单线程下载程序,下载的是我网站里的一个小游戏,挖金子。PYTHON刚刚接触,书刚看到函数那里,看不下去了,太枯燥了,就试着自己做一个小玩意提提兴趣。 其中肯定有很多问题,比如说比较笨的处理方法,请大家给我指出。
new:过了庸庸碌碌的一天之后,又拿其这个程序继续的改,形成了这个版本。
UseKnowledge:
1、httplib库的使用,会用就简单多啦。
2、设置引用页,有些网站下载需要,类似FLASHGET中的设置引用页。其实也是httplib中的知识。
3、下载进度的计算,这个难道我一个下午,没经验的结果。虽然现在设计的也不好,不能用于多线程,不过以后在改吧。
4、输出百分比,这个也小难了一会,不过后来找到方法了。用退格。呵呵。
new:5、也没有什么新的,就是在程序里加入了 __name__ 判断。把显示进度单独分出去形成progressNumber类,在类里加入了__doc__。
new:6、把下载类封好了。可以多个进程下载不同的文件。
A pity:
1、rMsg是要下载文件的总大小,在计算进度的时候 percent = round(totle/fsize*100) 中 fsize 直接用 rMsg是不行的,弄了一下午才找到是这个问题,为什么,还不知道。
2、文件变量用的比较乱,太晚了,不想整理了。
3、没有任何异常处理,太脆弱了。
new:4、progressNumber 类还是没有解决好,已经像CU的前辈求救了。其实我也是多余写这个东西,我想在图形界面上就不存在这个问题了。不过还是想知道解决方法。
new:5、没有加入对文件进行分块下载,
Future:
1、单个文件多进程分块下载。
2、下载任务考文本文件来配置(目前可以进行程序控制)
3、支持断点续传。
4、加入异常处理
Thanks:
BAIDU,我在百度搜索到了很多有用的东西。
GOODNAME008,看了他写的一个简单的关于下载文件的文章,并且不厌其烦地回答我弱智的问题。BLOG,http://blog.csdn.net/goodname008
new:谢谢CU wolfg 的鼓励,有人看并且给自己回应感觉确实不一样啊,也是动力啊。

"""

#引入HTTPLIB的库,URLLIB2也可以做个事情,但PY文档里面HTTPLIB介绍的比较多,所以就用这个了
import httplib
#单线程
import threading
#在最后计算下载百分比的时候用到了时间库
import time
#自己写的 显示进度的类
import progressNumber
        

class httpdown(threading.Thread):
    def __init__ (self,threadname,fileurl,filepath,fileobject,filereferer = None):
        """threadname : Thread name.
           fileurl : Download file root url. Example: www.wowor.org
           filepath : Download file absolute path from root. Example: /wjz.exe
           fileobject : Store file name. Example: wjz.exe
           filereferer : Set Referer,Reference RFC2616. Example: http://www.wowor.org
        """
        threading.Thread.__init__(self,name=threadname)
        self.tName = threadname
        self.fUrl = fileurl
        self.fPath = filepath
        self.fObject = fileobject
        self.fReferer = filereferer

    def run(self):
        #设置HTTP连接实例
        conn = httplib.HTTPConnection(self.fUrl)
        #发送GET请求,在httplib中有putrequest和request两种,在MANUALS中有,不能混用。
        conn.putrequest('GET',self.fPath)
        #PUT头,Referer也是设置引用页的地方。
        if self.fReferer:
            conn.putheader('Referer',self.fReferer)
        #PUT header结束,不结束后面进行不了。
        conn.endheaders()
        #得到服务器回应
        rMsg = conn.getresponse()
        #建立文件 fwrite
        fwrite = open(self.fObject,'wb+')
        #total后面计算进度用的,已下载量。
        total = 0
        #取得服务器返回的文件大小,length 文档中好像没有,我在LIB代码中查到的。
        fsize = rMsg.length
        #输出最后加逗号,不换行。
        print "%s download start..." % self.tName,
        #每次读取一千字节放到 ftmp 中
        ftmp = rMsg.read(1000)
        #创建自定义类progressNumber实例,功能:显示下载百分比。具体使用请参看progressNumber类 
        pn = progressNumber.progressNumber(fsize)
        #开始循环读,并且 用percent = round(totle/fsize*100)计算百分比
        while len(ftmp):
            fwrite.write(ftmp)
            total = total + len(ftmp)
            pn.progress(total)
            ftmp = rMsg.read(1000)
        print "Done!\b\b"
        #关闭文件与连接 
        fwrite.close()
        conn.close()
    


if __name__ == '__main__':
#建立并启动线程
downThread = httpdown("WjzDown","www.wowor.org","/wjz.exe","w.exe")
downThread.start()




progressNumber code

# Class Name: Progress Number Class

# Author: rikioy 
#
# Email: rikioy at gmail DOT com
#
# Date: 07/23/2006
#
#

class progressNumber:
    "Print prgress number behind the string."
    def __init__( self,finalcount):
        self.finalcount = finalcount
    def progress(self,count):
        "Update the current progress."
        
        count = min(count,self.finalcount)
        if self.finalcount:
            percentcomplete = int(round(100*count/self.finalcount))
        
            if percentcomplete < 10:
                print "%d%%" % percentcomplete,
                print "\b\b\b\b",
            else:
                print "%d%%" % percentcomplete,
                print "\b\b\b\b\b",
        else:
            pass

if __name__ == '__main__':
    from time import sleep
    
    print "Name          : Class prgressNumber"
    print "Class __doc__ : %s\n" % progressNumber.__doc__
    
    print "Demo."
    #notiec: Add one comma behind the string
    #When you use comma in print,the pring don't output '\n' 
    print "Display the progress behind this string.",
    pn = progressNumber(70)
    count = 0
    while count < 70:
        count += 1
        pn.progress(count)
        sleep(0.1) 


[ 本帖最后由 rikioy 于 2006-7-23 18:56 编辑 ]


 西门吹风_CU 回复于:2006-09-07 11:00:24

不错,学习到了一些库的经验,希望能看到搂主多线程和支持exception的版本:)


 rikioy 回复于:2006-09-09 08:50:16

有多线程的版本了。但是控制台输出的问题没法解决。


 ghostwwl 回复于:2006-09-09 15:24:34

如果是多线程的话 因为你是写到磁盘的是同一个文件 所以我觉得 可以用lock 实现多线程 应该没多大问题
当然你也可以不用lock 可以每个线程建一个文件 然后合并 这样要避免重复下在相同的数据 这个文件划分这块 估计就还有点麻烦
用lock还是最简单的


 chopin1998 回复于:2006-09-13 11:22:47

楼主,你的单线程百分比输出正确吗?


 chopin1998 回复于:2006-09-13 12:16:20

sys.stdout.flush()

posted on 2009-10-15 21:47  feney  阅读(340)  评论(1编辑  收藏  举报