窗外下着小雨,作为单身程序员的我逛着逛着发现一篇好东西,来自知乎 你都用 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爬取视频(其实是一篇福利)的更多相关文章

  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. EntityFrameworkCore v1.1.1 问题汇总

    随着宇宙第一IDE的最新版本发布[2017/3/7],AspNetCore 和EntityFrameworkCore(团队)都发布了最新的代码. 不过在我看来,这些到还不是最重要的.最重要的是dotn ...

  2. 选择客栈noip2011

    哈,没想到吧.今天居然有两篇(算什么,厕所读物吗 选择客栈 本题的更优解请跳转zt 这题11年,刚改2day. 对于30% 的数据,有 n ≤100: 对于50% 的数据,有 n ≤1,000: 对于 ...

  3. java多线程编程核心技术——第三章

    第一节等待/通知机制 1.1不使用等待/通知机制实现线程间的通讯 1.2什么是等待/通知机制 1.3等待/通知机制的实现 1.4方法wait()锁释放与notify()锁不释放 1.5当interru ...

  4. always中的敏感变量

    always语句下如果有判断语句if,那么if语句中的条件必须有always中的敏感变量. 否则错误提示为:Error (10200): Verilog HDL Conditional Stateme ...

  5. 王立平--WebView的缓存机制

    WebView的缓存能够分为页面缓存和数据缓存. 1.   页面缓存是指载入一个网页时的html.JS.CSS等页面或者资源数据. 这些缓存资源是因为浏览器的行为而产生.开发人员仅仅能通过配置HTTP ...

  6. iOS_20_微博OAuth授权_取得用户授权的accessToken

    终于效果图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJlX2VtaW5lbnQ=/font/5a6L5L2T/fontsize/400/fill ...

  7. 对于是否在一个python程序中编写函数的启发

    那我们到底是应该直接使用这些模块级别的函数呢,还是先编译一个模式对象,再调用模式对象的方法呢?这其实取决于正则表达式的使用频率,如果说我们这个程序只是偶尔使用到正则表达式,那么全局函数是比较方便的:如 ...

  8. VirtualBox 安装 Ubuntu 14.04 无法调节分辨率问题

    基础环境 宿主系统:Windows 10 虚拟机系统:Ubuntu 14.04-32bit.Ubuntu 14.04-64bit VirtualBox:5.2.0 r118431 (Qt5.6.2) ...

  9. Idea中右边的maven projects窗口找不到了如何调出来

    关于Idea中右边的maven  projects窗口找不到了如何调出来? 具体的idea版本我不太清楚,我用的是2016版,其他版本应该也是一样的. 首先idea自带了maven控件,不像Eclip ...

  10. Web服务器、应用服务器、Web容器、反向代理服务器区别与联系

    作者: 帅虫哥 出处:www.cnblogs.com/vipyoumay/p/7455431.html(点击尾部阅读原文前往) 我们知道,不同肤色的人外貌差别很大,而双胞胎的辨识很难.有意思的是Web ...