手机网页抓取视频(用Python爬取网页视频(HD)去爬取视频资源)

优采云 发布时间: 2021-09-11 16:04

  手机网页抓取视频(用Python爬取网页视频(HD)去爬取视频资源)

  记录:使用Python抓取网络视频

  相关:python、请求爬虫、m3u8文件、合成ts

  前几天刚自学了python爬虫,萌生了一个想法:爬取网络上的视频资源。所以就去做吧!

  但是因为我只学python的基本语法,对视频格式不是很了解,所以弄了两个晚上(week四、五后班后),今天正好是星期六,所以记录下两晚的结果吧!

  一、获取网页的HTML代码

  当然很简单

  requests.get(url).text

  将他保存为txt文件,方便操作

  我们打开文件,用ctl+f搜索,发现没有所谓的mp4或者其他可以直接下载播放的文件链接(根据网站当然,如果有mp4链接,情况简单10000倍,下面你就不用看了)

  我们可以找到m3u8的字符串

  

  这里有五个 .m3u8 链接。我猜是因为网站有5条播放线,所以我们自然选择第一条线(高清)来抓取视频资源!

  二、处理m3u8文件

  关于 m3u8

  m3u8是苹果推出的视频播放标准,是m3u的一种,但是编码方式是utf-8,是一种文件检索格式。将视频剪成小段ts格式的视频文件,然后存储在服务器中(现在为了减少I/O访问次数,一般存储在服务器的内存中),路径通过m3u8解析,然后发出请求。

  1.

  HD%u9ad8%u6e05%24https%3A%2F%2Fyouku.com-l-youku.com%2F20190207%2F20335_d1f19bfb%2Findex.m3u8

  这个链接根本打不开。我研究了一下,发现链接前面有mac_url=unescape(,意思是下面的链接需要解码才能使用。我查了这个解码方法:

  s2 = unescape (s1)

  规则:

  所有以 %xx 十六进制形式编码的字符都替换为 ASCII 字符集中的等效字符。

  %uxxxx 格式编码的字符(Unicode 字符)替换为十六进制编码 xxxx 的 Unicode 字符。

  由此,我们可以解码这个字符串:

  前面的“HD%u9ad8%u6e05%24”代表“HD HD$”,不是链接的一部分,可以忽略。

  # 字符(十六进制)转ASCII码

def hexToAscii(h):

d = int(h,16) # 转成十进制

return chr(d) # 转成ASCII码

# 从得到的html代码中获取m3u8链接(不同网站有区别)

def getM3u8(http_s):

ret1 = http_s.find("unescape")

ret2 = http_s.find(".m3u8")

ret3 = http_s.find("http", ret1, ret2) # "unescape"和".m3u8"之间找"http"

m3u8_url_1 = http_s[ret3: ret2 + 5] # 未解码的m3u8链接

# 下面对链接进行解码

while True:

idx = m3u8_url_1.find('%')

if idx != -1:

m3u8_url_1 = m3u8_url_1.replace(m3u8_url_1[idx:idx+3], \

hexToAscii(m3u8_url_1[idx+1:idx+3]))

else:

break

return m3u8_url_1

  不错

  所以我们得到了m3u8的链接

  网上也有在线解码网站,我们可以测试一下

  

  是不是一模一样! ! !

  另外,我们可以使用在线m3u8在线播放测试网站进行测试,可以直接播放! !这将表明链接是正确的

  

  2.

  好的,那么让我们看看这个链接里有什么?直接进入浏览器,它会让你下载一个.m3u8文件,下载后用notepad++打开。

  

  #EXTM3U

#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=800000,RESOLUTION=1080x608

1000k/hls/index.m3u8

  所以,这是什么鬼? ? ?

  事实证明,

  m3u8 链接是分层的(我是这么理解的),所以需要解析。最后一行的1000k/hls/index.m3u8其实是为了获取二级KEY。即用它来代替之前解析过的链接的最后一个“index.m3u8”,形成一个新的链接。

  # 寻找字符串s中最后出现字符c的index

def findLastchr(s, c):

ls = []

sum = 0

while True:

i = s.find(c)

if i != -1:

s = s[i+1:]

ls.append(i)

else:

break

for i in range(len(ls)):

sum += (ls[i] + 1)

return sum - 1

def getM3u8_2(m3u8_url_1):

r1 = requests.get(m3u8_url_1)

r1.raise_for_status()

text = r1.text

idx = findLastchr(text, '\n')

key = text[idx + 1:] # 得到第一层m3u8中的key

idx = findLastchr(m3u8_url_1, '/')

m3u8_url_2 = m3u8_url_1[:idx + 1] + key # 组成第二层的m3u8链接

return m3u8_url_2

  好的,接下来我们在浏览器中打开这个链接,我们会下载另一个.m3u8文件,打开记事本就可以看到

  

  我们看到了什么

  284e2012ca2000000.ts 等...

  当然要替换二级m3u8链接后面的index.m3u8,也就是ts链接。

  例如

  ts 文件将按顺序编号

  例如,这里我从 284e2012ca2000000.ts 到 284e2012ca2001806.ts

  以上是直接用浏览器下载,这里我们使用python程序自动完成(会调用之前定义的函数)

  # 从最原始的url-->生成一个ts列表的文件

def getTsFile(url, filename):

try:

r = requests.get(url)

r.encoding = "utf-8"

r.raise_for_status()

http_s = r.text

m3u8_url_1 = getM3u8(http_s)

print("第一层m3u8链接" + m3u8_url_1)

m3u8_url_2 = getM3u8_2(m3u8_url_1)

print("第二层m3u8链接" + m3u8_url_2)

# 通过新的m3u8链接,获取真正的ts播放列表

# 由于列表比较长,为他创建一个txt文件

r2 = requests.get(m3u8_url_2)

f = open(filename, "w", encoding="utf-8") # 这里要改成utf-8编码,不然默认gbk

f.write(r2.text)

f.close()

print("创建ts列表文件成功")

return "success"

except:

print("爬取失败")

return "failed"

  ts 文件处理1.

  毕竟这些链接太多了,用链表管理更方便,以后批量下载可以用索引循环

  两步:

  1. 提取ts列表文件内容,将ts的url一一拼接成列表

  2.批量下载ts文件

  # 提取ts列表文件的内容,逐个拼接ts的url,形成list

def getPlayList(filename, m3u8_url_2):

ls = []

f = open(filename, "r")

line = " " # line不能为空,不然进不去下面的循环

idx = findLastchr(m3u8_url_2, '/')

while line:

line = f.readline()

if line != '' and line[0] != '#':

line = m3u8_url_2[:idx+1] + line

ls.append(line[:-1]) # 去掉'\n'

return ls

# 批量下载ts文件

def loadTs(ls):

root = "D://mp4//"

length = len(ls)

try:

if not os.path.exists(root):

os.mkdir(root)

for i in range(length):

tsname = ls[i][-7:]

path = root + tsname

r = requests.get(ls[i])

with open(path, 'wb') as f:

f.write(r.content)

f.close()

print('\r' + tsname + " -->OK ({}/{}){:.2f}%".format(i, length, i*100/length), end='')

print("全部ts下载完毕")

except:

print("批量下载失败")

  我这里用的是D:\mp4路径,当然也可以改

  注意:下载生成ts文件时,命名一定要规范,

  如:0000.ts 0001.ts 0002.ts…… 1806.ts

  没有1.ts 2.ts 3.ts…… 1806.ts

  因为下面的合并是根据字符匹配的

  2.

  接下来我们将ts合并成mp4

  其实就是调用windows的命令

  复制/b *.ts new.mp4

  直接放代码

  # 整合所有ts文件,保存为mp4格式

def tsToMp4():

print("开始合并...")

root = "D://mp4//"

outdir = "output"

os.chdir(root)

if not os.path.exists(outdir):

os.mkdir(outdir)

os.system("copy /b *.ts new.mp4")

os.system("move new.mp4 {}".format(outdir))

print("结束合并...")

  好的

  就是这样! !

  

  

  这里不给出main函数。我所有源代码的链接如下:

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线