Python爬虫爬取ts碎片视频+验证码登录功能


Posted in Python onFebruary 22, 2021

目标:爬取自己账号中购买的课程视频。

一、实现登录账号

这里采用的是手动输入验证码的方式,有能力的盆友也可以通过图像识别的方式自动填写验证码。登录后,采用session保持登录。

1.获取验证码地址                                                                               

第一步:首先查看验证码对应的代码,可以从图中看到验证码图片的地址是:https://per.enetedu.com/Common/CreateImage?tmep_seq=1613623257608

颜色标红的部分tmep_seq=1613623257608,是为了解决浏览器缓存问题加的时间戳,因此真正的验证码图片地址是:https://per.enetedu.com/Common/CreateImage

Python爬虫爬取ts碎片视频+验证码登录功能

第二步:找出登录时提交的表单内容和POST地址。

(1) 不填写用户名密码和验证码,直接点击登录,使用Chrome浏览器的Network检查,找到POST地址:https://per.enetedu.com/AdminIndex/LoginDo

Python爬虫爬取ts碎片视频+验证码登录功能

(2) 继续向下看,找到提交的表单 Form Data。

Python爬虫爬取ts碎片视频+验证码登录功能

因此带有验证码的登录代码如下:

import requests
from PIL import Image
 
#用户名-密码-验证码方式,登录
CaptchaUrl = "https://per.enetedu.com/Common/CreateImage" #获取验证码地址
PostUrl = "https://per.enetedu.com/AdminIndex/LoginDo"  #post登录信息地址
 
client = requests.Session()
username = '替换为自己的用户名'
password = '替换为自己的密码'
 
qr_code = client.get(CaptchaUrl)
open('login.jpg', 'wb').write(qr_code.content) #将验证码图片保存至本地
img = Image.open('login.jpg')
img.show()  #打开图片
 
code = input("请输入验证码: \n") #输入验证码
postData = {      #构造POST表单
 'email': username,
 'pwd': password,
 'validateCode': code,
 'x': '22',
 'y': '19'
}
result = client.post(PostUrl,postData) #向PostUrl提交表单

二、实现ts碎片视频下载,并转换为mp4格式

1.分析视频下载地址

登录成功后,检查视频播放div对应的代码,企图找到视频地址直接保存至本地。结果,如下图所示,整个视频是被分割成一段一段的.ts文件,分段加载到页面中播放。GET每段视频的地址为右侧红框圈起来的部分。

Python爬虫爬取ts碎片视频+验证码登录功能

百度后才知道,整个视频如何分段是由一个m3u8文件来决定的。m3u8文件中的内容如下所示,记录了每段视频start和end的编号。

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:10
#EXTINF:10.000000,
start_0-end_765064-record.gv.ts
#EXTINF:10.000000,
start_765064-end_1769567-record.gv.ts
#EXTINF:10.000000,
start_1769567-end_2600798-record.gv.ts
#EXTINF:10.000000,
start_2600798-end_3593502-record.gv.ts
#EXTINF:10.000000,
start_3593502-end_4500784-record.gv.ts
#EXTINF:10.000000,
start_4500784-end_5399861-record.gv.ts
#EXTINF:10.000000,
start_5399861-end_6288622-record.gv.ts
#EXTINF:10.000000,
start_6288622-end_7044459-record.gv.ts
#EXTINF:10.000000,
start_7044459-end_7878487-record.gv.ts
#EXTINF:10.000000,
start_7878487-end_8811793-record.gv.ts
#EXTINF:10.000000,

因此,下载视频的关键是获取m3u8文件,通过这个视频的m3u8文件来分段下载视频。

我是人工找出m3u8的下载地址,暂时还没研究出来怎么通过视频地址自动解析出m3u8地址。找的方法很简单,还是在Chrome的Network控制台找。打开Network控制台,刷新页面,就可以找到如图所示的m3u8文件。查看m3u8文件的相关信息,可以看到红框圈起来的地址就是这个视频的m3u8下载地址。

Python爬虫爬取ts碎片视频+验证码登录功能

对比两个地址,可以发现文件名前的地址相同,视频下载地址即为"标红地址"+"m3u8文件中列出的视频段文件名":

https://bcdn.enetedu.com/conv/cdnfile/video/2016_06_27/1467034852884_f5821b/hi/record.m3u8

https://bcdn.enetedu.com/conv/cdnfile/video/2016_06_27/1467034852884_f5821b/hi/start_643887-end_1083181-record.gv.ts

因此可以将这部分地址设为:urlroot = https://bcdn.enetedu.com/conv/cdnfile/video/2016_06_27/1467034852884_f5821b/hi

为了方便下载其他视频时动态修改,改为动态截取:

url = input("请输入m3u8文件地址:")
urlRoot=self.url[0:url.rindex('/')]

2.批量下载ts视频片段

这一步使用上一步拼接的地址循环下载ts视频即可。下载时,使用登录时创建的session下载。

session是会话的意思,它可以让服务器“认得”客户端。简单理解就是,把每一个客户端和服务器的互动当作一个“会话”。既然在同一个“会话”里,服务器自然就能知道这个客户端是否登录过。代码如下:

client = requests.Session() 
client.post(PostUrl,postData) #登录
 
resp = client.get(download_path) #下载

碎片拼接的方法:下载完第一个ts片段后,直接在该文件后面继续写第二个ts片段,以此类推。而不是新建一个文件写入。与验证码登录结合起来,完整代码如下:

import requests
from PIL import Image
 
import sys
import m3u8
import time
import os
 
#用户名-密码-验证码方式,登录
CaptchaUrl = "https://per.enetedu.com/Common/CreateImage" #获取验证码地址
PostUrl = "https://per.enetedu.com/AdminIndex/LoginDo"  #post登录信息地址
 
client = requests.Session()
username = '526257482@qq.com'
password = 'dashuju_9514'
 
qr_code = client.get(CaptchaUrl)
open('login.jpg', 'wb').write(qr_code.content) #将验证码图片保存至本地
img = Image.open('login.jpg')
img.show()  #打开图片
 
code = input("请输入验证码: \n") #输入验证码
postData = { #构造POST表单
 'email': username,
 'pwd': password,
 'validateCode': code,
 'x': '56',
 'y': '19'
}
result = client.post(PostUrl,postData) #向PostUrl提交表单
 
#循环下载ts视频
class VideoCrawler():
 
 def __init__(self,url):
 
  super(VideoCrawler, self).__init__()
  self.url=url
  self.final_path=r"D:\Download\Film"
  
 
 #下载并解析m3u8文件
 def get_url_from_m3u8(self,readAdr):
  print("正在解析真实下载地址...")
  with open('temp.m3u8','wb') as file:
   file.write(requests.get(readAdr).content)
  m3u8Obj=m3u8.load('temp.m3u8')
  print("解析完成")
  return m3u8Obj.segments
 
 def run(self):
  print("Start!")
  start_time=time.time()
  realAdr = self.url #m3u8下载地址
  urlList=self.get_url_from_m3u8(realAdr) #解析m3u8文件,获取下载地址
  urlRoot=self.url[0:self.url.rindex('/')]
  i=1
  outputfile=open(os.path.join(self.final_path,'%s.ts'%self.fileName),'wb')#初始创建一个ts文件,之后每次循环将ts片段的文件流写入此文件中从而不需要在去合并ts文件
  
 
  for url in urlList:
   try:    
    download_path = "%s/%s" % (urlRoot, url.uri) #拼接地址
    resp = client.get(download_path) #使用拼接地址去爬取数据
    progess = i/len(urlList)#记录当前的爬取进度
    outputfile.write(resp.content) #将爬取到ts片段的文件流写入刚开始创建的ts文件中
    sys.stdout.write('\r正在下载:{},进度:{:.2%}'.format(self.fileName,progess))#通过百分比显示下载进度
    sys.stdout.flush()#通过此方法将上一行代码刷新,控制台只保留一行
   except Exception as e:
    print("\n出现错误:%s",e.args)
    continue#出现错误跳出当前循环,继续下次循环
   i+=1
  outputfile.close()
  print("下载完成!总共耗时%d s"%(time.time()-start_time))
  print("开始转换视频格式!")
  success = os.system(r'copy /b D:\Download\Film\{0}.ts D:\Download\Film\{0}.mp4'.format(self.fileName)) #ts转成mp4格式
  if (not success):
   print("格式转换成功!")
   os.remove(self.final_path+'\\'+self.fileName+".ts") #删除ts和m3u8临时文件
   os.remove("temp.m3u8")
 
if __name__=='__main__':
 m3u8_addr = input("输入m3u8文件下载地址:\n") 
 crawler=VideoCrawler(m3u8_addr)
 crawler.fileName = input("输入文件名:\n")
 crawler.run()
 quitClick=input("请按Enter键确认退出!")

三、总结

代码可以实现分段加载视频的爬取功能,其中还有很多细节待完善如:

  • 验证码可以通过图像识别的方法自动识别。
  • 通过解析视频地址获取m3u8文件,非计算机专业人使用起来更加友好。
  • 例子中的网站没有对m3u8文件进行加密,涉及到加密的m3u8还需要加一步解密的过程。

到此这篇关于Python爬虫爬取ts碎片视频+验证码登录功能的文章就介绍到这了,更多相关Python爬虫爬取视频内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
用Python和MD5实现网站挂马检测程序
Mar 13 Python
Python最基本的数据类型以及对元组的介绍
Apr 14 Python
Python读取Excel的方法实例分析
Jul 11 Python
python类中super()和__init__()的区别
Oct 18 Python
python编程嵌套函数实例代码
Feb 11 Python
在python中利用GDAL对tif文件进行读写的方法
Nov 29 Python
python 定时器每天就执行一次的实现代码
Aug 14 Python
Windows10下 python3.7 安装 facenet的教程
Sep 10 Python
Python Numpy 自然数填充数组的实现
Nov 28 Python
jupyter 中文乱码设置编码格式 避免控制台输出的解决
Apr 20 Python
使用python实现学生信息管理系统
Feb 25 Python
5个pandas调用函数的方法让数据处理更加灵活自如
Apr 24 Python
sklearn中的交叉验证的实现(Cross-Validation)
Feb 22 #Python
Python爬虫分析微博热搜关键词的实现代码
Feb 22 #Python
anaconda升级sklearn版本的实现方法
Feb 22 #Python
详解Python 中的 defaultdict 数据类型
Feb 22 #Python
python快速安装OpenCV的步骤记录
Feb 22 #Python
Python中生成ndarray实例讲解
Feb 22 #Python
python爬虫利用代理池更换IP的方法步骤
Feb 21 #Python
You might like
PHP开发大型项目的一点经验
2006/10/09 PHP
php使用pdo连接mssql server数据库实例
2014/12/25 PHP
PHP中创建和验证哈希的简单方法实探
2015/07/06 PHP
Zend Framework上传文件重命名的实现方法
2016/11/25 PHP
thinkPHP框架实现图像裁剪、缩放、加水印的方法
2017/03/14 PHP
laravel 之 Eloquent 模型修改器和序列化示例
2019/10/17 PHP
基于JQuery实现相同内容合并单元格的代码
2011/01/12 Javascript
JavaScript去掉数组中的重复元素
2011/01/13 Javascript
jQuery截取指定长度字符串的实现原理及代码
2014/07/01 Javascript
jQuery用FormData实现文件上传的方法
2016/11/21 Javascript
详解Vue方法与事件
2017/03/09 Javascript
jQuery插件FusionCharts绘制2D柱状图和折线图的组合图效果示例【附demo源码】
2017/04/10 jQuery
JS 调试中常见的报错问题解决方法
2017/05/20 Javascript
jquery 输入框查找关键字并提亮颜色的实例代码
2018/01/23 jQuery
AngularJs返回前一页面时刷新一次前面页面的方法
2018/10/09 Javascript
如何在微信小程序中实现Mixins方案
2019/06/20 Javascript
layer.alert回调函数执行关闭弹窗的实例
2019/09/11 Javascript
微信小程序搜索框样式并实现跳转到搜索页面(小程序搜索功能)
2020/03/10 Javascript
[02:30]DOTA2放量测试专访海涛:呼吁保护新手玩家
2013/08/26 DOTA
python实现向ppt文件里插入新幻灯片页面的方法
2015/04/28 Python
简单谈谈Python中的几种常见的数据类型
2017/02/10 Python
Python求出0~100以内的所有素数
2018/01/23 Python
Opencv图像处理:如何判断图片里某个颜色值占的比例
2020/06/03 Python
Python 打印自己设计的字体的实例讲解
2021/01/04 Python
基于HTML5 WebGL的3D机房的示例
2018/03/16 HTML / CSS
关于HTML5+ API plusready的兼容问题
2020/11/20 HTML / CSS
马来西亚网上购物:Youbeli
2018/03/30 全球购物
STP的判定过程
2012/10/01 面试题
电脑教师的自我评价
2013/12/18 职场文书
大学生就业指导课心得体会
2016/01/15 职场文书
导游词之崇武古城
2019/10/07 职场文书
Python中Selenium对Cookie的操作方法
2021/07/09 Python
SpringDataJPA在Entity中常用的注解介绍
2021/12/06 Java/Android
CentOS7安装GlusterFS集群以及相关配置
2022/04/12 Servers
收音机爱好者玩机13年,简评其使用过的19台收音机
2022/04/30 无线电
win10+RTX3050ti+TensorFlow+cudn+cudnn配置深度学习环境的方法
2022/06/25 Servers