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之集合的关系
Sep 24 Python
基于python进行桶排序与基数排序的总结
May 29 Python
python 利用for循环 保存多个图像或者文件的实例
Nov 09 Python
python写日志文件操作类与应用示例
Jul 01 Python
face++与python实现人脸识别签到(考勤)功能
Aug 28 Python
Python 3.8正式发布重要新功能一览
Oct 17 Python
PyCharm 在Windows的有用快捷键详解
Apr 07 Python
Python ADF 单位根检验 如何查看结果的实现
Jun 03 Python
Pycharm安装第三方库失败解决方案
Nov 17 Python
PyTorch 中的傅里叶卷积实现示例
Dec 11 Python
Django一小时写出账号密码管理系统
Apr 29 Python
python图像处理 PIL Image操作实例
Apr 09 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 daodb插入、更新与删除数据
2009/03/19 PHP
基于PHP编程注意事项的小结
2013/04/27 PHP
PHP实现从PostgreSQL数据库检索数据分页显示及根据条件查找数据示例
2018/06/09 PHP
PHP上传文件及图片到七牛的方法
2018/07/25 PHP
PHP使用PDO实现mysql防注入功能详解
2019/12/20 PHP
js ondocumentready onmouseover onclick onmouseout 样式
2010/07/22 Javascript
使用jQuery简单实现模拟浏览器搜索功能
2014/12/21 Javascript
js实现仿Windows风格选项卡和按钮效果实例
2015/05/13 Javascript
js实现div拖动动画运行轨迹效果代码分享
2015/08/27 Javascript
基于bootstrap实现广告轮播带图片和文字效果
2016/07/22 Javascript
AngularJS  $modal弹出框实例代码
2016/08/24 Javascript
用js实现简单算法的实例代码
2016/09/24 Javascript
快速掌握jquery分页插件jqPaginator的使用方法
2017/08/09 jQuery
JS实现页面内跳转的简单代码
2017/09/03 Javascript
让网站自动生成章节目录索引的多个js代码
2018/01/07 Javascript
vue实现手机号码的校验实例代码(防抖函数的应用场景)
2019/09/05 Javascript
ES5新增数组的实现方法
2020/05/12 Javascript
html-webpack-plugin修改页面的title的方法
2020/06/18 Javascript
介绍Python的Urllib库的一些高级用法
2015/04/30 Python
Python正则表达式如何进行字符串替换实例
2016/12/28 Python
Python中max函数用于二维列表的实例
2018/04/03 Python
用python生成1000个txt文件的方法
2018/10/25 Python
python matplotlib实现双Y轴的实例
2019/02/12 Python
python装饰器相当于函数的调用方式
2019/12/27 Python
python实现将字符串中的数字提取出来然后求和
2020/04/02 Python
Python Django form 组件动态从数据库取choices数据实例
2020/05/19 Python
基于python实现简单C/S模式代码实例
2020/09/14 Python
日本酒店、民宿、温泉旅馆、当地旅行团中文预订:e路东瀛
2019/12/09 全球购物
广州喜创信息技术有限公司JAVA软件工程师笔试题
2012/10/17 面试题
shell变量的作用空间是什么
2013/08/17 面试题
护理学毕业生自荐信
2013/10/02 职场文书
环保公益广告语
2014/03/13 职场文书
鉴定评语大全
2014/05/05 职场文书
就业协议书
2014/09/12 职场文书
2014年学校团委工作总结
2014/12/20 职场文书
MYSQL数据库使用UTF-8中文编码乱码的解决办法
2021/05/26 MySQL