使用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()