pycurl 分块下载

写爬虫时要下载文件,谁知道文件比较大,然后在下载时候总是丢包,因此参考网上的一些源码写了实现分块下载的功能,有能力的童鞋可以自己改写成多线程的。
这个pycurl的分块下载功能我把它封装成了一个类,直接使用即可,接收5个参数,用法如下

    d = downloader(downloadurl,out_filePath,None,None,None)
    d.download() #调用下载功能下载


完整代码如下:

import pycurl
# 设置curl对象 的proxy reffer cookies
def SetOpt(target_address,proxy=None,reffer=None,cookies=None):
        c = pycurl.Curl()
        c.setopt(pycurl.URL,target_address)

        if proxy != None:
            c.setopt(pycurl.PROXY,proxy)    # 设置代理
        if reffer != None:
            c.setopt(pycurl.REFERER,reffer)
        if cookies !=None:
            c.setopt(pycurl.COOKIE,cookies)
        return c

class downloader:
    def __init__(self,target_address,out_filePath,reffer,cookies,proxy):
        print out_filePath
        self.output_file=out_filePath       # 输出路径
        self.chunk=1*1024*1024              # 设置每次下载的块大小
        #创建存放文件的目录
        try:
            self.dir_name=self.output_file+"tmp"
            print self.dir_name
            os.mkdir(self.dir_name)
        except OSError:
            pass
        ######### 设置CURL对象 ######
        self.curl_obj= SetOpt(target_address,reffer=reffer,cookies=cookies)
        ## 临时的curl对象,用来获取文件的大小
        tmp_curl_obj = SetOpt(target_address,reffer=reffer,cookies=cookies)

         ##### 得到并设置下载文件的大小 ######
        tmp_curl_obj.setopt(tmp_curl_obj.NOBODY,True)  #获取的文件内容不包含body部分
        try:
            print "Trying to get size of the file"
            tmp_curl_obj.perform()
            self.size = tmp_curl_obj.getinfo(tmp_curl_obj.CONTENT_LENGTH_DOWNLOAD) #文件大小
            print  self.size
        except Exception, e:
            print e
            self.delete_temp()
            self.size = 0
        #打印进度
#        self.curl_obj.setopt(self.curl_obj.NOPROGRESS,1)
        self.curl_obj.setopt(self.curl_obj.PROGRESSFUNCTION,self.progress)

    ##### 下载 ######
    def download(self):
        if (self.size>0):
            print "Starting download. Total size: "+str(self.size)+" bytes or "+str(self.size/1024/1024)+" MB"    
        else:
            print "Starting download"

        #####  如果文件大小小于或等于块大小  就直接下载 不用分块了 #####
        if self.size <=self.chunk or self.size<0:
            self.curl_obj.fp = open(self.output_file, "wb")
            self.curl_obj.setopt(pycurl.WRITEDATA, self.curl_obj.fp)
            self.curl_obj.perform()
            self.curl_obj.fp.close()
            return

        #####  设置超时时间   #####
        self.curl_obj.setopt(pycurl.TIMEOUT,60*10)
        log=open("downloader.log","a")

        # lim_l  块头 lim_u 块尾  如lim_l=0,lim_u=1023, 则这个块就是 0-1023
        lim_l=0
        lim_u=self.chunk  # 0 - 1M
        i=1  #分块编号
        ###### 下载文件  #####
        while lim_l < self.size :  
            temp_output=os.path.join(self.dir_name,"output"+str(i))
            ###### 如果该分块已经存在且大小等于块大小1024*1024 说明该分块已经下载完成,继续下一次循环  #####
            if os.path.exists(temp_output) and os.path.getsize(temp_output)==self.chunk:
                #print "skip chunk ", i, lim_l
                i=i+1
                r=str(lim_l)+"-"+str(lim_u-1)  # 下载的文件分块范围 如 0-(1M-1)、 (1M-(2M-1))....
                lim_l=lim_l+self.chunk
                lim_u=lim_u+self.chunk
                continue

            #####  分块没有被下载则开始下载  #####
            self.curl_obj.fp = open(temp_output, "wb")
            self.curl_obj.setopt(pycurl.WRITEDATA, self.curl_obj.fp)
            r=str(lim_l)+"-"+str(lim_u-1)
            self.curl_obj.setopt(pycurl.RANGE,r)

            print "download chunk", i
            ##### 下载文件   #####
            while True:
                ##### 下载完成跳出这个循环  #####
                try:
                    self.curl_obj.perform()
                    self.curl_obj.fp.close()
                    break
                ###### 异常则继续下载  #####
                except pycurl.error, e:
                    logmsg = "Pycurl error caught "+str(e)+" while downloading at download range "+str(r)+" while storing to file "+str(temp_output)+"\n"
                    log.write(logmsg)
                    print "download {} exception".format(i)
                    self.curl_obj.fp.close()
                    self.curl_obj.fp=open(temp_output,"wb")
                    continue
            i=i+1
            lim_l=lim_l+self.chunk
            lim_u=lim_u+self.chunk


    ##### 删除下载的临时文件  #####
    def delete_temp(self):
        i=1
        while True:
            temp_output=os.path.join(self.dir_name,"output"+str(i))
            if os.path.exists(temp_output):
                os.remove(temp_output)
            else:
                break
            i=i+1
        try:
            os.rmdir(self.dir_name)
        except Exception, e:
            pass
    #####  合并文件  #####
    def concatenate(self):
        ##### 合并前清空output_file的内容   #####
        fp=open(self.output_file,'wb')
        i=1

        while True:
            temp_output=os.path.join(self.dir_name,"output"+str(i))
            if not os.path.exists(temp_output):
                break

            ##### 读取分块内容,依次附加到output_file  #####
            print "write chunk", i
            tp=open(temp_output,"rb")
            buf = tp.read(1024 * 1024)
            fp.write(buf)
            tp.close()
            i += 1

        fp.close()

    #打印进度
    def progress(self,download_total,downloaded,uploaded_total,upload):
        print "To be downloaded" + str(download_total)
        print "Downloaded : " + str(downloaded)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值