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

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

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

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

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

遭遇当头一棒:

  1. AttributeError: __exit__

这文档也会骗人的么!

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

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

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

  1. # -*- coding: utf-8 -*-
  2. import requests
  3. from contextlib import closing
  4. import os
  5.  
  6. def download_file(url, path):
  7. with closing(requests.get(url, stream=True)) as r:
  8. chunk_size = 1024
  9. content_size = int(r.headers['content-length'])
  10. print '下载开始'
  11. with open(path, "wb") as f:
  12. for chunk in r.iter_content(chunk_size=chunk_size):
  13. f.write(chunk)
  14. f.flush()
  15. os.fsync(f.fileno())

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

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

结果就很直观了:

  1. 已下载2.579129%
  2. 已下载2.581255%
  3. 已下载2.583382%
  4. 已下载2.585508%

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

  1. # -*- coding: utf-8 -*-
  2. import requests
  3. from contextlib import closing
  4. import time
  5.  
  6. def download_file(url, path):
  7. with closing(requests.get(url, stream=True)) as r:
  8. chunk_size = 1024*10
  9. content_size = int(r.headers['content-length'])
  10. print '下载开始'
  11. with open(path, "wb") as f:
  12. p = ProgressData(size = content_size, unit='Kb', block=chunk_size)
  13. for chunk in r.iter_content(chunk_size=chunk_size):
  14. f.write(chunk)
  15. p.output()
  16.  
  17. class ProgressData(object):
  18.  
  19. def __init__(self, block,size, unit, file_name='', ):
  20. self.file_name = file_name
  21. self.block = block/1000.0
  22. self.size = size/1000.0
  23. self.unit = unit
  24. self.count = 0
  25. self.start = time.time()
  26. def output(self):
  27. self.end = time.time()
  28. self.count += 1
  29. speed = self.block/(self.end-self.start) if (self.end-self.start)>0 else 0
  30. self.start = time.time()
  31. loaded = self.count*self.block
  32. progress = round(loaded/self.size, 4)
  33. if loaded >= self.size:
  34. print u'%s下载完成\r\n'%self.file_name
  35. else:
  36. print u'{0}下载进度{1:.2f}{2}/{3:.2f}{4} 下载速度{5:.2%} {6:.2f}{7}/s'.\
  37. format(self.file_name, loaded, self.unit,\
  38. self.size, self.unit, progress, speed, self.unit)
  39. print '%50s'%('/'*int((1-progress)*50))

运行:

  1. 下载开始
  2. 下载进度10.24Kb/120174.05Kb 0.01% 下载速度4.75Kb/s
  3. /////////////////////////////////////////////////
  4. 下载进度20.48Kb/120174.05Kb 0.02% 下载速度32.93Kb/s
  5. /////////////////////////////////////////////////

看上去舒服多了。

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

  1. # -*- coding: utf-8 -*-
  2. import requests
  3. from contextlib import closing
  4. import time
  5. import Queue
  6. import hashlib
  7. import threading
  8. import os
  9.  
  10. def download_file(url, path):
  11. with closing(requests.get(url, stream=True)) as r:
  12. chunk_size = 1024*10
  13. content_size = int(r.headers['content-length'])
  14. if os.path.exists(path) and os.path.getsize(path)>=content_size:
  15. print '已下载'
  16. return
  17. print '下载开始'
  18. with open(path, "wb") as f:
  19. p = ProgressData(size = content_size, unit='Kb', block=chunk_size, file_name=path)
  20. for chunk in r.iter_content(chunk_size=chunk_size):
  21. f.write(chunk)
  22. p.output()
  23.  
  24. class ProgressData(object):
  25.  
  26. def __init__(self, block,size, unit, file_name='', ):
  27. self.file_name = file_name
  28. self.block = block/1000.0
  29. self.size = size/1000.0
  30. self.unit = unit
  31. self.count = 0
  32. self.start = time.time()
  33. def output(self):
  34. self.end = time.time()
  35. self.count += 1
  36. speed = self.block/(self.end-self.start) if (self.end-self.start)>0 else 0
  37. self.start = time.time()
  38. loaded = self.count*self.block
  39. progress = round(loaded/self.size, 4)
  40. if loaded >= self.size:
  41. print u'%s下载完成\r\n'%self.file_name
  42. else:
  43. print u'{0}下载进度{1:.2f}{2}/{3:.2f}{4} {5:.2%} 下载速度{6:.2f}{7}/s'.\
  44. format(self.file_name, loaded, self.unit,\
  45. self.size, self.unit, progress, speed, self.unit)
  46. print '%50s'%('/'*int((1-progress)*50))
  47.  
  48. queue = Queue.Queue()
  49.  
  50. def run():
  51. while True:
  52. url = queue.get(timeout=100)
  53. if url is None:
  54. print u'全下完啦'
  55. break
  56. h = hashlib.md5()
  57. h.update(url)
  58. name = h.hexdigest()
  59. path = 'e:/download/' + name + '.mp4'
  60. download_file(url, path)
  61.  
  62. def get_url():
  63. queue.put(None)
  64.  
  65. if __name__ == '__main__':
  66. get_url()
  67. for i in xrange(4):
  68. t = threading.Thread(target=run)
  69. t.daemon = True
  70. t.start()

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

  

Python爬取视频(其实是一篇福利)的更多相关文章

  1. Python爬取视频指南

    摘自:https://www.jianshu.com/p/9ca86becd86d 前言 前两天尔羽说让我爬一下菜鸟窝的教程视频,这次就跟大家来说说Python爬取视频的经验 正文 https://w ...

  2. 以“有匪”为实战案例,用python爬取视频弹幕

    最近腾讯独播热剧"有匪"特别火,我也一直在追剧,每次看剧的时候都是把弹幕开启的,这样子看剧才有灵魂呀.借助手中的技术,想爬取弹幕分析下这部电视剧的具体情况和网友们的评论!对于弹幕的 ...

  3. python爬取视频网站m3u8视频,下载.ts后缀文件,合并成整视频

    最近发现一些网站,可以解析各大视频网站的vip.仔细想了想,这也算是爬虫呀,爬的是视频数据. 首先选取一个视频网站,我选的是 影视大全 ,然后选择上映不久的电影 “一出好戏” . 分析页面 我用的是c ...

  4. 没有内涵段子可以刷了,利用Python爬取段友之家贴吧图片和小视频(含源码)

    由于最新的视频整顿风波,内涵段子APP被迫关闭,广大段友无家可归,但是最近发现了一个"段友"的app,版本更新也挺快,正在号召广大段友回家,如下图,有兴趣的可以下载看看(ps:我不 ...

  5. python爬取快手视频 多线程下载

    就是为了兴趣才搞的这个,ok 废话不多说 直接开始. 环境: python 2.7 + win10 工具:fiddler postman 安卓模拟器 首先,打开fiddler,fiddler作为htt ...

  6. 用Python爬取B站、腾讯视频、爱奇艺和芒果TV视频弹幕!

    众所周知,弹幕,即在网络上观看视频时弹出的评论性字幕.不知道大家看视频的时候会不会点开弹幕,于我而言,弹幕是视频内容的良好补充,是一个组织良好的评论序列.通过分析弹幕,我们可以快速洞察广大观众对于视频 ...

  7. 教你用python爬取抖音app视频

    记录一下如何用python爬取app数据,本文以爬取抖音视频app为例. 编程工具:pycharm app抓包工具:mitmproxy app自动化工具:appium 运行环境:windows10 思 ...

  8. python爬取微信小程序(实战篇)

    python爬取微信小程序(实战篇) 本文链接:https://blog.csdn.net/HeyShHeyou/article/details/90452656 展开 一.背景介绍 近期有需求需要抓 ...

  9. 【Python爬虫案例】用Python爬取李子柒B站视频数据

    一.视频数据结果 今天是2021.12.7号,前几天用python爬取了李子柒的油管评论并做了数据分析,可移步至: https://www.cnblogs.com/mashukui/p/1622025 ...

随机推荐

  1. js作用域与执行环境(前端基础系列)

    一.作用域(what?) 官方解释是:"一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域." 单从文字理解比较难懂,举个栗子: ...

  2. Solr6.1.0Windows安装步骤

    一. 环境 solr 6.1.0  下载地址 http://archive.apache.org/dist/lucene/solr/6.1.0/ jdk 1.8 tomcat8 二. 安装solr到t ...

  3. Android学习笔记(10).布局管理器

    布局管理器的几个类都是ViewGroup派生的,用于管理组件的分布和大小,使用布局管理器能够非常好地解决屏幕适配问题. 布局管理器本身也是一个UI组件,布局管理器能够相互嵌套使用,以下是布局管理器的类 ...

  4. Codeforces 29D Ant on the Tree 树的遍历 dfs序

    题目链接:点击打开链接 题意: 给定n个节点的树 1为根 则此时叶子节点已经确定 最后一行给出叶子节点的顺序 目标: 遍历树并输出路径.要求遍历叶子节点时依照给定叶子节点的先后顺序訪问. 思路: 给每 ...

  5. OC对象与Core Foundation对象的转换

    OC对象使用了ARC,自己主动释放内存,可是CF中的对象没有ARC,必需要手动进行引用计数和内存释放. 两者对象之间的互相转换有三种形式: 1.__bridge: 直接转换,部改变对象的持有状况: i ...

  6. Jenkins具体安装与构建部署使用教程

    Jenkins是一个开源软件项目.旨在提供一个开放易用的软件平台,使软件的持续集成变成可能. Jenkins是基于Java开发的一种持续集成工具,用于监控持续反复的工作,功能包含:1.持续的软件版本号 ...

  7. Centos7.4下用Docker-Compose部署WordPress

    前言 最近在学习Docker相关知识,通过阅读第一本Docker书后,正想着手实战用一下这个技术,但又不太敢直接在项目环境下动手.考虑足足三秒钟之后决定买个阿里云ECS搭建一个属于自己的基于Docke ...

  8. VMware 虚拟机 Ubuntu 登录后蓝屏问题

    问题起因 在一次下班收工时关闭虚拟机 Ubuntu,出现异常:关机好久没有完成,进而导致 VMware 软件卡死.后来强行杀死 VMware.第二天上班,启动 VMware 后开启 Ubuntu,输入 ...

  9. License友好的前端组件合集

    在做Web开发过程中,不可避免的会用到各种UI组件.通常,我们并不会需要什么组件,都去自己开发的,网上有那么多好用的,我们为什么要自己造轮子呢?我通常只会在网上找不到合适的组件时,才会去自己开发一套. ...

  10. MongoDB的CURD命令

    1.启动客户端 在MongDB服务成功启动的情况下,打开cmd,在MongDB的bin文件目录下执行MongDB命令 可以看到MongDB版本号3.0.7与默认连接的数据库test.test数据库是系 ...