【python数据下载】urllib与requests的简单使用

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

你可能感兴趣的:(杂货铺,python,爬虫)