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实现简单QQ单用户机器人的方法
Jul 03 Python
python文件读写操作与linux shell变量命令交互执行的方法
Jan 14 Python
python数据结构之列表和元组的详解
Sep 23 Python
利用Python暴力破解zip文件口令的方法详解
Dec 21 Python
tensorflow实现简单的卷积神经网络
May 24 Python
Python3 翻转二叉树的实现
Sep 30 Python
python调用函数、类和文件操作简单实例总结
Nov 29 Python
python中文分词库jieba使用方法详解
Feb 11 Python
Python多线程Threading、子线程与守护线程实例详解
Mar 24 Python
jupyter notebook读取/导出文件/图片实例
Apr 16 Python
Python持续监听文件变化代码实例
Jul 22 Python
Python 数据可视化之Matplotlib详解
Nov 02 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
NT IIS下用ODBC连接数据库
2006/10/09 PHP
ubuntu10.04配置 nginx+php-fpm模式的详解
2013/06/03 PHP
深入php常用函数的使用汇总
2013/06/08 PHP
详细解读PHP的Yii框架中登陆功能的实现
2015/08/21 PHP
PHP框架Laravel学习心得体会
2015/10/28 PHP
PHP使用mysqli操作MySQL数据库的简单方法
2017/02/04 PHP
PHP实现求连续子数组最大和问题2种解决方法
2017/12/26 PHP
PHP Ajax跨域问题解决方案代码实例
2020/08/01 PHP
从jQuery.camelCase()学习string.replace() 函数学习
2011/09/13 Javascript
探讨JavaScript中声明全局变量三种方式的异同
2013/12/03 Javascript
利用jquery动画特效和css打造的侧边弹出垂直导航
2014/04/04 Javascript
原生js的弹出层且其内的窗口居中
2014/05/14 Javascript
Jquery中基本选择器用法实例详解
2015/05/18 Javascript
ExtJs动态生成treepanel的Json格式
2015/07/19 Javascript
jQuery中$.ajax()和$.getJson()同步处理详解
2015/08/12 Javascript
javascript实现html页面之间参数传递的四种方法实例分析
2015/12/15 Javascript
基于pako.js实现gzip的压缩和解压功能示例
2017/06/13 Javascript
JS原生带小白点轮播图实例讲解
2017/07/22 Javascript
React+Webpack快速上手指南(小结)
2018/08/15 Javascript
浅析Python函数式编程
2018/10/06 Python
Python中的heapq模块源码详析
2019/01/08 Python
Django使用消息提示简单的弹出个对话框实例
2019/11/15 Python
Python 实现将大图切片成小图,将小图组合成大图的例子
2020/03/14 Python
python rolling regression. 使用 Python 实现滚动回归操作
2020/06/08 Python
埃弗顿足球俱乐部官方网上商店:Everton Direct
2018/01/13 全球购物
如何使用PHP session
2015/04/21 面试题
资料员的岗位职责
2013/11/20 职场文书
开工仪式策划方案
2014/05/23 职场文书
学习朴航瑛老师爱岗敬业先进事迹思想汇报
2014/09/17 职场文书
酒店辞职书怎么写
2015/02/26 职场文书
个人年终总结怎么写
2015/03/09 职场文书
党员干部廉政承诺书
2015/04/28 职场文书
2015年环卫处个人工作总结
2015/07/27 职场文书
如何写好活动总结
2019/06/21 职场文书
CSS3实现列表无限滚动/轮播效果
2021/06/23 HTML / CSS
Python安装使用Scrapy框架
2022/04/12 Python