Python爬取视频(其实是一篇福利)过程解析


Posted in Python onAugust 01, 2019

窗外下着小雨,作为单身程序员的我逛着逛着发现一篇好东西,来自知乎 你都用 Python 来做什么?的第一个高亮答案。

到上面去看了看,地址都是明文的,得,赶紧开始吧。

下载流式文件,requests库中请求的stream设为True就可以啦,文档在此。

先找一个视频地址试验一下:

# -*- coding: utf-8 -*-
import requests 
def download_file(url, path):
  with requests.get(url, stream=True) as r:
    chunk_size = 1024
    content_size = int(r.headers['content-length'])
    print '下载开始'
    with open(path, "wb") as f:
      for chunk in r.iter_content(chunk_size=chunk_size):
        f.write(chunk) 
if __name__ == '__main__':
  url = '就在原帖...'
  path = '想存哪都行'
  download_file(url, path)

遭遇当头一棒:

AttributeError: __exit__

这文档也会骗人的么!

看样子是没有实现上下文需要的__exit__方法。既然只是为了保证要让r最后close以释放连接池,那就使用contextlib的closing特性好了:

# -*- coding: utf-8 -*-
import requests
from contextlib import closing
 
def download_file(url, path):
  with closing(requests.get(url, stream=True)) as r:
    chunk_size = 1024
    content_size = int(r.headers['content-length'])
    print '下载开始'
    with open(path, "wb") as f:
      for chunk in r.iter_content(chunk_size=chunk_size):
        f.write(chunk)

程序正常运行了,不过我盯着这文件,怎么大小不见变啊,到底是完成了多少了呢?还是要让下好的内容及时存进硬盘,还能省点内存是不是:

# -*- coding: utf-8 -*-
import requests
from contextlib import closing
import os
 
def download_file(url, path):
  with closing(requests.get(url, stream=True)) as r:
    chunk_size = 1024
    content_size = int(r.headers['content-length'])
    print '下载开始'
    with open(path, "wb") as f:
      for chunk in r.iter_content(chunk_size=chunk_size):
        f.write(chunk)
        f.flush()
        os.fsync(f.fileno())

文件以肉眼可见的速度在增大,真心疼我的硬盘,还是最后一次写入硬盘吧,程序中记个数就好了:

def download_file(url, path):
  with closing(requests.get(url, stream=True)) as r:
    chunk_size = 1024
    content_size = int(r.headers['content-length'])
    print '下载开始'
    with open(path, "wb") as f:
      n = 1
      for chunk in r.iter_content(chunk_size=chunk_size):
        loaded = n*1024.0/content_size
        f.write(chunk)
        print '已下载{0:%}'.format(loaded)
        n += 1

结果就很直观了:

已下载2.579129%
已下载2.581255%
已下载2.583382%
已下载2.585508%

心怀远大理想的我怎么会只满足于这一个呢,写个类一起使用吧:

# -*- coding: utf-8 -*-
import requests
from contextlib import closing
import time 
def download_file(url, path):
  with closing(requests.get(url, stream=True)) as r:
    chunk_size = 1024*10
    content_size = int(r.headers['content-length'])
    print '下载开始'
    with open(path, "wb") as f:
      p = ProgressData(size = content_size, unit='Kb', block=chunk_size)
      for chunk in r.iter_content(chunk_size=chunk_size):
        f.write(chunk)
        p.output()
 
 
class ProgressData(object):
 
  def __init__(self, block,size, unit, file_name='', ):
    self.file_name = file_name
    self.block = block/1000.0
    self.size = size/1000.0
    self.unit = unit
    self.count = 0
    self.start = time.time()
  def output(self):
    self.end = time.time()
    self.count += 1
    speed = self.block/(self.end-self.start) if (self.end-self.start)>0 else 0
    self.start = time.time()
    loaded = self.count*self.block
    progress = round(loaded/self.size, 4)
    if loaded >= self.size:
      print u'%s下载完成\r\n'%self.file_name
    else:
      print u'{0}下载进度{1:.2f}{2}/{3:.2f}{4} 下载速度{5:.2%} {6:.2f}{7}/s'.\
         format(self.file_name, loaded, self.unit,\
         self.size, self.unit, progress, speed, self.unit)
      print '%50s'%('/'*int((1-progress)*50))

运行:

下载开始
下载进度10.24Kb/120174.05Kb 0.01% 下载速度4.75Kb/s
/////////////////////////////////////////////////
下载进度20.48Kb/120174.05Kb 0.02% 下载速度32.93Kb/s
/////////////////////////////////////////////////

看上去舒服多了。

下面要做的就是多线程同时下载了,主线程生产url放入队列,下载线程获取url:

# -*- coding: utf-8 -*-
import requests
from contextlib import closing
import time
import Queue
import hashlib
import threading
import os 
def download_file(url, path):
  with closing(requests.get(url, stream=True)) as r:
    chunk_size = 1024*10
    content_size = int(r.headers['content-length'])
    if os.path.exists(path) and os.path.getsize(path)>=content_size:
      print '已下载'
      return
    print '下载开始'
    with open(path, "wb") as f:
      p = ProgressData(size = content_size, unit='Kb', block=chunk_size, file_name=path)
      for chunk in r.iter_content(chunk_size=chunk_size):
        f.write(chunk)
        p.output()
 
class ProgressData(object):
 
  def __init__(self, block,size, unit, file_name='', ):
    self.file_name = file_name
    self.block = block/1000.0
    self.size = size/1000.0
    self.unit = unit
    self.count = 0
    self.start = time.time()
  def output(self):
    self.end = time.time()
    self.count += 1
    speed = self.block/(self.end-self.start) if (self.end-self.start)>0 else 0
    self.start = time.time()
    loaded = self.count*self.block
    progress = round(loaded/self.size, 4)
    if loaded >= self.size:
      print u'%s下载完成\r\n'%self.file_name
    else:
      print u'{0}下载进度{1:.2f}{2}/{3:.2f}{4} {5:.2%} 下载速度{6:.2f}{7}/s'.\
         format(self.file_name, loaded, self.unit,\
         self.size, self.unit, progress, speed, self.unit)
      print '%50s'%('/'*int((1-progress)*50))
 queue = Queue.Queue() 
def run():
  while True:
    url = queue.get(timeout=100)
    if url is None:
      print u'全下完啦'
      break
    h = hashlib.md5()
    h.update(url)
    name = h.hexdigest()
    path = 'e:/download/' + name + '.mp4'
    download_file(url, path) 
def get_url():
  queue.put(None)
if __name__ == '__main__':
  get_url()
  for i in xrange(4):
    t = threading.Thread(target=run)
    t.daemon = True
    t.start()

加了重复下载的判断,至于怎么源源不断的生产url,诸位摸索吧,保重身体!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python遍历文件夹并删除特定格式文件的示例
Mar 05 Python
python查找目录下指定扩展名的文件实例
Apr 01 Python
Python实现快速多线程ping的方法
Jul 15 Python
Python使用中文正则表达式匹配指定中文字符串的方法示例
Jan 20 Python
pandas or sql计算前后两行数据间的增值方法
Apr 20 Python
在dataframe两列日期相减并且得到具体的月数实例
Jul 03 Python
Python关于excel和shp的使用在matplotlib
Jan 03 Python
Python实现bilibili时间长度查询的示例代码
Jan 14 Python
python 最简单的实现适配器设计模式的示例
Jun 30 Python
python中字符串的编码与解码详析
Dec 03 Python
Python基础之元类详解
Apr 29 Python
Python爬虫之自动爬取某车之家各车销售数据
Jun 02 Python
flask框架jinja2模板与模板继承实例分析
Aug 01 #Python
Win10环境python3.7安装dlib模块趟过的坑
Aug 01 #Python
python爬虫解决验证码的思路及示例
Aug 01 #Python
Django多数据库的实现过程详解
Aug 01 #Python
Python解决pip install时出现的Could not fetch URL问题
Aug 01 #Python
numpy.meshgrid()理解(小结)
Aug 01 #Python
Python-接口开发入门解析
Aug 01 #Python
You might like
星际争霸, 教主第一视角, ZvT经典龙蛇演义
2020/03/02 星际争霸
php与paypal整合方法
2010/11/28 PHP
php自动加载机制的深入分析
2013/06/08 PHP
改写ThinkPHP的U方法使其路由下分页正常
2014/07/02 PHP
yii框架redis结合php实现秒杀效果(实例代码)
2017/10/26 PHP
firefo xml 读写实现js代码
2009/06/11 Javascript
javascript 密码框防止用户粘贴和复制的实现代码
2014/02/17 Javascript
用js提交表单解决一个页面有多个提交按钮的问题
2014/09/01 Javascript
jQuery+canvas实现的球体平抛及颜色动态变换效果
2016/01/28 Javascript
使用Xcache缓存器加速PHP网站的配置方法
2017/04/22 Javascript
elementui的默认样式修改方法
2018/02/23 Javascript
Vue2.0系列之过滤器的使用
2018/03/01 Javascript
关于微信小程序bug记录与解决方法
2018/08/15 Javascript
js实现幻灯片轮播图
2020/08/14 Javascript
nodeJs项目在阿里云的简单部署
2020/11/27 NodeJs
在ironpython中利用装饰器执行SQL操作的例子
2015/05/02 Python
python冒泡排序简单实现方法
2015/07/09 Python
浅析Python的Django框架中的Memcached
2015/07/23 Python
python获取多线程及子线程的返回值
2017/11/15 Python
python 修改本地网络配置的方法
2019/08/14 Python
python闭包、深浅拷贝、垃圾回收、with语句知识点汇总
2020/03/11 Python
python与c语言的语法有哪些不一样的
2020/09/13 Python
巧用 CSS3的webkit-box-reflect 倒影实现各类动效
2021/03/05 HTML / CSS
澳大利亚制造的羊皮靴:Original UGG Boots
2017/11/13 全球购物
Chi Chi London官网:购买连衣裙和礼服
2020/10/25 全球购物
意大利时尚奢侈品店:D’Aniello Boutique
2021/01/19 全球购物
Laravel的加密解密与哈希实例讲解
2021/03/24 PHP
英语师范专业毕业生自荐信
2013/09/21 职场文书
销售文员岗位职责
2013/11/29 职场文书
求职信模版
2013/11/30 职场文书
优秀电子工程系毕业生求职信
2014/05/24 职场文书
2014党员批评和自我批评思想汇报
2014/09/21 职场文书
2015清明节祭奠英烈寄语大全
2015/03/04 职场文书
2015年七七事变78周年纪念活动方案
2015/05/06 职场文书
投诉信格式范文
2015/07/02 职场文书
Java集成swagger文档组件
2021/06/28 Java/Android