4.5.1VIP视频爬取
4.5.1 VIP视频爬取
冬夜微醺,挑灯回叹,巍哥⽆⼼睡眠,突然想看⽚。于是巍哥上⽹搜索python,学习了起来。
⼀、基本概念
爬⾍是什么
爬⾍是指请求⽹站并获取数据的⾃动化程序。⾕歌的搜索引擎爬⾍,隔⼏天对全⽹的⽹页爬取⼀遍,供⼤家查阅,这应是善意爬⾍。但12306抢票软件爬⾍,为了私欲⽆节制地访问⽹站,这就是恶意爬⾍。技术很单纯,哲学很复杂。
爬⾍做什么
我们访问⽹站:浏览器提交请求->下载⽹页代码->解析成页⾯
爬⾍访问⽹站:模拟浏览器发送请求->获取⽹页代码提取有⽤数据->存于数据库或⽂件中
访问⽹站的HTTP连接消息报⽂有Request请求和Response响应两种。⽤户发送Request后浏览器接收到
⽹站Response后,会解析其内容来显⽰给⽤户。⽽爬⾍程序则是模拟浏览器发送请求接收⽹站Response后,提取其中有⽤数据。
反爬是什么
猫和⽼⿏已可以和谐共处了,⽭与盾虽惺惺相惜却很难真正的亲近。爬-反爬-反反爬-反反反爬……对反爬⼿段建⽴初步概念,⼩⽩在学习实践中可以多些思考的⽅向避免⼊坑。
判断请求头来进⾏反爬
这是⽹站早期的反爬⽅式:User-Agent/referrer/cookie
措施:请求头⾥⾯添加对应的参数(复制浏览器⾥⾯的数据)
根据⽤户⾏为来进⾏反爬
请求频率过⾼,服务器设置规定时间之内的请求阈值
措施:降低请求频率或者使⽤代理(IP代理)
⽹页中设置⼀些陷阱(正常⽤户访问不到但是爬⾍可以访问到)
措施:分析⽹页,避开这些特殊陷阱
请求间隔太短,返回相同的数据
措施:增加请求间隔
js加密
常见反爬⽅式,⽂中获取视频下载地址时⽹站便将时间信息做了js加密附值给参数。
参数加密
服务器响应给浏览器的js⽂件,动态⽣成⼀些加密参数,浏览器会根据js的计算得到这些参数。如果请求中没有这些参数,那么服务器就认为请求⽆效。
措施:研究JS,到⽣成参数的算法模拟实现。或使⽤execjs把js代码提取到py⽂件中执⾏。
Cookie加密
浏览器运⾏⽹站JS⽣成⼀个(或多个)cookie再带着这个cookie做⼆次请求。服务器那边收到这个cookie就认为你的访问是通过浏览器过来的合法访问。
措施:研究JS,到⽣成Cookie的算法模拟实现(把Chrome浏览器保存的该⽹站的cookie删除后F12观察)
ajax请求参数加密
抓某个⽹页⾥⾯的数据,发现⽹页源代码⾥⾯没有我们要的数据,那些数据往往是ajax请求得到的。
措施:通过debug JS来到对应的JS加密算法。F12 “XHR/fetch Breakpoints”、 Selenium+PhantomJS
JS反调试(反debug)
打开F12时,会暂停在⼀个“debugger”代码⾏,⽆论怎样都跳不出去。这个“debugger”让我们⽆法调试JS。但是关掉F12窗⼝,⽹页就正常加载了。
措施:在这个函数调⽤的地⽅打个“Breakpoint”。刷新页⾯,在Console⾥⾯重新定义它为空,继续运⾏就可以跳过该陷阱。
JS发送⿏标点击事件
从浏览器可以打开正常的页⾯,⽽在requests⾥⾯却被要求输⼊验证码或重定向其它⽹页。F12观察,每点击页⾯的的链接,它都会做⼀个“cl.gif”的请求。它请求时发送的参数⾮常多,如包含了被点击的链接等等。因为requests没有⿏标事件响应就没有访问cl.gif的过程就直接访问链接,服务器就拒绝服务。
措施:访问链接前先访问⼀下cl.gif,带上所需参数。
字体加密
⽹站采⽤了⾃定义的字体⽂件,在浏览器上正常显⽰,但是爬⾍抓取下来的数据是乱码
登录验证码
验证码登陆才能访问其⽹站,从最开始使⽤简单验证码,识别数字,到更复杂的验证码如:内容验证码、滑动验证码、图⽚拼接验证码等等。
措施:⼀种⽅法是通过第三⽅平台接⼝,完成验证码的验证。
常⽤加密算法、编码
MD5、ASE、RSA、base64
⼆、视频爬取
各⼤视频⽹站,VIP视频⼀般可以试看6分钟。所以⽹络上就出现了⼤量的视频解析⽹站,在这个灰⾊地带,应该是⽩嫖吸引流量通过⼴告谋利。其原理就是调⽤第三⽅「视频解析接⼝」实现的,源头估计是⼀些有VIP账号的在后台解析视频然后分享。随着版权意识、版权管理的加强,以及技术的更新迭代,这类「视频解析接⼝」也⼤量的失效了。
视频观看
借助第三⽅视频解析接⼝,观看只需要三⾏代码即可实现:
import webbrowser
url='/?url=www.iqiyi/v_19rra0h3wg.html'
webbrowser.open(url)
⽂中使⽤的解析接⼝:
# 视频接⼝时效不定,了⼏个接⼝。线路⼆可以查看剧集,但有⼴告
self.lines = {
"Line-1": "/?url={}",
"Line-2": "z1.m1907/?jx={}",
"Line-3": "jx.618g/?url={}",
叶问演员表"Line-4": "www.sfsft/admin.php?url={}",
}
视频下载
北京进出最新消息付费内容,⽹站肯定不会想让轻易得到。通过解析接⼝可以观看,按道理也就应该能拿到视频实际地址。视频下载,⼀般⽽⾔,⽆⾮两种情况:
基金认购和申购的区别⼀种,链接明确是以 mp4、mkv、rmvb 这类视频格式后缀为结尾的链接,这种下载很简单,跟图⽚下载⽅法⼀样,就是视频⽂件要⽐图⽚⼤⽽已。
另⼀种,链接是以 m3u8 这类分段视频后缀结尾的链接,视频都是分段存储的。观看视频,其实是在
加载⼀个个 ts 视频⽚段,⼀个⽚段是⼏秒钟的视频。下载视频就是将 ts 视频⽚段组合成最终视频。m3u8 这种格式的视频,就是由⼀个个 ts 视频⽚段组成的。所以下载的关键是要获取m3u8⽂件的地址。
拿到了关键的m3u8⽂件,多线程加快下载速度,然后⽤FFmpeg拼接ts⽂件为⼀个mp4⽂件。FFmpeg,它的中⽂名叫多媒体视频处理⼯具。FFmpeg 有⾮常强⼤的功能包括视频采集、视频格式转换、视频抓图、给视频加⽔印等功能。这种 ts 视频⽚段合成,格式转换问题,交给FFmpeg 就好了。
1.
2. 在Python中使⽤ffmpy
pip install ffmpy3
导⼊模块后,修改ffmpy3.py⽂件的__init__中的executable为ffmpeg可执⾏⽂件的路径:
def __init__(self, executable='D:\\anaconda3\\ffmpeg', global_options=None, inputs=None, outputs=None):
(例中,把,,三个执⾏⽂件拷到了Python安装⽬录)
确认m3u8⽂件地址
image-20220111172934387
在出现⼤量ts⽂件之前,了⼀阵⼦也没到包含m3u8⽂件的请求与应答。
开⼼地发现很容易就看到第4条请求中就包含着m3u8的应答:
image-20220111173009541
请求头内容为:
image-20220111173024806
请求的参数为:可见有z, jx, sqig, g , 4个参数
image-20220111173037750
应答内容为:
党员的权利和义务是什么image-20220111173049048
⾄此,顺利地达成所愿:
可惜⾼兴了⼏个⼩时,过了0:00,发现这样请求失效了。重新播放获取地址对⽐发现:
问题便出在参数z=5d855143e6fd5d1a252ac6c34b2b7e0f上,它变了。可见这个参数经过了加密且和时间有关。那么请求中的z是怎么得来的呢。如前图所⽰,在该请求之前,⽹站还有2条请求像是js⽂件。尝试搜索z=:
image-20220111173335776
可见请求之前的两个js⽂件都有z的出现。那么,继续到js⽂件中到z的实现:
case 33:
c = new Date,
l = c.getTime(),
u = 6e4 * c.getTimezoneOffset(),
d = l + u + 36e5 * 8,
m = new Date(d),
p = (p = m).getDate() + 9 + 9 ^ 10,
p = (p = St()(String(p))).substring(0, 10),
p = St()(p),
b = m.getDay() + 11397,
v = "//a1.m1907/api/v/?z=".concat(p, "&jx=").concat(o),
v += "&s1ig=".concat(b),
(g = fe.getAll()) && (v += "&g=".concat(g.join(","))),魏书生班规
o || (v = "//a1.m1907/api/v/"),
到了js代码中参数z的实现,但打断点跟踪那个St( )怎么定义却迷失了⽅向,到后来没信⼼将那些密密⿇⿇的实现弄过来是否值得花时间。 在要放弃时发现:5d855143e6fd5d1a252ac6c34b2b7e0f,这个32数字很像MD5算法的输出。于是不⽢⼼地⽤MD5去试了⼀下,居然成功了。(希望等以后能⼒
提升了再返回去把这个问题搞清楚)
模拟⽤python实现:
''' 模拟⽹站JS中加密:
request中的query string parameters:
"z": "5d855143e6fd5d1a252ac6c34b2b7e0f",
"jx": "{}"
"s1ig": "11399",
js⽂件的定义:
c = new Date,
l = c.getTime(),
u = 6e4 * c.getTimezoneOffset(),
d = l + u + 36e5 * 8,
m = new Date(d),
p = (p = m).getDate() + 9 + 9 ^ 10,
p = (p = St()(String(p))).substring(0, 10),
p = St()(p),
b = m.getDay() + 11397,
v = "//a1.m1907/api/v/?z=".concat(p, "&jx=").concat(o),
v += "&s1ig=".concat(b),
'''
def MD5p() :
lt = w()杨采钰 陈金飞
ut = datetime.datetime.utcnow()
o = ((ut.day-lt.day)*24+ut.hour-lt.hour)*60
#o = (ut.hour-lt.hour)*60
l = int(time.time()*1000)
u = int(6e4 * o)
d = int(l + u + 36e5 * 8)
m = time.ime(d/1000)).tm_mday
p = str(m+ 9 + 9^10)
b = lt.weekday()+1 + 11397
p=de()).hexdigest()
p=md5(p[0:10].encode()).hexdigest()
return p, b
关键参数z,s1ig便搞定了。剩下的就容易多了。:)
拿到了关键的m3u8⽂件,多线程下载,⽤FFmpeg拼接ts⽂件为⼀个mp4⽂件。
⾄此,巍哥点燃⼀⽀烟,长吁⼀⼝⽓。
【】
附界⾯显⽰:
image-20220111174337430image-20220111174415166
发布评论