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 相关文章推荐
wxpython中利用线程防止假死的实现方法
Aug 11 Python
python将ansible配置转为json格式实例代码
May 15 Python
Python将DataFrame的某一列作为index的方法
Apr 08 Python
解决安装tensorflow遇到无法卸载numpy 1.8.0rc1的问题
Jun 13 Python
使用python生成杨辉三角形的示例代码
Aug 29 Python
浅述python2与python3的简单区别
Sep 19 Python
对numpy中向量式三目运算符详解
Oct 31 Python
opencv与numpy的图像基本操作
Mar 08 Python
Python button选取本地图片并显示的实例
Jun 13 Python
解决python中的幂函数、指数函数问题
Nov 25 Python
如何在pycharm中安装第三方包
Oct 27 Python
Python实现Matplotlib,Seaborn动态数据图
May 06 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
PHP中SimpleXML函数用法分析
2014/11/26 PHP
thinkphp常见路径用法分析
2014/12/02 PHP
浅谈PHP中output_buffering
2015/07/13 PHP
thinkphp3.x中cookie方法的用法分析
2016/05/19 PHP
SAE实时日志接口SDK用法示例
2016/10/09 PHP
php中static和const关键字用法分析
2016/12/07 PHP
PHP实现将base64编码字符串转换成图片示例
2018/06/22 PHP
PHP聊天室简单实现方法详解
2018/12/08 PHP
php无限极分类实现方法分析
2019/07/04 PHP
js小技巧--自动隐藏红叉叉
2007/08/13 Javascript
js渐变显示渐变消失示例代码
2013/08/01 Javascript
jQuery jcrop插件截图使用方法
2013/11/20 Javascript
js判断60秒以及倒计时示例代码
2014/01/24 Javascript
使用AngularJS对路由进行安全性处理的方法
2015/06/18 Javascript
nodejs读写json文件的简单方法(必看)
2017/03/09 NodeJs
Bootstrap 3浏览器兼容性问题及解决方案
2017/04/11 Javascript
基于angular-utils-ui-breadcrumbs使用心得(分享)
2017/11/03 Javascript
详解nodejs解压版安装和配置(带有搭建前端项目脚手架)
2018/12/06 NodeJs
基于Vue-Cli 打包自动生成/抽离相关配置文件的实现方法
2018/12/09 Javascript
node错误处理与日志记录的实现
2018/12/24 Javascript
详解vuex之store源码简单解析
2019/06/13 Javascript
jQuery实现动态加载瀑布流
2020/09/01 jQuery
vue-cli4使用全局less文件中的变量配置操作
2020/10/21 Javascript
python 切片和range()用法说明
2013/03/24 Python
在Python的Tornado框架中实现简单的在线代理的教程
2015/05/02 Python
Anaconda2下实现Python2.7和Python3.5的共存方法
2018/06/11 Python
python文件拆分与重组实例
2018/12/10 Python
Python测试模块doctest使用解析
2019/08/10 Python
曼城官方网上商店:Manchester City
2019/09/10 全球购物
沙滩主题婚礼活动策划方案
2014/09/15 职场文书
银行授权委托书范本
2014/10/04 职场文书
群众路线批评与自我批评发言稿
2014/10/16 职场文书
幼儿园中班个人总结
2015/02/28 职场文书
三十年同学聚会感言
2015/07/30 职场文书
2016年乡镇综治宣传月活动总结
2016/03/16 职场文书
如何写好竞聘报告
2019/04/03 职场文书