Python爬虫进阶之爬取某视频并下载的实现


Posted in Python onDecember 08, 2020

这几天在家闲得无聊,意外的挖掘到了一个资源网站(你懂得),但是网速慢广告多下载不了种种原因让我突然萌生了爬虫的想法。

下面说说流程:

一、网站分析

首先进入网站,F12检查,本来以为这种低端网站很好爬取,是我太低估了web主。可以看到我刷新网页之后,出现了很多js文件,并且响应获取的代码与源代码不一样,这就不难猜到这个网站是动态加载页面。

Python爬虫进阶之爬取某视频并下载的实现

目前我知道的动态网页爬取的方法只有这两种:1、从网页响应中找到JS脚本返回的JSON数据;2、使用Selenium对网页进行模拟访问。源代码问题好解决,重要的是我获取的源代码中有没有我需要的东西。我再一次进入网站进行F12检查源代码,点击左上角然后在页面点击一个视频获取一个元素的代码,结果里面没有嵌入的原视频链接(看来我真的是把别人想的太笨了)。

Python爬虫进阶之爬取某视频并下载的实现

没办法只有进行抓包,去找js请求的接口。再一次F12打开网页调试工具,点击单独的一个视频进行播放,然后在Network中筛选一下,只看HXR响应(HXR全称是XMLHTTPRequest,HMLHTTP是AJAX网页开发技术的重要组成部分。除XML之外,XMLHTTP还能用于获取其它格式的数据,如JSON或者甚至纯文本。)。

Python爬虫进阶之爬取某视频并下载的实现

然后我一项一项的去检查返回的响应信息,发现当我点击播放的时候有后缀为.m3u8的链接,随后就不断刷新.ts文件的链接。

Python爬虫进阶之爬取某视频并下载的实现

本来以为这就是原视频的地址,我傻傻的直接从这个m3u8文件的headers中的URL直接进入网站看看,结果傻眼了,获取的是一串串.ts的文件名。

Python爬虫进阶之爬取某视频并下载的实现

没办法只能百度君了。 科普了一下,也就说我们必须把ts文件都下载下来进行合并之后才能转成视频。

Python爬虫进阶之爬取某视频并下载的实现

好了,视频原地址弄清楚了,现在我们开始从一个视频扩展到首页的整个页面的视频。再一次进行抓包分析,发现一个API中包含了首页的分类列表,然而里面并没有进入分类的URL地址,只有一个tagid值和图片的地址。

Python爬虫进阶之爬取某视频并下载的实现

于是我又在主页点一个分类,再次进行抓包,发现了一个API中包含了一个分类的单页所有视频的信息,通过他们的headers中的URL对比发现,关于视频的前一部分都是https:xxxxxxx&c=video,然后m=categories,通过字面意思我们都可以知道是分类,而每个tagid值对应不同的分类。并且还发现每个URL中都追加了时间戳timestamp(这是web主为了确保请求不会在它第一次被发送后即缓存,看来还是有小心机啊)。当m=lists,则是每个分类下的视频列表,这里面我们就可以找到每个视频对应的ID了。

Python爬虫进阶之爬取某视频并下载的实现

Python爬虫进阶之爬取某视频并下载的实现

Python爬虫进阶之爬取某视频并下载的实现

通过id我们可以获取到视频的详细信息,并且还有m3u8文件URL地址的后面一部分。

Python爬虫进阶之爬取某视频并下载的实现

好了,网站我们解析清楚了,现在开始堆码了。

二、写代码

导入相关模块

import requests
from datetime import datetime
import re
#import json 
import time
import os

#视频分类和视频列表URL的前一段
url = "http://xxxxxxx/api/?d=pc&c=video&"
#m3u8文件和ts文件的URL前一段
m3u8_url ='https://xxxxxxxxxxxxx/videos/cherry-prod/2020/03/01/2dda82de-5b31-11ea-b5ae-1c1b0da2bc3f/hls/480/'
#构造请求头信息
header = {"user-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2"}
#创建空列表存放视频信息
vediomassag=''
#返回当前时间戳
TimeStamp = int(datetime.timestamp(datetime.now()))

2.定义函数,获取网站首页分类列表信息

#自定义函数获取分类
def get_vediocategory(url, TimeStamp):
 cgURL = url + "m=categories×tamp=" + str(TimeStamp) + '&'
 response = requests.get(cgURL, headers=header)
 category = response.text
# strrr='"%s"'%category
# return strrr
 return category

3.定义函数,通过上一个函数返回的分类信息,根据分类对应的id,输入id并传输到当前URL中以便获取分类下的视频列表信息

#获取分类后的视频列表
def get_vedioList(url, TimeStamp, tagID):
 listURL = url + "m=lists×tamp=" + str(TimeStamp) + '&' + "page=1&tag_id=" + str(tagID) + "&sort_type=&is_vip=0"
 response = requests.get(listURL, headers=header)
 vedioLists = response.text
 return vedioLists

4.在视频列表信息中获取视频对应的id,获取单个视频详细信息的URL

#获取单个视频的详细信息
def get_vediomassages(url, TimeStamp, vedioID):
 videoURL = url + "m=detail×tamp=" + str(TimeStamp) + '&' + "&id=" + str(vedioID)
 response = requests.get(videoURL, headers=header)
 vediomassag = response.text
 return vediomassag

5.在视频详细信息中找到m3u8文件的下载地址,并将文件保存到创建的文件中

#将下载的m3u8文件放进创建的ts列表文件中
def get_m3u8List(m3u8_url,vediomassag):
 lasturl = r'"m3u8_720_url":"(.*?)","download_url'
 last_url =re.findall(lasturl,vediomassag)
 lastURL=m3u8_url+str(last_url)
 response = requests.get(lastURL, headers=header)
 tsList = response.text
 cur_path='E:\\files' #在指定路径建立文件夹
 try:
 	if not os.path.isdir(cur_path): #确认文件夹是否存在
 		os.makedirs(cur_path)  #不存在则新建
 except:
 	print("文件夹存在")
 filename=cur_path+'\\t2.txt' #在文件夹中存放txt文件
 f = open(filename,'a', encoding="utf-8")
 f.write(tsList)
 f.close
 print('创建%s文件成功'%(filename))
 return filename

6.将m3u8文件中的ts单个提取出来放进列表中。

# 提取ts列表文件的内容,逐个拼接ts的url,形成list
def get_tsList(filename):
 ls = []
 with open(filename, "r") as file:
  line = f.readlines()
  for line in lines:
   if line.endswith(".ts\n"):
    ls.append(line[:-1])
 return ls

7.遍历列表获取单个ts地址,请求下载ts文件放进创建的文件夹中

# 批量下载ts文件
def DownloadTs(ls):
 length = len(ls)
 root='E:\\mp4'
 try:
  if not os.path.exists(root):
   os.mkdir(root)
 except:
  print("文件夹创建失败")
 try:
  for i in range(length):
   tsname = ls[i][:-3]
   ts_URL=url+ls[i]
   print(ts_URL)
   r = requests.get(ts_URL)
   with open(root, 'a') as f:
    f.write(r.content)
    f.close()
    print('\r' + tsname + " -->OK ({}/{}){:.2f}%".format(i, length, i * 100 / length), end='')
  print("下载完毕")
 except:
  print("下载失败")

代码整合

import requests
from datetime import datetime
import re
#import json
import time
import os


url = "http://xxxxxxxx/api/?d=pc&c=video&"
m3u8_url ='https://xxxxxxxxxxxxxxx/videos/cherry-prod/2020/03/01/2dda82de-5b31-11ea-b5ae-1c1b0da2bc3f/hls/480/'
header = {"user-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2"}
vediomassag=''
TimeStamp = int(datetime.timestamp(datetime.now()))



#自定义函数获取分类
def get_vediocategory(url, TimeStamp):
 cgURL = url + "m=categories×tamp=" + str(TimeStamp) + '&'
 response = requests.get(cgURL, headers=header)
 category = response.text
# strrr='"%s"'%category
# return strrr
 return category

#获取分类后的视频列表
def get_vedioList(url, TimeStamp, tagID):
 listURL = url + "m=lists×tamp=" + str(TimeStamp) + '&' + "page=1&tag_id=" + str(tagID) + "&sort_type=&is_vip=0"
 response = requests.get(listURL, headers=header)
 vedioLists = response.text
 return vedioLists

#获取单个视频的详细信息
def get_vediomassages(url, TimeStamp, vedioID):
 videoURL = url + "m=detail×tamp=" + str(TimeStamp) + '&' + "&id=" + str(vedioID)
 response = requests.get(videoURL, headers=header)
 vediomassag = response.text
 return vediomassag

#将下载的m3u8文件放进创建的ts列表文件中
def get_m3u8List(m3u8_url,vediomassag):
 lasturl = r'"m3u8_720_url":"(.*?)","download_url'
 last_url =re.findall(lasturl,vediomassag)
 lastURL=m3u8_url+str(last_url)
 response = requests.get(lastURL, headers=header)
 tsList = response.text
 cur_path='E:\\files' #在指定路径建立文件夹
 try:
 	if not os.path.isdir(cur_path): #确认文件夹是否存在
 		os.makedirs(cur_path)  #不存在则新建
 except:
 	print("文件夹存在")
 filename=cur_path+'\\t2.txt' #在文件夹中存放txt文件
 f = open(filename,'a', encoding="utf-8")
 f.write(tsList)
 f.close
 print('创建%s文件成功'%(filename))
 return filename

# 提取ts列表文件的内容,逐个拼接ts的url,形成list
def get_tsList(filename):
 ls = []
 with open(filename, "r") as file:
  line = f.readlines()
  for line in lines:
   if line.endswith(".ts\n"):
    ls.append(line[:-1])
 return ls


# 批量下载ts文件
def DownloadTs(ls):
 length = len(ls)
 root='E:\\mp4'
 try:
  if not os.path.exists(root):
   os.mkdir(root)
 except:
  print("文件夹创建失败")
 try:
  for i in range(length):
   tsname = ls[i][:-3]
   ts_URL=url+ls[i]
   print(ts_URL)
   r = requests.get(ts_URL)
   with open(root, 'a') as f:
    f.write(r.content)
    f.close()
    print('\r' + tsname + " -->OK ({}/{}){:.2f}%".format(i, length, i * 100 / length), end='')
  print("下载完毕")
 except:
  print("下载失败")


'''# 整合所有ts文件,保存为mp4格式(此处函数复制而来未做实验,本人直接在根目录
命令行输入copy/b*.ts 文件名.mp4,意思是将所有ts文件合并转换成自己命名的MP4格式
文件。)
def MergeMp4():
 print("开始合并")
 path = "E://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("结束合并")'''
 
if __name__ == '__main__':
# 将获取的分类信息解码显示出来
# print(json.loads(get_vediocategory(url, TimeStamp)))
 print(get_vediocategory(url, TimeStamp))
 tagID = input("请输入分类对应的id")
 print(get_vedioList(url, TimeStamp, tagID))
 vedioID = input("请输入视频对应的id")
 get_vediomassages(url, TimeStamp, vedioID)
 get_m3u8List(m3u8_url,vediomassag)
 get_tsList(filename)
 DownloadTs(ls)
# MergeMp4()

此时正在下载

Python爬虫进阶之爬取某视频并下载的实现

三、问题:

首先对于这种网站采取的爬取方法有很多,而我的方法相对来说有点太低端了,并且我也 是第一次写博客,第一次写爬虫这类程序,在格式上命名上存在着很多问题,函数的用法不全面。并且在运行的时候效率低速度太慢。在获取分类列表和视频列表时,因为是JSON文件,需要转码,过程太多加上程序不够稳定我就注释掉了。还有就是对于这种动态网页了解不够,所以学爬虫的小伙伴一定要把网页的基础搞好。希望各位大佬多指正多批评,让我们这些小白一起努力学好Python。

注意:里面所有的链接我的给打码了,怕被和谐了哈哈

到此这篇关于Python爬虫进阶之爬取某视频并下载的实现的文章就介绍到这了,更多相关Python 爬取某视频并下载内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python检查序列seq是否含有aset中项的方法
Jun 30 Python
python数据结构之图深度优先和广度优先实例详解
Jul 08 Python
使用Python读写及压缩和解压缩文件的示例
Jul 08 Python
利用python批量给云主机配置安全组的方法教程
Jun 21 Python
Python实现的人工神经网络算法示例【基于反向传播算法】
Nov 11 Python
python3安装pip3(install pip3 for python 3.x)
Apr 03 Python
Window系统下Python如何安装OpenCV库
Mar 05 Python
Keras实现DenseNet结构操作
Jul 06 Python
Python如何定义有默认参数的函数
Aug 10 Python
通过实例解析python subprocess模块原理及用法
Oct 10 Python
python中pop()函数的语法与实例
Dec 01 Python
pymongo insert_many 批量插入的实例
Dec 05 Python
selenium框架中driver.close()和driver.quit()关闭浏览器
Dec 08 #Python
Python hashlib和hmac模块使用方法解析
Dec 08 #Python
Python虚拟环境virtualenv创建及使用过程图解
Dec 08 #Python
Selenium执行完毕未关闭chromedriver/geckodriver进程的解决办法(java版+python版)
Dec 07 #Python
python 实现数据库中数据添加、查询与更新的示例代码
Dec 07 #Python
python 爬取小说并下载的示例
Dec 07 #Python
Python常用GUI框架原理解析汇总
Dec 07 #Python
You might like
php foreach 使用&(与运算符)引用赋值要注意的问题
2010/02/16 PHP
php数组(array)输出的三种形式详解
2013/06/05 PHP
为你总结一些php信息函数
2015/10/21 PHP
PHP中session跨子域的三种实现方法
2016/07/25 PHP
PHP基于socket实现客户端和服务端通讯功能
2017/07/13 PHP
PHP时间相关常用函数用法示例
2020/06/03 PHP
HR vs ForZe BO3 第二场 2.13
2021/03/10 DOTA
跨浏览器开发经验总结(三)   警惕“IE依赖综合症”
2010/05/13 Javascript
解析使用js判断只能输入数字、字母等验证的方法(总结)
2013/05/14 Javascript
javascript版的in_array函数(判断数组中是否存在特定值)
2014/05/09 Javascript
jquery text()方法取标签中的文本
2014/07/25 Javascript
深入浅析react native es6语法
2015/12/09 Javascript
基于jQuery实现鼠标点击导航菜单水波动画效果附源码下载
2016/01/06 Javascript
使用angularjs.foreach时return的问题解决
2018/09/30 Javascript
react+ant design实现Table的增、删、改的示例代码
2018/12/27 Javascript
vue input标签通用指令校验的实现
2019/11/05 Javascript
微信小程序中的上拉、下拉菜单功能
2020/03/13 Javascript
vue 解决无法对未定义的值,空值或基元值设置反应属性报错问题
2020/07/31 Javascript
[01:14]TI珍贵瞬间系列(六):冠军
2020/08/30 DOTA
总结网络IO模型与select模型的Python实例讲解
2016/06/27 Python
使用python绘制常用的图表
2016/08/27 Python
Python自定义函数定义,参数,调用代码解析
2017/12/27 Python
Python读取word文本操作详解
2018/01/22 Python
python线程中同步锁详解
2018/04/27 Python
python3使用QQ邮箱发送邮件
2020/05/20 Python
Python3.6 + TensorFlow 安装配置图文教程(Windows 64 bit)
2020/02/24 Python
CSS3 border-image详解、应用及jQuery插件
2011/08/29 HTML / CSS
HTML5对手机页面长按会粘贴复制禁用的解决方法
2016/07/19 HTML / CSS
带你认识HTML5中的WebSocket
2015/05/22 HTML / CSS
JD Sports比利时官网:英国领先的运动鞋和运动服饰零售商
2018/10/10 全球购物
AJAX的优缺点都有什么
2015/08/18 面试题
金融专业大学生职业生涯规划范文
2014/01/16 职场文书
2014年党务公开实施方案
2014/02/27 职场文书
爱国主义演讲稿
2014/05/07 职场文书
我们的节日国庆活动方案
2014/08/19 职场文书
MySQL基础(一)
2021/04/05 MySQL