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使用rabbitmq实现网络爬虫示例
Feb 20 Python
python使用nntp读取新闻组内容的方法
May 08 Python
Python解惑之True和False详解
Apr 24 Python
解读python logging模块的使用方法
Apr 17 Python
python切片及sys.argv[]用法详解
May 25 Python
python的schedule定时任务模块二次封装方法
Feb 19 Python
django框架自定义模板标签(template tag)操作示例
Jun 24 Python
简单了解Django ContentType内置组件
Jul 23 Python
详解python中的index函数用法
Aug 06 Python
python将音频进行变速的操作方法
Apr 08 Python
使用python批量修改XML文件中图像的depth值
Jul 22 Python
python gui开发——制作抖音无水印视频下载工具(附源码)
Feb 07 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
你真的了解JavaScript吗?
2007/02/24 Javascript
JavaScript入门教程(2) JS基础知识
2009/01/31 Javascript
js实现拉伸拖动iframe的具体代码
2013/08/03 Javascript
JQuery EasyUI 日期控件如何控制日期选择区间
2014/05/05 Javascript
浅析javascript操作 cookie对象
2014/12/26 Javascript
JavaScript中的数组操作介绍
2014/12/30 Javascript
JavaScript中join()方法的使用简介
2015/06/09 Javascript
jquery实现的简单二级菜单效果代码
2015/09/22 Javascript
js实现楼层效果的简单实例
2016/07/15 Javascript
AngularJS bootstrap启动详解及实例代码
2016/09/14 Javascript
bootstrap laydate日期组件使用详解
2017/01/04 Javascript
浅谈JavaScript的innerWidth与innerHeight
2017/10/12 Javascript
详解http访问解析流程原理
2017/10/18 Javascript
Angular实现的敏感文字自动过滤与提示功能示例
2017/12/29 Javascript
详解使用jQuery.i18n.properties实现js国际化
2018/05/04 jQuery
Vue-cli3项目配置Vue.config.js实战记录
2018/07/29 Javascript
详解react-refetch的使用小例子
2019/02/15 Javascript
详解JavaScript函数callee、call、apply的区别
2019/03/08 Javascript
微信小程序使用wx.request请求服务器json数据并渲染到页面操作示例
2019/03/30 Javascript
详解vue.js移动端配置flexible.js及注意事项
2019/04/10 Javascript
vue element upload组件 file-list的动态绑定实现
2019/10/11 Javascript
详解Python文本操作相关模块
2017/06/22 Python
django的model操作汇整详解
2019/07/26 Python
如何基于Python获取图片的物理尺寸
2019/11/25 Python
keras 使用Lambda 快速新建层 添加多个参数操作
2020/06/10 Python
Python3爬虫中Splash的知识总结
2020/07/10 Python
Python Charles抓包配置实现流程图解
2020/09/29 Python
纯CSS3制作页面切换效果的实例代码
2019/05/30 HTML / CSS
详解FireFox下Canvas使用图像合成绘制SVG的Bug
2019/07/10 HTML / CSS
法国珠宝店:CLEOR
2017/01/29 全球购物
英国在线汽车和面包车零件商店:Car Parts 4 Less
2018/08/15 全球购物
skyn ICELAND官网:冰岛成分天然护肤品
2020/08/24 全球购物
婚前财产公证书
2014/04/10 职场文书
职称评定个人总结
2015/03/05 职场文书
工作迟到检讨书范文
2015/05/06 职场文书
保险公司反洗钱宣传活动总结
2015/05/08 职场文书