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当中的数据类型和变量
Apr 25 Python
python实现mysql的单引号字符串过滤方法
Nov 14 Python
Python时间模块datetime、time、calendar的使用方法
Jan 13 Python
利用python模拟sql语句对员工表格进行增删改查
Jul 05 Python
Python基于回溯法子集树模板实现8皇后问题
Sep 01 Python
Python面向对象之静态属性、类方法与静态方法分析
Aug 24 Python
python一键去抖音视频水印工具
Sep 14 Python
解决django后台样式丢失,css资源加载失败的问题
Jun 11 Python
python异常触发及自定义异常类解析
Aug 06 Python
python实现将json多行数据传入到mysql中使用
Dec 31 Python
用python查找统一局域网下ip对应的mac地址
Jan 13 Python
Python爬虫实现selenium处理iframe作用域问题
Jan 27 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 进行手机 APP 开发(API 接口开发)
2014/08/11 PHP
PHP版本如何选择?应该使用哪个版本?
2015/05/13 PHP
Zend Framework基本页面布局分析
2016/03/19 PHP
php中关于长度计算容易混淆的问题分析
2016/05/27 PHP
Smarty模板常见的简单应用分析
2016/11/15 PHP
jQuery使用CSS()方法给指定元素同时设置多个样式
2015/03/26 Javascript
JavaScript DOM操作表格及样式
2015/04/13 Javascript
简单介绍jsonp 使用小结
2016/01/27 Javascript
Bootstrap基本插件学习笔记之模态对话框(16)
2016/12/08 Javascript
从零开始学习Node.js系列教程四:多页面实现数学运算的client端和server端示例
2017/04/13 Javascript
关于Angularjs中跨域设置白名单问题
2018/04/17 Javascript
vue组件之间通信方式实例总结【8种方式】
2019/02/22 Javascript
react同构实践之实现自己的同构模板
2019/03/13 Javascript
Vue 动态路由的实现及 Springsecurity 按钮级别的权限控制
2019/09/05 Javascript
微信小程序跳转到其他网页(外部链接)的实现方法
2019/09/20 Javascript
mpvue 页面预加载新增preLoad生命周期的两种方式
2019/10/17 Javascript
JavaScript正则表达式验证登录实例
2020/03/18 Javascript
跟老齐学Python之字典,你还记得吗?
2014/09/20 Python
python3+PyQt5实现文档打印功能
2018/04/24 Python
idea创建springMVC框架和配置小文件的教程图解
2018/09/18 Python
Python中asyncio与aiohttp入门教程
2018/10/16 Python
python3+opencv3识别图片中的物体并截取的方法
2018/12/05 Python
python与mysql数据库交互的实现
2020/01/06 Python
Python3以GitHub为例来实现模拟登录和爬取的实例讲解
2020/07/30 Python
一篇文章教你用python画动态爱心表白
2020/11/22 Python
法国奢华女性时尚配饰网上商店:Monnier Frères
2016/08/27 全球购物
Melijoe美国官网:法国奢侈童装购物网站
2017/04/19 全球购物
游戏商店:Eneba
2020/04/25 全球购物
为什么要优先使用同步代码块而不是同步方法?
2013/01/30 面试题
有个性的自我评价范文
2013/11/15 职场文书
资源环境与城市管理专业推荐信
2013/11/30 职场文书
遗嘱公证书标准样本
2014/04/08 职场文书
班主任师德师风自我剖析材料
2014/10/02 职场文书
写给医院的感谢信
2015/01/22 职场文书
国王的演讲观后感
2015/06/03 职场文书
《狼牙山五壮士》教学反思
2016/02/17 职场文书