热搜词
发表于 2022-10-22 11:18:17 | 显示全部楼层 |阅读模式
前言
为求实用,提高以后用python下载视频资料的效率,增强下载视频相关知识点在脑海里的可得性,特此记录
此文章会不定时更新,完善

下载视频
方法一----->you-get
下载与使用
使用
优点
可在终端(cmd)执行,一行代码就是快
下载音乐,短视频极其便捷
实测结果是30个视屏只有9个完整下来了,个中原因先按下不表

you-get https://v.youku.com/v_show/id_XMzk4NDE2Njc4OA==.html?firsttime=0

1
2
必要依赖
ffmpeg
用于视频音频合成
指令

选项        说明        是否使用过
-i        显示资源信息,比如说格式、清晰度、大小等        √
-u        指定下载或查看的url,有时候可以省略-u直接加上url       
-o        设置输出文件夹,即保存路径,若不指定,则保存在当前工作目录        √
-O        设置文件名,可采用默认文件名        √
-f        强制覆盖已存在的文件       
-l        优先下载整个列表       
-P        使用密码(若访问视频需要密码)       
-t        设置超时时间,单位是秒       
-c        使用cookie,加载cookies.txt 或者cookies.sqlite       
缺点
可支持平台有限,但不少,主要有b站,优酷视频,豆瓣,网易云,爱奇艺,酷狗
小结
you-get实用、小巧、实用性强,以最小的时间成本获取视频。但功能单一,可操作空间不高,用作一般性的视频下载工具很适合,爬取电影类的视频文件不适合

方法二------->you-get加pycharm
方向
利用you-get的
便捷可制作简单使用用户交互界面程序
也可进一步代码编写重复下载特定目标

方法三------->代码实现
下视频
url
url都知道是资源地址,但一个视屏的url有很多模样,它们有着不同的意义。关于url详解请见这里
以.mp4为结尾的url

http://ggkkmuup9wuugp6ep8d.exp.b ... m671xd58s1yy16y.mp4
1
这是一个典型例子,它包含了协议名、域名、虚拟目录然后还有.mp4,

得到这样的链接可以就直接下载了

先点开这个链接看看是不是能直接播放,结果显示这样

然后用以下两个方法
法一:

import requests
headers = {  # 模拟浏览器身份头向对方发送消息
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
    }
url = "http://ggkkmuup9wuugp6ep8d.exp.bcevod.com/mda-km671xd58s1yy16y/mda-km671xd58s1yy16y.mp4“
content = requests.get(url,headers=headers).content
with open("D:/base/%s.mp4"%i,"ab") as fp:
     fp.write(content)
     print("正在下载s")
1
2
3
4
5
6
7
8
9
法二:

open('D:/base/test.mp4', "wb") as mp4:
    for chunk in r.iter_content(chunk_size=1024 * 1024):
        if chunk:
            mp4.write(chunk)
1
2
3
4
法二中涉及的相关知识先按下不表
!!!header加Referer!!!

非以.mp4为结尾的url

一般情况没那么容易直接得到.mp4url,

找url的两个方向之一-----elements

查看源码,url就在层层代码下面,上文例子中的mp4url就是藏在两层页面下的某个标签的src。秘诀是先看一眼源代码页面,如果入眼结构清晰明了,那么多半不复杂。回到视频播放页面,借助右键检查仔细排查标签就可以了

但如果查看源代码页面后发现有很多看不懂的长长的段落,特别是有很多大括号,或者js样式的,总之能一眼看到不对劲的网页,这种情况就不是能通过元素查找找出来的。它需要一些手段如selelnium,抓包技术(数据包)

找url的两个方向之一-----network

这个方向就有点像刚才提到的抓包技术,不过真正使用抓包是要借助专业工具的。这里先介绍用浏览器自带的抓包功能来找我们的url。即右键检查,点击network,找到数据流,挨个检查查找对我们有用的信息,这个方法主要针对动态网页。

找url的两个方向本质上都是一样,都是从数据中筛选有用的信息

一开始是要找.mp4的url实现直接下载的,但很明显如果源代码网页很复杂那么.mp4的url就根本不会存在(存在也会被加密)

这种情况就换种思路,找接口(api)

接口(api)像是别的开发者写的一个封装函数,得到它加入某些参数,就能获得对应的内容。

以b站为例,它就有它的视频接口,找到这个接口,给他添加对应的参数就能得到指定的视频。不难看出,这个接口内一定包含了我们需要的url,不过这个url的格式肯定不是.mp4那么简单而且是可以添加参数,拼接而成的。另外,若是这样,就算得到这个拼接而成的url,能不能用上面提到的两种代码下载也未可知。

下面就以b站为例,查找使用它的接口
找到接口

'https://api.bilibili.com/x/player/playurl?' + 'bvid=' + bvid +'&cid=' + str(cid) + '&qn=64&type=&otype=json'
1
或者代码实现找url(network中有的视频有playurl,有的没有,用正则找靠谱)
需要先用正则在目标网页源代码中找到包含视频直接url的json文件

pattern = r'\<script\>window\.__playinfo__=(.*?)\</script\>'
result = re.findall(pattern, html)[0]
1
2

然后解析json

temp = json.loads(result)
1
接着提取内容

video_url = temp['data']['dash']['video'][0]['baseUrl']
print(video_url)
1
2
这是打印结果

{'code': 0, 'message': '0', 'ttl': 1, 'data': {'from': 'local', 'result': 'suee', 'message': '', 'quality': 32, 'format': 'flv480', 'timelength': 8679, 'accept_format': 'flv720,flv480,mp4', 'accept_description': ['高清 720P', '清晰 480P', '流畅 360P'], 'accept_quality': [64, 32, 16], 'video_codecid': 7, 'seek_param': 'start', 'seek_type': 'offset', 'dash': {'duration': 9, 'minBufferTime': 1.5, 'min_buffer_time': 1.5, 'video': [{'id': 64, 'baseUrl': 'https://upos-sz-mirrorkodo.bilivideo.com/upgcxcode/43/29/288562943/288562943-1-30064.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEqxTEto8BTrNvN0GvT90W5JZMkX_YN0MvXg8gNEV4NC8xNEV4N03eN0B5tZlqNxTEto8BTrNvNeZVuJ10Kj_g2UB02J0mN0B5tZlqNCNEto8BTrNvNC7MTX502C8f2jmMQJ6mqF2fka1mqx6gqj0eN0B599M=&uipk=5&nbs=1&deadline=1613228680&gen=playurl&os=kodobv&oi=827278138&trid=3625ae10dddf49fc88c17490d5867c64u&platform=pc&upsig=1d6f8c7c311ba495bca7f2da3fe288f6&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform&mid=0&orderid=0,3&agrr=0&logo=80000000', 'base_url': 'https://upos-s
1
可以看到有base_url这样的链接出现,打开这样的链接发现无法访问,也不是.mp4但这个就是我们需要下载的的url
这个base_url也可以直接在net-work里直接找到

下载b站视频经验

得到base_url后如何使用它下载?
就差这临门一脚了
最后代码如下

import requests
url = "https://cn-jszj-dx-v-09.bilivideo.com/upgcxcode/18/28/287972818/287972818-1-30074.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEqxTEto8BTrNvN0GvT90W5JZMkX_YN0MvXg8gNEV4NC8xNEV4N03eN0B5tZlqNxTEto8BTrNvNeZVuJ10Kj_g2UB02J0mN0B5tZlqNCNEto8BTrNvNC7MTX502C8f2jmMQJ6mqF2fka1mqx6gqj0eN0B599M=&uipk=5&nbs=1&deadline=1613356156&gen=playurl&os=vcache&oi=827278138&trid=3f0f02d09e5a46e8943e7bb069e62f60u&platform=pc&upsig=343a85c8a72a750ba56c93eee4c28d63&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform&cdnid=8192&mid=410239695&orderid=0,3&agrr=0&logo=80000000"
headers = {  # 模拟浏览器身份头向对方发送消息
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
}
begin = 0
end = 1024 * 1024 - 1
flag = 0
headers.update({'Range': 'bytes=' + str(begin) + '-' + str(end)})
while True:
    # 添加请求头键值对,写上 range:请求字节范围
    headers.update({'Range': 'bytes=' + str(begin) + '-' + str(end)})
    res = requests.get(url=url, headers=headers)
    if res.status_code != 416:
        # 响应码不为416时有数据,由于我们不是b站服务器,最终那个数据包的请求range肯定会超出限度,所以传回来的http状态码是416而不是206
        begin = end + 1
        end = end + 1024 * 1024
    else:
        headers.update({'Range': str(end + 1) + '-'})
        res = requests.get(url=url, headers=headers)
        flag = 1
    with open("D:/base/a.mp4", 'ab') as fp:
        fp.write(res.content)
        fp.flush()
    if flag == 1:
        fp.close()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
最后一步不添加range字节范围是不会成功的
这个出现个大问题,我下载的只是m4s文件,而m4s文件需要一个视频文件和一个音频文件用合并才能完整观看………

还有一种思路是直接很据视频接口找到flv链接…………

b站接口是get请求
现在已经可以根据接口实现爬取指定bv号的单个或系列视频了

只要搞懂了爬取视频的本质就是找url或接口,那么做起来就是水到渠成了

需要注意的是
1.一个错误示范是这样的

import requests
headers = {  # 模拟浏览器身份头向对方发送消息
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
    }
for i in range(142):

    url = "https://www.bilibili.com/video/BV17o4y1976Q?p=%s"%i
    content = requests.get(url,headers=headers).content
    with open("D:/base/%s.mp4"%i,"ab") as fp:
        fp.write(content)
        print("正在下载%s"%i)
1
2
3
4
5
6
7
8
9
10
11
这里就把间接的url当做直接的url来使用了,结果当然会出错,下出来文件也是打不开的
改成

import requests
headers = {  # 模拟浏览器身份头向对方发送消息
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
    }

url = "http://ggkkmuup9wuugp6ep8d.exp.bcevod.com/mda-km671xd58s1yy16y/mda-km671xd58s1yy16y.mp4"
content = requests.get(url,headers=headers).content
with open("D:/base/s.mp4","ab") as fp:
    fp.write(content)
    print("正在下载s")
1
2
3
4
5
6
7
8
9
10
就可以下载成功了

2.加密的url

有时候一个视频右键就能复制它的地址(这个url通常毫无用处)

就像这个

blob:https://www.bilibili.com/62cc1137-e104-4360-a03f-b856bf1079ca
1
这个网址是经过加密的,详情见为什么视频链接地址是blob
而爬虫的需求则是要在网页数据里找到直接url的相对位置从而实现批量下载,
3.
找到接口后不要直接下载里面的url,要在头里添加range字节范围
4.
普通下载速度极慢
5.
断点续传

下电影之最简单的情况
以某电影网站为例
在network找到js文件,其名称末尾是有序排序没有反爬手段,可以直接循环下载(这就是找到直接的url下载,上文第一个错误案例就是与本案例的做法混淆了)
涉及到的原理也有上面提到的断点续传
在HTTP协议中,Content-Length用于描述HTTP消息实体的传输长度the transfer-length of the message-body。
几行代码就可以

import requests
from urllib3.exceptions import InsecureRequestWarning
from urllib3 import disable_warnings

disable_warnings(InsecureRequestWarning)  # https问题的报错

print("开始下载!")
for i in range(1712):
    url = "url%s.ts" % i
    ret = requests.get(url,verify=False).content
    with open( r"D:/base/白日夢想家4.mp4","ab") as f:
        f.write(ret)
        print("第%d个ts文件已写入"%i)
print("下载完毕!")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
优点
没啥优点,就是能下载这件事本身稍微让人开心一点
使用you-get不能下载电影,而这个方法至少能做到
缺点
上述寥寥代码下载速度极慢,使用线程池、多线程知识或许能提高速度(此项待办),否则没有实用性
小结
不是所有网站都这么好爬,很少能使用这个方法,就算能用
速度也很慢
就算你会提高速度方法
学这种方法本身也耗时间,可能大于你获取电影的意义
如果这两个问题都不是问题,比如学习多线程、线程池甚至代理 本来就是学爬虫应知应会的,获取电影对自己很重要本人有电影收集爱好的,那么可以尝试学习更多
ps:实用第一,目前我多线程等知识掌握不充分,也没有特别要爬取电影的需求,既然如此,不如选择去学习实用性更强而且可以跳过多线程学习的scapy,学会以scrapy框架下载文字图片视频,还有selenium,这样性价比会大于单纯为下载电影而学习的方向
个中逻辑还需要时间来清晰化

难一点的情况
js文件跟上面一个情况不一样,似乎是加密编码过的,略略查找没能解决,暂且搁置,日后补充

方法四----------->scrapy下载


另关于视频处理及其强大的软件
格式工厂
不必多言

总结
能用python下载视频或电影是我一直以来学习的动力之一,我希望这种方式能给我带来诸多益处,当然学习过程中逐渐发现这个目标在软件众多,网络发达的今天根本不算什么。随随便便都有很多种方法能替代python的功能,但这么想就局限了自己的视野。
————————————————
版权声明:本文为CSDN博主「丹尼尔•卡尼�」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_51598376/article/details/113778759

全部评论0
回复
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|Archiver|手机版|小黑屋|管理员之家 ( 苏ICP备2023053177号-2 )

GMT+8, 2024-12-23 00:29 , Processed in 0.160654 second(s), 22 queries .

Powered by Discuz! X3.5

Cpoyright © 2001-2024 Discuz! Team