天天看點

【python資料下載下傳】urllib與requests的簡單使用使用python進行資料下載下傳

使用python進行資料下載下傳

文章目錄

  • 使用python進行資料下載下傳
    • 使用urllib進行下載下傳
    • 使用requests進行下載下傳
    • 多程序
      • 完整代碼

使用urllib進行下載下傳

在使用python作為爬蟲與下載下傳工具時,

urllib

是個常用的包,其核心下載下傳方法使用起來非常簡單,隻需一個方法:

  • urllib.request.urlretrieve():
    urllib.request.urlretrieve(url, filename=None, reporthook=None, data=None)
      """
      @filename: 指定的存儲路徑
      @reporthook: 指定的回調函數, 包含block number, a read size, and the total file size
      """
               
  • 實際上簡單使用隻需要一行代碼:
    import urllib
    urllib.request.urlretrieve(download_url, save_path)
               

而當我們需要顯示下載下傳進度時,可以在

reporthook

中傳入一個回調函數,這個回調函數接口是固定的,會傳入三個參數分别為:目前已經下載下傳的塊,每次傳輸的塊大小以及檔案總大小。

  • reporthook的簡單實作
    def schedule(blocknum,blocksize,totalsize):
      # print(blocknum, blocksize, totalsize)
      """
      * 用于urllib.request.urlretrieve方法的回調函數
      @ blocknum:目前已經下載下傳的塊
      @ blocksize:每次傳輸的塊大小
      @ totalsize:網頁檔案總大小
      """
      if totalsize == 0:
          percent = 0
      else:
          percent = blocknum * blocksize / totalsize
      if percent > 1.0:
          percent = 1.0
      percent = percent * 100
      # 列印下載下傳的百分比
      print("download %s : %.4f%%" %(base_name, percent))
               

使用requests進行下載下傳

除了

urllib

外使用

requests

子產品也是一個常用的方法。使用

requests

時,多數的操作需要手動完成,但也是以在實行斷點續傳等操作時也更加友善。

  • 使用requests進行資料下載下傳:
    # 首次請求
    r1 = requests.get(download_url, stream=True, verify=False)
    # 獲得檔案的總大小
    total_size = int(r1.headers['Content-Length'])
    if os.path.exists(video_save_path):
        temp_size = os.path.getsize(video_save_path)
    else:
        temp_size = 0
    # 下載下傳時,從本地檔案已經下載下傳過的檔案後面繼續下載下傳
    headers = {'Range': 'bytes=%d-' % temp_size}
    r = requests.get(download_url, stream=True, verify=False, headers=headers)
    with open(video_save_path, "ab") as f:
        # 當下載下傳大檔案時,不能一次加載,采用疊代方式下載下傳
        for chunk in r.iter_content(chunk_size=1024):
            if chunk:
                temp_size += len(chunk)
                f.write(chunk)
                f.flush()
                # 列印下載下傳進度
                print("download %s : %d / %d || %.4f%%" %(base_name, temp_size, total_size, temp_size/total_size))
               

多程序

python提供了便利的多程序方法,這裡我們采用了最簡單的方式:

  • 多程序
    def download():
      # 解析下載下傳檔案位址并存入清單
      with open('download_urls.txt', 'r', encoding='utf-8') as f:
          urls = f.readlines()
          f.close()
      process = []
      # 建立程序并加入程序池,每個程序對應一個下載下傳檔案(檔案較大且個數較少,根據需要改寫)
      for url in urls:
          process.append(Process(target=_download, args=[url.strip()]))
      # 建立并啟動程序
      [p.start() for p in process]
      # 等待子程序結束後再繼續往下運作,在目前位置阻塞主程序
      [p.join() for p in process]
               

完整代碼

"""
* 提供了多程序下載下傳
* 使用urllib.request包,當下載下傳失敗時自動重新下載下傳
"""
import os
import os
import urllib.request
import socket
import sys
import logging
# 設定逾時時間
socket.setdefaulttimeout(30)

from multiprocessing import Process, Queue
#設定日志子產品
logging.basicConfig(level=logging.DEBUG #設定日志輸出格式
                    ,filename="demo.log" #log日志輸出的檔案位置和檔案名
                    ,filemode="w" #檔案的寫入格式,w為重新寫入檔案,預設是追加
                    ,format="%(asctime)s - %(name)s - %(levelname)-9s - %(filename)-8s : %(lineno)s line - %(message)s" #日志輸出的格式
                    # -8表示占位符,讓輸出左對齊,輸出長度都為8位
                    ,datefmt="%Y-%m-%d %H:%M:%S" #時間輸出的格式
                    )

def _download(*args):
    """
    * 子程序函數,負責從每一個傳入的url下載下傳檔案
    """
    logger=logging.getLogger()
    fh = logging.FileHandler('log.txt', mode='a', encoding='utf-8', delay=False)
    logger.addHandler(fh)

    # 下載下傳位址解析,指定存儲位置
    download_url = args[0]
    base_name = os.path.basename(download_url)
    video_save_path = os.path.join('save/', base_name)
    
    def schedule(blocknum,blocksize,totalsize):
        # print(blocknum, blocksize, totalsize)
        """
        * 用于urllib.request.urlretrieve方法的回調函數,接口是固定的
        @ blocknum:目前已經下載下傳的塊
        @ blocksize:每次傳輸的塊大小
        @ totalsize:網頁檔案總大小
        """
        if totalsize == 0:
            percent = 0
        else:
            percent = blocknum * blocksize / totalsize
        if percent > 1.0:
            percent = 1.0
        percent = percent * 100
        print("download %s : %.4f%%" %(base_name, percent))
  
    while True:
        #當下載下傳失敗時重新下載下傳
        try:
            logger.info('downloding %s ...'%download_url)
            urllib.request.urlretrieve(download_url, video_save_path, schedule)
        except Exception as e:
            logger.info('exception has occured in downloading {}: {}'.format(download_url, e))
            continue
        break

def download():
    # 解析下載下傳檔案位址并存入清單
    with open('download.txt', 'r', encoding='utf-8') as f:
        lines = f.readlines()
        f.close()
    process = []
    # 建立程序并加入程序池,每個程序對應一個下載下傳檔案(檔案較大且個數較少,根據需要改寫)
    for line in lines:
        process.append(Process(target=_download, args=[line.strip()]))
    # 建立并啟動程序
    [p.start() for p in process]
    # 等待子程序結束後再繼續往下運作,在目前位置阻塞主程序
    [p.join() for p in process]

    

if __name__ == '__main__':
    
    download()