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使用Scrapy爬取妹子图
May 28 Python
Python聚类算法之凝聚层次聚类实例分析
Nov 20 Python
Python中强大的命令行库click入门教程
Dec 26 Python
Python使用requests及BeautifulSoup构建爬虫实例代码
Jan 24 Python
python进程和线程用法知识点总结
May 28 Python
python 将日期戳(五位数时间)转换为标准时间
Jul 11 Python
python文字转语音实现过程解析
Nov 12 Python
Python for i in range ()用法详解
Sep 18 Python
Tensorflow 1.0之后模型文件、权重数值的读取方式
Feb 12 Python
TFRecord文件查看包含的所有Features代码
Feb 17 Python
Python 随机按键模拟2小时
Dec 30 Python
python基础学习之生成器与文件系统知识总结
May 25 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
基于header的一些常用指令详解
2013/06/06 PHP
PHP实现求连续子数组最大和问题2种解决方法
2017/12/26 PHP
Laravel 框架返回状态拦截代码
2019/10/18 PHP
关于Anemometer图形化显示MySQL慢日志的工具搭建及使用的详细介绍
2020/07/13 PHP
select 控制网页内容隐藏于显示的实现代码
2010/05/25 Javascript
javascript当中的代码嗅探扩展原生对象和原型(prototype)
2013/01/11 Javascript
控制页面按钮在后台执行期间不重复提交的JS方法
2013/06/24 Javascript
javascript得到当前页的来路即前一页地址的方法
2014/02/18 Javascript
javascript中clipboardData对象用法详解
2015/05/13 Javascript
详细分析JavaScript变量类型
2015/07/08 Javascript
js中对函数设置默认参数值的3种方法
2015/10/23 Javascript
Knockoutjs 学习系列(一)ko初体验
2016/06/07 Javascript
JS数组返回去重后数据的方法解析
2017/01/03 Javascript
Bootstarp 基础教程之表单部分实例代码
2017/02/03 Javascript
Vuex 使用 v-model 配合 state的方法
2018/11/13 Javascript
利用原生的JavaScript实现简单拼图游戏
2018/11/18 Javascript
微信小程序实现手势滑动卡片效果
2019/08/26 Javascript
Python列表生成式与生成器操作示例
2018/08/01 Python
使用Python实现将list中的每一项的首字母大写
2019/06/11 Python
pandas计算最大连续间隔的方法
2019/07/04 Python
基于Django静态资源部署404的解决方法
2019/07/28 Python
Django admin禁用编辑链接和添加删除操作详解
2019/11/15 Python
Django+boostrap 美化admin后台的操作
2020/03/11 Python
python使用隐式循环快速求和的实现示例
2020/09/11 Python
浅谈html5与APP混合开发遇到的问题总结
2018/03/20 HTML / CSS
AE美国鹰日本官方网站: American Eagle Outfitters
2016/12/10 全球购物
瑜伽服装品牌:露露柠檬(lululemon athletica)
2017/06/04 全球购物
美国第二大连锁书店:Books-A-Million
2017/12/28 全球购物
Ajax请求总共有多少种Callback
2016/07/17 面试题
小学教师学期末自我评价
2013/09/25 职场文书
个人找工作的自我评价
2013/10/17 职场文书
美术专业个人自我评价
2014/01/18 职场文书
开会迟到检讨书
2014/02/03 职场文书
2014年感恩母亲演讲稿
2014/05/27 职场文书
欢迎新生标语
2014/10/06 职场文书
基于Redis延迟队列的实现代码
2021/05/13 Redis