X视频
day01 关于课程
-
模块
- JS逆向案例
- APP逆向(*)
- 平台开发:刷播放量
-
上课节奏:8:00 ~ 10:00
-
大家需要提前准备:
-
Python开发环境 & Pycharm。
-
建议:安卓手机(root)
-
绝大部分:安卓模拟器
-
少部分:安卓手机(root)
我自己:红米8A,想办法去root. - 解开BL锁(等7天左右) - 才能root操作
-
-
今日内容
专业干刷单(12人+3000部手机)。
某视频的播放量(腾讯技术)。
1.前戏
1.1 JSONP
1.2 AES加密
Python默认想要进行AES加密,都要通过一个第三方模块。
pip install pycryptodome==3.10.1
基础版本(app逆向):
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
def aes_encrypt(data_string):
key = "fd6b639dbcff0c2a1b03b389ec763c4b"
iv = "77b07a672d57d64c"
aes = AES.new(
key=key.encode('utf-8'),
mode=AES.MODE_CBC,
iv=iv.encode('utf-8')
)
raw = pad(data_string.encode('utf-8'), 16)
return aes.encrypt(raw)
data = "aadzfalskdjf;lkaj;dkjfa;skdjf;akjsdf;kasd;fjaoqwierijhnlakjdhf"
result = aes_encrypt(data)
print(result)
变换版本:
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import binascii
KEY = "4E2918885FD98109869D14E0231A0BF4"
KEY = binascii.a2b_hex(KEY)
IV = "16B17E519DDD0CE5B79D7A63A4DD801C"
IV = binascii.a2b_hex(IV)
def aes_encrypt(data_string):
aes = AES.new(
key=KEY,
mode=AES.MODE_CBC,
iv=IV
)
raw = pad(data_string.encode('utf-8'), 16)
aes_bytes = aes.encrypt(raw)
return binascii.b2a_hex(aes_bytes).decode().upper()
data = "|878975262|d000035rirv|1631615607|mg3c3b04ba|1.3.5|ktjwlm89_to920weqpg|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
result = aes_encrypt(data)
print(result)
逆向的过程中,如果看到的AES,一定要去找:key、iv
1.3 JS原型和面向对象
ES5,不支持面向对象(居多)。
ES6,支持面向对象。
即使专业前端开发会用一些框架(ES6编写) --> 自动转换成ES5 --> 用户获取JS的面向对象的代码(ES5)。
// JS中定义了一个函数
function f1(){
}
f1()
// JS中定义了一个函数
function f1(a1,a2){
}
f1(1,2)
// JS中定义了一个函数
function f1(a1,a2){
this.a1 = a1; // this,就像python中的self
this.a2 = a2;
}
// 实例化一个对象
var data = new f1(1,2)
data.a1 // 1
data.a2 // 2
// JS中定义了一个函数(构造方法)
function f1(a1,a2){
this.a1 = a1; // this,就像python中的self
this.a2 = a2;
}
// 基于原型实现的面向对象中的方法。(方法)
f1.prototype = {
preInfo:function(a3){
// this.a1
return this.a1 + this.a2 + a3; # 【断点】
}
}
// 实例化一个对象
var data = new f1(1,2)
data.a1 // 1
data.a2 // 2
var result = data.preInfo(100)
console.log(result) // 103
# 问题:如果以后你某中方式确定,推到上面的调用者的话,就可以去找构造方法。
# 问题:上述示例,找到构造方法了,你能看出来a1是谁传的值,以及等于什么?接下来应该继续在往上找。
# 问题:如何找?
# - 根据特征去代码中通篇去找。
# - 找调用栈。
class f1(object):
def __init__(self,a1,a2):
self.a1 = a1
self.a2 = a2
def preInfo(self,a3):
return self.a1 + self.a2 + self.a3
data =f1(1,2)
data.preInfo(100)
2.正餐
视频地址: https://w.yangshipin.cn/video?type=0&vid=x0000354oy4
2.1 用无痕模式
以前你访问过这个平台的话,有一些的cookie会记录下来(模拟第一次访问),内部算法生成的值都会重新计算一遍。
2.2 分析网络请求
2.3 点击播放分析(URL)
点击播放按钮后发生了啥?如果通过代码模拟出来了,就可以去刷播放量了。
https://btrace.yangshipin.cn/kvcollect?BossId=2865&Pwd=1698957057&_dc=0.6335834477551188
https://btrace.yangshipin.cn/kvcollect?BossId=2865
所以:
BossId,固定。
Pwd,固定。
_dc,去所有的js中搜索 _dc,如果能直接搜到并看到:_dc=xxx、 get_dc、create_dc
一般情况下,如果你们在URL中看到:
- 时间戳
>>> time.time()
1631626900.097156
>>> time.time()
1631626901.741516
>>> time.time()
1631626902.218645
- 随机数
JS: Math.random()
Python:
import random
_dc = random.random()
-
关于参数
-
参数固定
-
算法生成
当我们在js中找到算法的具体实现了,我们就有两种方式去实现这个算法: - 用Python代码直接实现。 - 写JS + Python + node.js 可以直接去编译JS代码并的到结果。
-
之前的请求返回
-
搜索 _dc
2.4 点播播放分析(请求体)
请求体中数据来源:
-
参数固定
# version: 1.3.5 version: wc-1.25.0 platform: 4330701
-
算法生成
pid guid
-
之前发给咱们的
vurl,其实就是视频的地址。 问题:视频地址是怎么来的? https://mp4playcloud-cdn.ysp.cctv.cn/n000094fgki.Cvkc10002.mp4?sdtfrom=v7007&guid=ktk3s1js_xw0ljnwa6j&vkey=3475262D508387FF356D4D84989A058ABC495EBD0F89E7300A87A15C70DE5584A007A714E4326E5BB79047390EF700569BF305ABA8B28A29A10D0598EC5064E05365DFF66A90D6B84DD9B6FF600060C309C2FD27AA55EA53B1FB13F6FD483DD7A1D9BEA2E3D32FD3AA0F82CD951052366072396D81E673AAEF7940BD78F3C718&platform=2
2.4.1 vurl是怎么来的?
https://mp4playcloud-cdn.ysp.cctv.cn/n000094fgki.Cvkc10002.mp4?sdtfrom=v7007&guid=ktk3s1js_xw0ljnwa6j&vkey=3475262D508387FF356D4D84989A058ABC495EBD0F89E7300A87A15C70DE5584A007A714E4326E5BB79047390EF700569BF305ABA8B28A29A10D0598EC5064E05365DFF66A90D6B84DD9B6FF600060C309C2FD27AA55EA53B1FB13F6FD483DD7A1D9BEA2E3D32FD3AA0F82CD951052366072396D81E673AAEF7940BD78F3C718&platform=2
https://mp4play-hs-cdn.ysp.cctv.cn/x0000354oy4.sKCU10002.mp4?sdtfrom=4330701&guid=ldxsr073_tz1om4v69f&vkey=249E24625E70F73A1F70A9460CB9AABB22A0010713801351070AD38BC3B142C87D16568A55AD685C3A0900E91D6B5CC7E7087F93A285D7B17B0CE307C5257226C4994269F0A50A3B9C31DCA3436BBD4A6E02A094FD55F505CE3B98D17A325B14EEF8CBAC568DE0629FC51EE29F277EDAE6B203C3D3E1673A233A94459D6899A1&platform=2
n000094fgki.Cvkc10002,视频资源。【playvinfo,fn】
sdtfrom=v7007,固定
guid=ktk3s1js_xw0ljnwa6j,内部算法算成。
vkey=3475262D508387FF356D4D84989A058ABC495EBD0...【playvinfo,fvkey】
platform=2, 固定
1.分析playvinfo请求
希望等到返回值中的:
n000094fgki.Cvkc10002,视频资源。【playvinfo,fn】
vkey=3475262D508387FF356D4D84989A058ABC495EBD0...【playvinfo,fvkey】
代码去伪造请求:
https://playvv.yangshipin.cn/playvinfo?callback=txplayerJsonpCallBack_getinfo_191839&&charge=0&defaultfmt=auto&otype=json&guid=ktk3s1js_xw0ljnwa6j&flowid=ktk5wcw7_qlbraag6wx_4330701&platform=4330701&sdtfrom=v7007&defnpayver=0&appVer=1.3.5&host=w.yangshipin.cn&ehost=https%3A%2F%2Fw.yangshipin.cn%2Fvideo&refer=w.yangshipin.cn&sphttps=1&sphls=&_rnd=1631629201&spwm=4&vid=n000094fgki&defn=auto&fhdswitch=&show1080p=false&dtype=1&clip=4&defnsrc=&fmt=auto&defsrc=1&encryptVer=8.1&cKey=--01EC95C2F91572F711D89557AA6608107FF4D13F9F480F8352A6527C5B4C30BA8F73F6B7B011E018551EFFB87C75FECB6301C112D206FCB32AFBD95EDF28B6E3C311A766455846585DB04327CDD5545BAE50F2DC23DBAAC0859CA00BA4BEAEC115A5282FB0F12111CB533A7BBB2368B6CAFDF2E406F6FAEB627BAE9593F13AEDB54039D21EF0F9C6D7EA14C9734592A8EB7C75F100172E4323EF8E447E84008F8F&_1631629201089=
https://playvv.yangshipin.cn/playvinfo?callback=jsonp1&guid=ldxsr073_tz1om4v69f&platform=4330701&vid=x0000354oy4&defn=auto&charge=0&defaultfmt=auto&otype=json&defnpayver=1&appVer=1.25.0&sphttps=1&sphls=1&spwm=4&dtype=3&defsrc=1&encryptVer=8.1&sdtfrom=4330701&cKey=--01BBC805E4DE40F1F84A80DE0519123C7908F93CFEF74654982786AAAFE287312BEDFAB241BFD22EE26D88434B3F7D058ABB7B6902311BE57CE0FAB08C945981FEE76CCCD062716592388A6E6484A0FAAAE9DAB88DD68A6DA52440F7AF9072894109DA99802BF37591D8D305F421DD8045498F4FAFC1218240501D29EFC5A1796BF14DF7185D214540040EBDB898D01A9F2B639461DE9A39482B042ED8A3DBAE82&panoramic=false&flowid=ldxtb4ui_0mk4zjki4v9
guid: ktk3s1js_xw0ljnwa6j
flowid: ktk5wcw7_qlbraag6wx_4330701
# _rnd: 1631629201
cKey: --01EC95C2F91572F711D89557AA6608107FF4D13F9F480F8352A6527C5B4C30BA8F73F6B7B011E018551EFFB87C75FECB6301C112D206FCB32AFBD95EDF28B6E3C311A766455846585DB04327CDD5545BAE50F2DC23DBAAC0859CA00BA4BEAEC115A5282FB0F12111CB533A7BBB2368B6CAFDF2E406F6FAEB627BAE9593F13AEDB54039D21EF0F9C6D7EA14C9734592A8EB7C75F100172E4323EF8E447E84008F8F
根据关键字:playvinfo
去搜索。
"--018B5C39470C7167AF32830598B7054E912B1ACB0E6A4A3C44D3821932E2DB9180B84C096FBE90E5A593D4C1152FFA0DFB9C0A7A0DA86AFC215F3D63BA58BACD1CCEC2DC5C2F7CC073194F624C2633744044A9D491A8256C76AA1C41AD07F4BADEDB14ED3EBA75CD0CEC43A9C6CCF187C2DBDBABA0DA918D87E6BC89A0CF90087B6F2B51B6FCBDDC12364B5BCB87B3ACB54D55DE286124D6B3CE81897EAC884BB6"
# ckey = y(p.vid, p._rnd, p.appVer, p.guid, p.platform)
Me(e.vid, e.svrtick || _.a.getTimeStampStr(), "1.25.0", t, r)
-
明文:
"|330701920|n000094fgki|1631631539|mg3c3b04ba|1.3.5|ktk3s1js_xw0ljnwa6j|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
-
加密模式:CBC
-
iv和key
key = "4E2918885FD98109869D14E0231A0BF4" iv = "16B17E519DDD0CE5B79D7A63A4DD801C"
vkey = --01 + toString(某些参数 + AES加密得来的).upper()
所以,ckey是通过 某些参数 + AES加密得来的。
测试:
"|20445933|n000094fgki|1631632032|mg3c3b04ba|1.3.5|ktk3s1js_xw0ljnwa6j|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
Wn = Dt + qn + Gn
"|1950641294|x0000354oy4|1675992251|mg3c3b04ba|1.25.0|ldxsr073_tz1om4v69f|4330701|https://w.yangshipin.cn/|mozilla/5.0 (windows nt ||Mozilla|Netscape|Win32|"
"--0135A69A45AFE36284C87EB1C7E7000C3F2F6E9B0184B3F7D3A3AB22C1C22239C1EEB9EF79A16C9CE1054347FA743C30692C3847E2B8D20F878789614868EE272B8EC877D0CD9ACCBE9BF23CC8D527BF7A8920ED46D8FD2057B0C630EA779AD4C842F689BB40F622A891DA3B618D5F02D51117FF069A51DC84BCD037A3A3608D1E9FDFFF42EE508C310AFECC7AA2FCF45932FB1A42D990A0463C8A9594AA2B00ED"
--0135A69A45AFE36284C87EB1C7E7000C3F2F6E9B0184B3F7D3A3AB22C1C22239C1EEB9EF79A16C9CE1054347FA743C30692C3847E2B8D20F878789614868EE272B8EC877D0CD9ACCBE9BF23CC8D527BF7A8920ED46D8FD2057B0C630EA779AD4C842F689BB40F622A891DA3B618D5F02D51117FF069A51DC84BCD037A3A3608D1E9FDFFF42EE508C310AFECC7AA2FCF45932FB1A42D990A0463C8A9594AA2B00ED
我们算法跑一下:
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import binascii
KEY = "4E2918885FD98109869D14E0231A0BF4"
KEY = binascii.a2b_hex(KEY)
IV = "16B17E519DDD0CE5B79D7A63A4DD801C"
IV = binascii.a2b_hex(IV)
def aes_encrypt(data_string):
aes = AES.new(
key=KEY,
mode=AES.MODE_CBC,
iv=IV
)
raw = pad(data_string.encode('utf-8'), 16)
aes_bytes = aes.encrypt(raw)
return binascii.b2a_hex(aes_bytes).decode().upper()
data = "|20445933|n000094fgki|1631632032|mg3c3b04ba|1.3.5|ktk3s1js_xw0ljnwa6j|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
result = aes_encrypt(data)
print(f"--01{result}")
问题来了:明文是怎么来的?
vid="n000094fgki"
_rnd=? 【int(time.time())】
appVer="1.3.5"
platform="4330701"
guid=?
y(p.vid, p._rnd, p.appVer, p.guid, p.platform);
Me(e.vid, e.svrtick || _.a.getTimeStampStr(), "1.25.0", t, r)
"|x0000354oy4|1675992251|mg3c3b04ba|1.25.0|ldxsr073_tz1om4v69f|4330701|https://w.yangshipin.cn/|mozilla/5.0 (windows nt ||Mozilla|Netscape|Win32|"
vid="x0000354oy4"
_rnd=1675992251
appVer="1.25.0"
platform="4330701"
guid=?
关于rnd
import time
rnd= int(time.time())
关于guid
import execjs
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
guid = javascript_file.call('createGUID')
print(guid)
关于flowid
w.dataset.flowid = "".concat(w.dataset.playerId, "_").concat(w.dataset.platform);
- playerId,调用guid
- 拼接platform
import execjs
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
guid = javascript_file.call('createGUID')
print(guid)
flowid = javascript_file.call('createGUID') + "_" + "4330701"
print(flowid)
关于pid
import execjs
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
guid = javascript_file.call('createGUID')
print(guid)
pid = javascript_file.call('createGUID')
print(pid)
flowid = pid + "_" + "4330701"
print(flowid)
明文的算法汇总
EA = "|" + qa + | + la
Wn = "|" + qn + Gn
"|x0000354oy4|1675995214|mg3c3b04ba|1.25.0|ldxsr073_tz1om4v69f|4330701|https://w.yangshipin.cn/|mozilla/5.0 (windows nt ||Mozilla|Netscape|Win32|"
Gn = "|" + vid + "|" + 时间戳 + "|" + "mg3c3b04ba" + "|" + appVer + "|" + guid + "|" + platform + "|" + "https://w.yangshipin.cn/|mozilla/5.0 (windows nt ||Mozilla|Netscape|Win32|"
la = vid + | + rnd + | + Wt + | + "1.3.5"拼接 =》 wt?
qa = ?
-
qa 是什么?
Aa = "|n000094fgki|1631634260|mg3c3b04ba|1.3.5|ktk3s1js_xw0ljnwa6j|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|" // Aa[St] = Aa长度 $a = 0 wl = -5516 for (Se = 0; Se < Aa[St]; Se++) Ma = Aa[bt](Se), // 找到字符对应ascii值,ord $a = ($a << wl + 1360 + 9081 - 4920) - $a + Ma, // ($a << 5) - $a $a &= $a; qa = $a 计算qn Vn = "|x0000354oy4|1675992251|mg3c3b04ba|1.25.0|ldxsr073_tz1om4v69f|4330701|https://w.yangshipin.cn/|mozilla/5.0 (windows nt ||Mozilla|Netscape|Win32|" for (Ur = 0; Ur < Vn[Ut]; Ur++) Xn = Vn[Lt](Ur), Yn = (Yn << Ne + 1360 + 9081 - 4920) - Yn + Xn, Yn &= Yn; qn = Yn
import ctypes def create_qa(data_string): """ 原算法 Aa = "|d000035rirv|1622526980|mg3c3b04ba|1.3.2|df553a055bb06eda3653173ee5a010bf|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|" wl = -5516 $a=0 for (Se = 0; Se < Aa[St]; Se++) Ma = Aa[bt](Se), Ae["charCodeAt"]() $a = ($a << wl + 1360 + 9081 - 4920) - $a + Ma, $a &= $a; qa = $a """ a = 0 for i in data_string: _char = ord(i) a = (a << 5) - a + _char a &= a return ctypes.c_int32(a).value la = "|n000094fgki|1631634260|mg3c3b04ba|1.3.5|ktk3s1js_xw0ljnwa6j|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|" qa = create_qa(la) print(qa)
-
wt是什么?la是什么?
wt = mg3c3b04ba la = "|n000094fgki|1631634260|mg3c3b04ba|1.3.5|ktk3s1js_xw0ljnwa6j|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
扩展:用python去执行js
-
自己电脑上安装node.js
https://nodejs.org/zh-cn/
-
在python中安装一个模块
pip install PyExecJS==1.5.1
-
用python代码去执行js代码
import execjs javascript_file = execjs.compile(''' function createDc() { return Math.random(); } ''') result = javascript_file.call('createDc') print(result)
day02 x视频播放
今日概要:
- x视频
- x视频并发方案
- 线程池,10线程
- 协程,10协程(虚拟)
- 线程池 + 协程 混合模式
1.x视频脚本
- rnd
- guid
- pid
- flowid
- _dc
- AES加密生成ckey
- ckey再去获取
- vkey
- 资源地址
1.1 简单的算法
import execjs
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
def run():
app_version = "1.3.5"
platform = "4330701"
guid = javascript_file.call('createGUID')
pid = javascript_file.call('createGUID')
flow_id = "{}_{}".format(pid, platform)
if __name__ == '__main__':
run()
1.2 生成ckey
-
明文拼接
-
--014DD7322BE036A532732A1CC71689F26BB95A5A39867D226EF19F3264A49FB259551B1B25CAA5B38EBA9ED56973E7AC220536D0456454C731E76D5511096E357CB6A5DD0917B9062739FD018CA6BAEF51B9F4A845CEF922A02293FF94AA6726E8DE4ED07EAA59D18C8CFCA03D1226B8D0B1362DFB97B0A993C8665133A236AEC212E9636EBB6B2BCADEFFC60C5D2016BF191BB30FEDB548D26B0EABF80675F92F
-
准备好相关参数
-
小算法
-
AES加密
import execjs
import time
from urllib.parse import urlparse, parse_qs
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import binascii
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
import ctypes
def create_qa(data_string):
"""
原算法
Aa = "|d000035rirv|1622526980|mg3c3b04ba|1.3.2|df553a055bb06eda3653173ee5a010bf|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
wl = -5516
$a=0
for (Se = 0; Se < Aa[St]; Se++)
Ma = Aa[bt](Se), Ae["charCodeAt"]()
$a = ($a << wl + 1360 + 9081 - 4920) - $a + Ma,
$a &= $a;
qa = $a
"""
a = 0
for i in data_string:
_char = ord(i)
a = (a << 5) - a + _char
a &= a
return ctypes.c_int32(a).value
def aes_encrypt(data_string):
key = binascii.a2b_hex("4E2918885FD98109869D14E0231A0BF4")
iv = binascii.a2b_hex("16B17E519DDD0CE5B79D7A63A4DD801C")
aes = AES.new(
key=key,
mode=AES.MODE_CBC,
iv=iv
)
raw = pad(data_string.encode('utf-8'), 16)
aes_bytes = aes.encrypt(raw)
return binascii.b2a_hex(aes_bytes).decode()
def create_ckey(vid, app_version, guid, platform):
rnd = str(int(time.time()))
wt = "mg3c3b04ba"
ending = "https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
# 1.拼接字符串
data_list = ["", vid, rnd, wt, app_version, guid, platform, ending]
data_string = "|".join(data_list)
# 根据data_string生成qa
qa = create_qa(data_string)
encrypt_string = "|{}{}".format(qa, data_string)
# 2.AES加密
ckey = "--01" + aes_encrypt(encrypt_string).upper()
return ckey
def run(video_url):
vid = parse_qs(urlparse(video_url).query)['vid'][0]
app_version = "1.3.5"
platform = "4330701"
guid = javascript_file.call('createGUID')
pid = javascript_file.call('createGUID')
flow_id = "{}_{}".format(pid, platform)
# 1.创建ckey
ckey = create_ckey(vid, app_version, guid, platform)
print(ckey)
# 2.拿着ckey去发送请求从而获得
# fn是资源地址 "u000058lp0z.ZKuq10002.mp4"
# vkey=...
# 3.去播放
if __name__ == '__main__':
video_url = "https://w.yangshipin.cn/video?type=0&vid=u000058lp0z&ptag=yangshipincp"
run(video_url)
1.3 获取vkey
import requests
import json
import execjs
import time
from urllib.parse import urlparse, parse_qs
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import binascii
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
import ctypes
def create_qa(data_string):
"""
原算法
Aa = "|d000035rirv|1622526980|mg3c3b04ba|1.3.2|df553a055bb06eda3653173ee5a010bf|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
wl = -5516
$a=0
for (Se = 0; Se < Aa[St]; Se++)
Ma = Aa[bt](Se), Ae["charCodeAt"]()
$a = ($a << wl + 1360 + 9081 - 4920) - $a + Ma,
$a &= $a;
qa = $a
"""
a = 0
for i in data_string:
_char = ord(i)
a = (a << 5) - a + _char
a &= a
return ctypes.c_int32(a).value
def aes_encrypt(data_string):
key = binascii.a2b_hex("4E2918885FD98109869D14E0231A0BF4")
iv = binascii.a2b_hex("16B17E519DDD0CE5B79D7A63A4DD801C")
aes = AES.new(
key=key,
mode=AES.MODE_CBC,
iv=iv
)
raw = pad(data_string.encode('utf-8'), 16)
aes_bytes = aes.encrypt(raw)
return binascii.b2a_hex(aes_bytes).decode()
def create_ckey(vid, rnd, app_version, guid, platform):
wt = "mg3c3b04ba"
ending = "https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
# 1.拼接字符串
data_list = ["", vid, rnd, wt, app_version, guid, platform, ending]
data_string = "|".join(data_list)
# 根据data_string生成qa
qa = create_qa(data_string)
encrypt_string = "|{}{}".format(qa, data_string)
# 2.AES加密
ckey = "--01" + aes_encrypt(encrypt_string).upper()
return ckey
def fetch_vkey(vid, rnd, app_ver, platform, flow_id, guid, ckey):
params = {
"callback": "txplayerJsonpCallBack_getinfo_711482",
"charge": "0",
"defaultfmt": "auto",
"otype": "json",
"guid": guid,
"flowid": flow_id,
"platform": platform,
"sdtfrom": "v7007",
"defnpayver": "0",
"appVer": app_ver,
"host": "w.yangshipin.cn",
"ehost": "https://w.yangshipin.cn/video",
"refer": "w.yangshipin.cn",
"sphttps": "1",
"_rnd": rnd, # _rnd: x.getTimeStampStr(),
"spwm": "4",
"vid": vid,
"defn": "auto",
"show1080p": "false",
"dtype": "1",
"clip": "4",
"fmt": "auto",
"defnsrc": "",
"fhdswitch": "",
"defsrc": "1",
"sphls": "",
"encryptVer": "8.1",
"cKey": ckey,
}
headers = {
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, '
'like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'referer': 'https://m.yangshipin.cn/',
}
url = "https://playvv.yangshipin.cn/playvinfo"
with requests.get(url=url, params=params, headers=headers) as res:
# txplayerJsonpCallBack_getinfo_711482( {"dltype":1,"exem":0} } )
# 1.去掉函数名和括号,再进行json序列化
# json.loads(res.text[1:-1])
# 返回的是个原组吧
# print(res.text)
# data = json.loads(res.text)
# print(data)\
# 假设内部都是单引号,这一句也会报错。
# json.loads(res.text[1:-1])
# 2.evel直接编译并执行函数
return eval(res.text)
def txplayerJsonpCallBack_getinfo_711482(info_dict):
return info_dict['vl']['vi'][0]['fn'], info_dict['vl']['vi'][0]['fvkey']
def run(video_url):
vid = parse_qs(urlparse(video_url).query)['vid'][0]
app_version = "1.3.5"
platform = "4330701"
guid = javascript_file.call('createGUID')
pid = javascript_file.call('createGUID')
flow_id = "{}_{}".format(pid, platform)
rnd = str(int(time.time()))
# 1.创建ckey
ckey = create_ckey(vid, rnd, app_version, guid, platform)
# 2.拿着ckey去发送请求从而获得
# fn是资源地址 "u000058lp0z.ZKuq10002.mp4"
# vkey=...
fn, vkey = fetch_vkey(vid, rnd, app_version, platform, flow_id, guid, ckey)
print(fn, vkey)
# 3.去播放
if __name__ == '__main__':
video_url = "https://w.yangshipin.cn/video?type=0&vid=u000058lp0z&ptag=yangshipincp"
run(video_url)
1.4 去播放
-
GET传参
import random params = { "BossId":2865, "Pwd":1698957057, "_dc":random.random() }
-
请求体中的参数
vurl=https://mp4playcloud-cdn.ysp.cctv.cn/u000058lp0z.ZKuq10002.mp4? sdtfrom=v7007&guid=ktmw8ugi_j0kk5cmqmgr&vkey=8650581214BB5F6ED0A3FE10602B5670A5D66B6597D4B11599D708F31B50114B44672F3CBF1D2AA392799F31F1FAB47CB48FEA5B3B22877326E4C6ADFB7205D5C112826FAA41633F00AA07C232E479512F4C7F45A5C9E949157083967F96872D3B9FED7A7C6F0791018C82A370C249892A2C9B089CE9DF7E8682C69B0ABF46A5&platform=2 data_dict = { ... }
import time
import random
import ctypes
import datetime
import binascii
from urllib.parse import urlparse, parse_qs, urlencode
import execjs
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
def create_qa(data_string):
"""
原算法
Aa = "|d000035rirv|1622526980|mg3c3b04ba|1.3.2|df553a055bb06eda3653173ee5a010bf|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
wl = -5516
$a=0
for (Se = 0; Se < Aa[St]; Se++)
Ma = Aa[bt](Se), Ae["charCodeAt"]()
$a = ($a << wl + 1360 + 9081 - 4920) - $a + Ma,
$a &= $a;
qa = $a
"""
a = 0
for i in data_string:
_char = ord(i)
a = (a << 5) - a + _char
a &= a
return ctypes.c_int32(a).value
def aes_encrypt(data_string):
key = binascii.a2b_hex("4E2918885FD98109869D14E0231A0BF4")
iv = binascii.a2b_hex("16B17E519DDD0CE5B79D7A63A4DD801C")
aes = AES.new(
key=key,
mode=AES.MODE_CBC,
iv=iv
)
raw = pad(data_string.encode('utf-8'), 16)
aes_bytes = aes.encrypt(raw)
return binascii.b2a_hex(aes_bytes).decode()
def create_ckey(vid, rnd, app_version, guid, platform):
wt = "mg3c3b04ba"
ending = "https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
# 1.拼接字符串
data_list = ["", vid, rnd, wt, app_version, guid, platform, ending]
data_string = "|".join(data_list)
# 根据data_string生成qa
qa = create_qa(data_string)
encrypt_string = "|{}{}".format(qa, data_string)
# 2.AES加密
ckey = "--01" + aes_encrypt(encrypt_string).upper()
return ckey
def fetch_vkey(vid, rnd, app_ver, platform, flow_id, guid, ckey):
params = {
"callback": "txplayerJsonpCallBack_getinfo_711482",
"charge": "0",
"defaultfmt": "auto",
"otype": "json",
"guid": guid,
"flowid": flow_id,
"platform": platform,
"sdtfrom": "v7007",
"defnpayver": "0",
"appVer": app_ver,
"host": "w.yangshipin.cn",
"ehost": "https://w.yangshipin.cn/video",
"refer": "w.yangshipin.cn",
"sphttps": "1",
"_rnd": rnd, # _rnd: x.getTimeStampStr(),
"spwm": "4",
"vid": vid,
"defn": "auto",
"show1080p": "false",
"dtype": "1",
"clip": "4",
"fmt": "auto",
"defnsrc": "",
"fhdswitch": "",
"defsrc": "1",
"sphls": "",
"encryptVer": "8.1",
"cKey": ckey,
}
headers = {
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, '
'like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'referer': 'https://m.yangshipin.cn/',
}
url = "https://playvv.yangshipin.cn/playvinfo"
with requests.get(url=url, params=params, headers=headers) as res:
# txplayerJsonpCallBack_getinfo_711482( {"dltype":1,"exem":0} } )
# 1.去掉函数名和括号,再进行json序列化
# json.loads(res.text[1:-1])
# 返回的是个原组吧
# print(res.text)
# data = json.loads(res.text)
# print(data)\
# 假设内部都是单引号,这一句也会报错。
# json.loads(res.text[1:-1])
# 2.evel直接编译并执行函数
return eval(res.text)
def txplayerJsonpCallBack_getinfo_711482(info_dict):
return info_dict['vl']['vi'][0]['fn'], info_dict['vl']['vi'][0]['fvkey']
def play(video_url, vid, pid, guid, fn, vkey):
download_params = {
"sdtfrom": "v7007",
"guid": guid,
"vkey": vkey,
"platform": "2",
}
# 视频下载连接视频
vurl = "https://mp4playcloud-cdn.ysp.cctv.cn/{}?{}".format(fn, urlencode(download_params))
params = {
"BossId": 2865,
"Pwd": 1698957057,
"_dc": random.random() # "&_dc=".concat(Math.random()))
}
data = {
"uin": "",
"vid": vid,
"coverid": "",
"pid": pid,
"guid": guid,
"unid": "",
"vt": "0",
"type": "3",
# "url": "https://w.yangshipin.cn/video?type=0&vid=d000035rirv",
"url": video_url,
"bi": "0",
"bt": "0",
"version": "1.3.2",
"platform": "4330701",
"defn": "0",
# "ctime": "2021-06-02 09:30:01",
"ctime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"ptag": "",
"isvip": "-1",
"tpid": "13",
"pversion": "h5",
"hc_uin": "",
"hc_vuserid": "",
"hc_openid": "",
"hc_appid": "",
"hc_pvid": "0",
"hc_ssid": "",
"hc_qq": "",
"hh_ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML like Gecko) Chrome/90.0.4430.212 Safari/537.36",
"ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML like Gecko) Chrome/90.0.4430.212 Safari/537.36",
"ckey": "",
"iformat": "0",
"hh_ref": video_url,
"vuid": "",
"vsession": "",
"format_ua": "other",
"common_rcd_info": "",
"common_ext_info": "",
"v_idx": "0",
"rcd_info": "",
"extrainfo": "",
"c_channel": "",
"vurl": vurl,
"step": "6",
"val": "164",
"val1": "1",
"val2": "1",
"idx": "0",
"c_info": "",
"isfocustab": "0",
"isvisible": "0",
"fact1": "",
"fact2": "",
"fact3": "",
"fact4": "",
"fact5": "",
"cpay": "0",
"tpay": "0",
"dltype": "1"
}
res = requests.post(
url="https://btrace.yangshipin.cn/kvcollect",
params=params,
data=data,
headers={
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, '
'like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'referer': 'https://m.yangshipin.cn/',
}
)
res.close()
def run(video_url):
vid = parse_qs(urlparse(video_url).query)['vid'][0]
app_version = "1.3.5"
platform = "4330701"
guid = javascript_file.call('createGUID')
pid = javascript_file.call('createGUID')
flow_id = "{}_{}".format(pid, platform)
rnd = str(int(time.time()))
# 1.创建ckey
ckey = create_ckey(vid, rnd, app_version, guid, platform)
# 2.拿着ckey去发送请求从而获得
# fn是资源地址 "u000058lp0z.ZKuq10002.mp4"
# vkey=...
fn, vkey = fetch_vkey(vid, rnd, app_version, platform, flow_id, guid, ckey)
# 3.去播放
play(video_url, vid, pid, guid, fn, vkey)
if __name__ == '__main__':
url = "https://w.yangshipin.cn/video?type=0&vid=u000058lp0z&ptag=yangshipincp"
run(url)
2.并发方案
- 进程,资源消耗多。
- 线程,资源消耗少。
- 协程,资源消耗更少。
多线程或多进程开发?
应该开多少个线程?多少个进程? 如果进程和线程开的过多会导致效率低下,所以一般我们用进程池和线程池来进行开发。
import time
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
def task(idx):
print(idx)
time.sleep(2)
# 内部最多可以有10个线程的线程池
pool = ThreadPoolExecutor(10)
# 往线程池中发任务,1000个任务
for i in range(1000):
pool.submit(task, i)
# 等待线程池将所有的任务执行完毕
pool.shutdown()
print("执行完毕")
2.1 线程池版本
import time
import random
import ctypes
import datetime
import binascii
from urllib.parse import urlparse, parse_qs, urlencode
from concurrent.futures import ThreadPoolExecutor
import execjs
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
def create_qa(data_string):
"""
原算法
Aa = "|d000035rirv|1622526980|mg3c3b04ba|1.3.2|df553a055bb06eda3653173ee5a010bf|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
wl = -5516
$a=0
for (Se = 0; Se < Aa[St]; Se++)
Ma = Aa[bt](Se), Ae["charCodeAt"]()
$a = ($a << wl + 1360 + 9081 - 4920) - $a + Ma,
$a &= $a;
qa = $a
"""
a = 0
for i in data_string:
_char = ord(i)
a = (a << 5) - a + _char
a &= a
return ctypes.c_int32(a).value
def aes_encrypt(data_string):
key = binascii.a2b_hex("4E2918885FD98109869D14E0231A0BF4")
iv = binascii.a2b_hex("16B17E519DDD0CE5B79D7A63A4DD801C")
aes = AES.new(
key=key,
mode=AES.MODE_CBC,
iv=iv
)
raw = pad(data_string.encode('utf-8'), 16)
aes_bytes = aes.encrypt(raw)
return binascii.b2a_hex(aes_bytes).decode()
def create_ckey(vid, rnd, app_version, guid, platform):
wt = "mg3c3b04ba"
ending = "https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
# 1.拼接字符串
data_list = ["", vid, rnd, wt, app_version, guid, platform, ending]
data_string = "|".join(data_list)
# 根据data_string生成qa
qa = create_qa(data_string)
encrypt_string = "|{}{}".format(qa, data_string)
# 2.AES加密
ckey = "--01" + aes_encrypt(encrypt_string).upper()
return ckey
def fetch_vkey(vid, rnd, app_ver, platform, flow_id, guid, ckey):
params = {
"callback": "txplayerJsonpCallBack_getinfo_711482",
"charge": "0",
"defaultfmt": "auto",
"otype": "json",
"guid": guid,
"flowid": flow_id,
"platform": platform,
"sdtfrom": "v7007",
"defnpayver": "0",
"appVer": app_ver,
"host": "w.yangshipin.cn",
"ehost": "https://w.yangshipin.cn/video",
"refer": "w.yangshipin.cn",
"sphttps": "1",
"_rnd": rnd, # _rnd: x.getTimeStampStr(),
"spwm": "4",
"vid": vid,
"defn": "auto",
"show1080p": "false",
"dtype": "1",
"clip": "4",
"fmt": "auto",
"defnsrc": "",
"fhdswitch": "",
"defsrc": "1",
"sphls": "",
"encryptVer": "8.1",
"cKey": ckey,
}
headers = {
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, '
'like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'referer': 'https://m.yangshipin.cn/',
}
url = "https://playvv.yangshipin.cn/playvinfo"
with requests.get(url=url, params=params, headers=headers) as res:
# txplayerJsonpCallBack_getinfo_711482( {"dltype":1,"exem":0} } )
# 1.去掉函数名和括号,再进行json序列化
# json.loads(res.text[1:-1])
# 返回的是个原组吧
# print(res.text)
# data = json.loads(res.text)
# print(data)\
# 假设内部都是单引号,这一句也会报错。
# json.loads(res.text[1:-1])
# 2.evel直接编译并执行函数
return eval(res.text)
def txplayerJsonpCallBack_getinfo_711482(info_dict):
return info_dict['vl']['vi'][0]['fn'], info_dict['vl']['vi'][0]['fvkey']
def play(video_url, vid, pid, guid, fn, vkey):
download_params = {
"sdtfrom": "v7007",
"guid": guid,
"vkey": vkey,
"platform": "2",
}
# 视频下载连接视频
vurl = "https://mp4playcloud-cdn.ysp.cctv.cn/{}?{}".format(fn, urlencode(download_params))
params = {
"BossId": 2865,
"Pwd": 1698957057,
"_dc": random.random() # "&_dc=".concat(Math.random()))
}
data = {
"uin": "",
"vid": vid,
"coverid": "",
"pid": pid,
"guid": guid,
"unid": "",
"vt": "0",
"type": "3",
# "url": "https://w.yangshipin.cn/video?type=0&vid=d000035rirv",
"url": video_url,
"bi": "0",
"bt": "0",
"version": "1.3.2",
"platform": "4330701",
"defn": "0",
# "ctime": "2021-06-02 09:30:01",
"ctime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"ptag": "",
"isvip": "-1",
"tpid": "13",
"pversion": "h5",
"hc_uin": "",
"hc_vuserid": "",
"hc_openid": "",
"hc_appid": "",
"hc_pvid": "0",
"hc_ssid": "",
"hc_qq": "",
"hh_ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML like Gecko) Chrome/90.0.4430.212 Safari/537.36",
"ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML like Gecko) Chrome/90.0.4430.212 Safari/537.36",
"ckey": "",
"iformat": "0",
"hh_ref": video_url,
"vuid": "",
"vsession": "",
"format_ua": "other",
"common_rcd_info": "",
"common_ext_info": "",
"v_idx": "0",
"rcd_info": "",
"extrainfo": "",
"c_channel": "",
"vurl": vurl,
"step": "6",
"val": "164",
"val1": "1",
"val2": "1",
"idx": "0",
"c_info": "",
"isfocustab": "0",
"isvisible": "0",
"fact1": "",
"fact2": "",
"fact3": "",
"fact4": "",
"fact5": "",
"cpay": "0",
"tpay": "0",
"dltype": "1"
}
res = requests.post(
url="https://btrace.yangshipin.cn/kvcollect",
params=params,
data=data,
headers={
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, '
'like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'referer': 'https://m.yangshipin.cn/',
}
)
print(res.text)
res.close()
def run(video_url):
vid = parse_qs(urlparse(video_url).query)['vid'][0]
app_version = "1.3.5"
platform = "4330701"
guid = javascript_file.call('createGUID')
pid = javascript_file.call('createGUID')
flow_id = "{}_{}".format(pid, platform)
rnd = str(int(time.time()))
# 1.创建ckey
ckey = create_ckey(vid, rnd, app_version, guid, platform)
# 2.拿着ckey去发送请求从而获得
# fn是资源地址 "u000058lp0z.ZKuq10002.mp4"
# vkey=...
fn, vkey = fetch_vkey(vid, rnd, app_version, platform, flow_id, guid, ckey)
# 3.去播放
play(video_url, vid, pid, guid, fn, vkey)
if __name__ == '__main__':
url = "https://w.yangshipin.cn/video?type=0&vid=u000058lp0z&ptag=yangshipincp"
pool = ThreadPoolExecutor(5)
for i in range(2):
pool.submit(run, url)
pool.shutdown()
print("完成")
my
import execjs
import time
import requests
import json
import random
import datetime
from urllib.parse import urlparse, parse_qs, urlencode
from concurrent.futures import ThreadPoolExecutor
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import binascii
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
import ctypes
def create_qn(data_string):
"""
原算法
Vn = "|x0000354oy4|1675992251|mg3c3b04ba|1.25.0|ldxsr073_tz1om4v69f|4330701|https://w.yangshipin.cn/|mozilla/5.0 (windows nt ||Mozilla|Netscape|Win32|"
Ne = -5516
for (Ur = 0; Ur < Vn[Ut]; Ur++)
Xn = Vn[Lt](Ur),
Yn = (Yn << Ne + 1360 + 9081 - 4920) - Yn + Xn,
Yn &= Yn;
qn = Yn
"""
a = 0
for i in data_string:
_char = ord(i)
a = (a << 5) - a + _char
a &= a
return ctypes.c_int32(a).value
def aes_encrypt(data_string):
key = binascii.a2b_hex("4E2918885FD98109869D14E0231A0BF4")
iv = binascii.a2b_hex("16B17E519DDD0CE5B79D7A63A4DD801C")
aes = AES.new(
key=key,
mode=AES.MODE_CBC,
iv=iv
)
raw = pad(data_string.encode('utf-8'), 16)
aes_bytes = aes.encrypt(raw)
return binascii.b2a_hex(aes_bytes).decode()
def create_ckey(vid, app_version, guid, platform):
"""
--01 4DD7322BE036A532732A1CC71689F26BB95A5A39867D226EF19F3264A49FB259551B1B25CAA5B38EBA9ED56973E7AC220536D0456454C731E76D5511096E357CB6A5DD0917B9062739FD018CA6BAEF51B9F4A845CEF922A02293FF94AA6726E8DE4ED07EAA59D18C8CFCA03D1226B8D0B1362DFB97B0A993C8665133A236AEC212E9636EBB6B2BCADEFFC60C5D2016BF191BB30FEDB548D26B0EABF80675F92F
"""
rnd = str(int(time.time()))
sr = "mg3c3b04ba"
ending = "https://w.yangshipin.cn/|mozilla/5.0 (windows nt ||Mozilla|Netscape|Win32|"
# 1.拼接字符串
data_list = ["", vid, rnd, sr, app_version, guid, platform, ending]
data_string = "|".join(data_list)
# print(data_string)
# 根据data_string生成qa
qn = create_qn(data_string)
# print(qn)
# 待加密的明文
encrypt_string = "|{}{}".format(qn, data_string)
# 2.AES加密
ckey = "--01" + aes_encrypt(encrypt_string).upper()
return ckey
def fetch_vkey(vid, app_ver, platform, flow_id, guid, ckey):
params = {
"callback": 'jsonp1',
"charge": "0",
"defaultfmt": "auto",
"otype": "json",
"guid": guid,
"flowid": flow_id,
"platform": platform,
"sdtfrom": "4330701",
"defnpayver": "1",
"appVer": app_ver,
"sphttps": "1",
"spwm": "4",
"vid": vid,
"defn": "auto",
"dtype": "3",
"defsrc": "1",
"encryptVer": "8.1",
"cKey": ckey,
}
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
'referer': 'https://w.yangshipin.cn/',
}
url = "https://playvv.yangshipin.cn/playvinfo"
with requests.get(url=url, params=params, headers=headers) as res:
# txplayerJsonpCallBack_getinfo_711482( {"dltype":1,"exem":0} } )
# 1.去掉函数名和括号,再进行json序列化
# json.loads(res.text[1:-1])
# 返回的是个原组吧
# print(res.text)
# data = json.loads(res.text)
# print(data)\
# 假设内部都是单引号,这一句也会报错。
# json.loads(res.text[1:-1])
# 2.eval直接编译并执行函数
return eval(res.text)
def jsonp1(info_dict):
return info_dict['vl']['vi'][0]['fn'], info_dict['vl']['vi'][0]['fvkey']
def play(video_url, vid, pid, guid, fn, vkey):
download_params = {
"sdtfrom": "4330701",
"guid": guid,
"vkey": vkey,
"platform": "2",
}
# 视频下载连接视频
vurl = "https://mp4playali-cdn.ysp.cctv.cn/{}?{}".format(fn, urlencode(download_params))
# print(vurl)
params = {
"BossId": 2865,
}
data = {
"ctime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"ua": "mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/107.0.0.0 safari/537.36",
"hh_ua": "mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/107.0.0.0 safari/537.36",
"platform": "4330701",
"guid": guid,
"Pwd": 1698957057,
"version": "wc-1.25.0",
"url": video_url,
"hh_ref": video_url,
"vid": vid,
"isfocustab": "1",
"isvisible": "1",
"idx": "0",
"val": "667",
"pid": pid,
"bi": "480",
"bt": "480",
"defn": "hd",
"step": "1011",
"val1": "0",
"val2": "0",
"fact1": "",
"fact2": "",
"fact3": "",
"fact4": "",
"fact5": ""
}
res = requests.post(
url="https://btrace.yangshipin.cn/kvcollect",
params=params,
data=data,
headers={
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
'referer': 'https://w.yangshipin.cn/',
}
)
res.close()
def run(video_url):
vid = parse_qs(urlparse(video_url).query)['vid'][0]
app_version = "1.20.5"
platform = "4330701"
guid = flow_id = javascript_file.call('createGUID')
pid = javascript_file.call('createGUID')
# 1.创建ckey
ckey = create_ckey(vid, app_version, guid, platform)
# print(ckey)
# 2.拿着ckey去发送请求从而获得
# fn是资源地址 "u000058lp0z.ZKuq10002.mp4"
# data_dict = fetch_vkey(vid, app_version, platform, flow_id, guid, ckey)
# result = data_dict.get('vl').get('vi')[0]
# fn = result.get('fn')
# vkey = result.get('fvkey')
fn, vkey = fetch_vkey(vid, app_version, platform, flow_id, guid, ckey)
# print(fn, vkey)
# 3.去播放
play(video_url, vid, pid, guid, fn, vkey)
if __name__ == '__main__':
video_url = "https://w.yangshipin.cn/video?type=0&vid=x0000354oy4"
pool = ThreadPoolExecutor(5)
for i in range(10):
pool.submit(run, video_url)
pool.shutdown()
print('刷单完成!')
2.2 协程版本
1.什么是协程?
协程也可以去实现其他的操作,例如:
100000000000, 你想让一亿个数字相加。
一亿拆分成10份,让这10份用协程去跑。
可以去完成:
- IO任务
- 计算型的任务(不用协程)
2. Python3.4之前官方未提供功能
以前大家都是用 gevent、greenlet、twisted。
3. Python3.4 + 装饰器
asyncio模块。
import asyncio
@asyncio.coroutine
def func1():
print(1)
yield from asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务
print(2)
@asyncio.coroutine
def func2():
print(3)
yield from asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务
print(4)
tasks = [
asyncio.ensure_future( func1() ), # 协程,任务1
asyncio.ensure_future( func2() ) # 协程,任务2
]
# 将任务交给内部的时间循环去处理(一个线程)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
>>>1
>>>3
>>>2
>>>4
4. Python3.5 + async & awit 关键字
让async & awit关键字代替装饰器去实现协程代码的编写。
注意:@asyncio.coroutine装饰器的模式在python3.8后就会移除掉。
import asyncio
async def func1():
print(1)
await asyncio.sleep(2)
print(2)
async def func2():
print(3)
await asyncio.sleep(2)
print(4)
tasks = [
asyncio.ensure_future(func1()), # 任务1
asyncio.ensure_future(func2()) # 任务2
]
# 将任务交给内部的事件循环去处理(一个线程)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
5. Python3.7 + Task和asyncio.run
import asyncio
async def func():
print("协程内部代码")
# 调用协程函数,返回一个协程对象。
result = func()
# 方式一
# loop = asyncio.get_event_loop() # 创建一个事件循环
# loop.run_until_complete(result) # 将协程当做任务提交到事件循环的任务列表中,协程执行完成之后终止。
# 方式二
# 本质上方式一是一样的,内部先 创建事件循环 然后执行 run_until_complete,一个简便的写法。
# asyncio.run 函数在 Python 3.7 中加入 asyncio 模块,
asyncio.run(result)
import asyncio
async def func11():
print(100)
await asyncio.sleep(2) # 爬虫去发送网络请求
print(200)
return "alex"
async def func1():
print(1)
v1 = await func11()
print(2,v1)
return "wupeiqi"
async def func2():
print(1)
await asyncio.sleep(2)
print(2)
return "格林"
async def main():
print("main开始")
# 创建协程,将协程封装到Task对象中并添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。
# 在调用
task_list = [
asyncio.create_task(func1(), name="n1"), # 任务1
asyncio.create_task(func2(), name="n2") # 任务2
]
# await asyncio.wait(task_list)
# 当执行某协程遇到IO操作时,会自动化切换执行其他任务。
# 此处的await是等待所有协程执行完毕,并将所有协程的返回值保存到done
# 如果设置了timeout值,则意味着此处最多等待的秒,完成的协程返回值写入到done中,未完成则写到pending中。
done, pending = await asyncio.wait(task_list, timeout=1)
print(done, pending)
# asyncio.run(协程对象) # 协程对象=协程函数()
asyncio.run( main() )
6.协程小案例
pip install aiohttp
# 以前发送请求 requests 模块
import aiohttp
import asyncio
async def fetch(session, url):
print("发送请求:", url)
async with session.get(url) as response:
text = await response.text() # IO等待
print("得到结果:", url, len(text))
async def main():
async with aiohttp.ClientSession() as session:
url_list = [
'https://python.org',
'https://www.baidu.com',
'https://www.pythonav.com'
]
"""
tasks = [
asyncio.create_task( fetch(session, "https://python.org") ),
asyncio.create_task( fetch(session, 'https://www.baidu.com')),
asyncio.create_task( fetch(session, 'https://www.pythonav.com')),
]
"""
tasks = [asyncio.create_task(fetch(session, url)) for url in url_list]
await asyncio.wait(tasks)
if __name__ == '__main__':
asyncio.run(main())
import requests
session = requests.Session()
session.get()
session.post()
session.close()
requsets.get()
requsets.post()
储存起来的cookie可以直接拿来使用对下一次post请求来说
7.协程版本
import time
import random
import datetime
import aiohttp
import asyncio
from urllib.parse import parse_qs, urlparse, urlencode
import execjs
import ctypes
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import binascii
HEADERS = {
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, '
'like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'referer': 'https://m.yangshipin.cn/',
}
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
def aes_encrypt(data_string):
key = binascii.a2b_hex("4E2918885FD98109869D14E0231A0BF4")
iv = binascii.a2b_hex("16B17E519DDD0CE5B79D7A63A4DD801C")
aes = AES.new(
key=key,
mode=AES.MODE_CBC,
iv=iv
)
raw = pad(data_string.encode('utf-8'), 16)
aes_bytes = aes.encrypt(raw)
return binascii.b2a_hex(aes_bytes).decode().upper()
def create_qa(data_string):
"""
string = "|d000035rirv|1622526980|mg3c3b04ba|1.3.2|df553a055bb06eda3653173ee5a010bf|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
原算法
Aa = "|d000035rirv|1622526980|mg3c3b04ba|1.3.2|df553a055bb06eda3653173ee5a010bf|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
wl = -5516
$a=0
for (Se = 0; Se < Aa[St]; Se++)
Ma = Aa[bt](Se), Ae["charCodeAt"]()
$a = ($a << wl + 1360 + 9081 - 4920) - $a + Ma,
$a &= $a;
qa = $a
"""
a = 0
for i in data_string:
_char = ord(i)
a = (a << 5) - a + _char
# a &= a & 0xffffffff
a &= a
return ctypes.c_int32(a).value
def create_ckey(vid, rnd, app_ver, platform, guid):
wt = "mg3c3b04ba"
ending = "https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
data_list = ["", vid, rnd, wt, app_ver, guid, platform, ending]
string = "|".join(data_list)
qa = create_qa(string)
encrypt_string = "|{}{}".format(qa, string)
ckey = "--01" + aes_encrypt(encrypt_string).upper()
return ckey
async def fetch_vkey(session, vid, rnd, app_ver, platform, flow_id, guid, ckey):
params = {
"callback": "txplayerJsonpCallBack_getinfo_711482",
"charge": "0",
"defaultfmt": "auto",
"otype": "json",
"guid": guid,
"flowid": flow_id,
"platform": platform,
"sdtfrom": "v7007",
"defnpayver": "0",
"appVer": app_ver,
"host": "w.yangshipin.cn",
"ehost": "https://w.yangshipin.cn/video",
"refer": "w.yangshipin.cn",
"sphttps": "1",
"_rnd": rnd, # _rnd: x.getTimeStampStr(),
"spwm": "4",
"vid": vid,
"defn": "auto",
"show1080p": "false",
"dtype": "1",
"clip": "4",
"fmt": "auto",
"defnsrc": "",
"fhdswitch": "",
"defsrc": "1",
"sphls": "",
"encryptVer": "8.1",
"cKey": ckey,
}
headers = {
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, '
'like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'referer': 'https://m.yangshipin.cn/',
}
url = "https://playvv.yangshipin.cn/playvinfo"
async with session.get(url=url, params=params, headers=headers) as res:
text = await res.text() # IO等待
fn, vkey = eval(text)
return fn, vkey
def txplayerJsonpCallBack_getinfo_711482(arg):
return arg['vl']['vi'][0]['fn'], arg['vl']['vi'][0]['fvkey']
async def play(session, video_url, vid, pid, guid, fn, vkey):
download_params = {
"sdtfrom": "v7007",
"guid": guid,
"vkey": vkey,
"platform": "2",
}
# 视频下载连接视频
download_url = "https://mp4playcloud-cdn.ysp.cctv.cn/{}?{}".format(fn, urlencode(download_params))
# 播放视频
params = {
"BossId": 2865,
"Pwd": 1698957057,
"_dc": random.random() # "&_dc=".concat(Math.random()))
}
data = {
"uin": "",
"vid": vid,
"coverid": "",
"pid": pid,
"guid": guid,
"unid": "",
"vt": "0",
"type": "3",
# "url": "https://w.yangshipin.cn/video?type=0&vid=d000035rirv",
"url": video_url,
"bi": "0",
"bt": "0",
"version": "1.3.2",
"platform": "4330701",
"defn": "0",
# "ctime": "2021-06-02 09:30:01",
"ctime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"ptag": "",
"isvip": "-1",
"tpid": "13",
"pversion": "h5",
"hc_uin": "",
"hc_vuserid": "",
"hc_openid": "",
"hc_appid": "",
"hc_pvid": "0",
"hc_ssid": "",
"hc_qq": "",
"hh_ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML like Gecko) Chrome/90.0.4430.212 Safari/537.36",
"ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML like Gecko) Chrome/90.0.4430.212 Safari/537.36",
"ckey": "",
"iformat": "0",
"hh_ref": video_url,
"vuid": "",
"vsession": "",
"format_ua": "other",
"common_rcd_info": "",
"common_ext_info": "",
"v_idx": "0",
"rcd_info": "",
"extrainfo": "",
"c_channel": "",
"vurl": download_url,
"step": "6",
"val": "164",
"val1": "1",
"val2": "1",
"idx": "0",
"c_info": "",
"isfocustab": "0",
"isvisible": "0",
"fact1": "",
"fact2": "",
"fact3": "",
"fact4": "",
"fact5": "",
"cpay": "0",
"tpay": "0",
"dltype": "1"
}
url = "https://btrace.yangshipin.cn/kvcollect"
async with session.post(url=url, params=params, data=data, headers=HEADERS) as res:
text = await res.text() # IO等待
print(text)
async def handler(video_url):
try:
async with aiohttp.ClientSession() as session:
platform = "4330701"
app_ver = "1.3.5"
rnd = str(int(time.time()))
vid = parse_qs(urlparse(video_url).query)['vid'][0]
guid = javascript_file.call('createGUID')
pid = javascript_file.call('createGUID')
flow_id = "{}_{}".format(pid, platform)
ckey = create_ckey(vid, rnd, app_ver, platform, guid)
# 网络请求
fn, vkey = await fetch_vkey(session, vid, rnd, app_ver, platform, flow_id, guid, ckey)
await play(session, video_url, vid, pid, guid, fn, vkey)
except Exception as e:
print(e)
async def engine(video_url):
# 创建100个任务
tasks = [
asyncio.create_task(handler(video_url)) for _ in range(100)
]
await asyncio.wait(tasks)
def task(video_url):
# import platform
# if "Windows" in platform.platform():
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
# engine(video_url)协程对象
asyncio.run(engine(video_url))
if __name__ == '__main__':
task("https://w.yangshipin.cn/video?type=0&vid=u000058lp0z&ptag=yangshipincp")
my
:python3.6环境
import execjs
import time
import requests
import ctypes
import json
import random
import asyncio
import aiohttp
import datetime
from urllib.parse import urlparse, parse_qs, urlencode
from concurrent.futures import ThreadPoolExecutor
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import binascii
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
def create_qn(data_string):
"""
原算法
Vn = "|x0000354oy4|1675992251|mg3c3b04ba|1.25.0|ldxsr073_tz1om4v69f|4330701|https://w.yangshipin.cn/|mozilla/5.0 (windows nt ||Mozilla|Netscape|Win32|"
Ne = -5516
for (Ur = 0; Ur < Vn[Ut]; Ur++)
Xn = Vn[Lt](Ur),
Yn = (Yn << Ne + 1360 + 9081 - 4920) - Yn + Xn,
Yn &= Yn;
qn = Yn
"""
a = 0
for i in data_string:
_char = ord(i)
a = (a << 5) - a + _char
a &= a
return ctypes.c_int32(a).value
def aes_encrypt(data_string):
key = binascii.a2b_hex("4E2918885FD98109869D14E0231A0BF4")
iv = binascii.a2b_hex("16B17E519DDD0CE5B79D7A63A4DD801C")
aes = AES.new(
key=key,
mode=AES.MODE_CBC,
iv=iv
)
raw = pad(data_string.encode('utf-8'), 16)
aes_bytes = aes.encrypt(raw)
return binascii.b2a_hex(aes_bytes).decode()
def create_ckey(vid, app_version, guid, platform):
"""
--01 4DD7322BE036A532732A1CC71689F26BB95A5A39867D226EF19F3264A49FB259551B1B25CAA5B38EBA9ED56973E7AC220536D0456454C731E76D5511096E357CB6A5DD0917B9062739FD018CA6BAEF51B9F4A845CEF922A02293FF94AA6726E8DE4ED07EAA59D18C8CFCA03D1226B8D0B1362DFB97B0A993C8665133A236AEC212E9636EBB6B2BCADEFFC60C5D2016BF191BB30FEDB548D26B0EABF80675F92F
"""
rnd = str(int(time.time()))
sr = "mg3c3b04ba"
ending = "https://w.yangshipin.cn/|mozilla/5.0 (windows nt ||Mozilla|Netscape|Win32|"
# 1.拼接字符串
data_list = ["", vid, rnd, sr, app_version, guid, platform, ending]
data_string = "|".join(data_list)
# print(data_string)
# 根据data_string生成qa
qn = create_qn(data_string)
# print(qn)
# 待加密的明文
encrypt_string = "|{}{}".format(qn, data_string)
# 2.AES加密
ckey = "--01" + aes_encrypt(encrypt_string).upper()
return ckey
async def fetch_vkey(session, vid, app_ver, platform, flow_id, guid, ckey):
params = {
"callback": 'jsonp1',
"charge": "0",
"defaultfmt": "auto",
"otype": "json",
"guid": guid,
"flowid": flow_id,
"platform": platform,
"sdtfrom": "4330701",
"defnpayver": "1",
"appVer": app_ver,
"sphttps": "1",
"spwm": "4",
"vid": vid,
"defn": "auto",
"dtype": "3",
"defsrc": "1",
"encryptVer": "8.1",
"cKey": ckey,
}
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
'referer': 'https://w.yangshipin.cn/',
}
url = "https://playvv.yangshipin.cn/playvinfo"
async with session.get(url=url, params=params, headers=headers) as res:
text = await res.text()
return eval(text)
def jsonp1(info_dict):
return info_dict['vl']['vi'][0]['fn'], info_dict['vl']['vi'][0]['fvkey']
async def play(session, video_url, vid, pid, guid, fn, vkey):
download_params = {
"sdtfrom": "4330701",
"guid": guid,
"vkey": vkey,
"platform": "2",
}
# 视频下载连接视频
vurl = "https://mp4playali-cdn.ysp.cctv.cn/{}?{}".format(fn, urlencode(download_params))
# print(vurl)
params = {
"BossId": 2865,
}
data = {
"ctime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"ua": "mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/107.0.0.0 safari/537.36",
"hh_ua": "mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/107.0.0.0 safari/537.36",
"platform": "4330701",
"guid": guid,
"Pwd": 1698957057,
"version": "wc-1.25.0",
"url": video_url,
"hh_ref": video_url,
"vid": vid,
"isfocustab": "1",
"isvisible": "1",
"idx": "0",
"val": "667",
"pid": pid,
"bi": "480",
"bt": "480",
"defn": "hd",
"step": "1011",
"val1": "0",
"val2": "0",
"fact1": "",
"fact2": "",
"fact3": "",
"fact4": "",
"fact5": ""
}
async with session.post(
url="https://btrace.yangshipin.cn/kvcollect",
params=params,
data=data,
headers={
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
'referer': 'https://w.yangshipin.cn/',
}
) as res:
text = await res.text()
print(text)
async def handler(video_url):
try:
async with aiohttp.ClientSession() as session:
vid = parse_qs(urlparse(video_url).query)['vid'][0]
app_version = "1.20.5"
platform = "4330701"
guid = flow_id = javascript_file.call('createGUID')
pid = javascript_file.call('createGUID')
# 1.创建ckey
ckey = create_ckey(vid, app_version, guid, platform)
# print(ckey)
# 2.拿着ckey去发送请求从而获得
# fn是资源地址 "u000058lp0z.ZKuq10002.mp4"
fn, vkey = await fetch_vkey(session, vid, app_version, platform, flow_id, guid, ckey)
# print(fn, vkey)
# 3.去播放
await play(session, video_url, vid, pid, guid, fn, vkey)
except Exception as e:
print('--》播放错误原因:', e)
def task(video_url):
# 创建100个任务
tasks = [asyncio.ensure_future(handler(video_url)) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
if __name__ == '__main__':
video_url = "https://w.yangshipin.cn/video?type=0&vid=x0000354oy4"
task(video_url)
print('刷单完成!')
2.3 线程池+协程版本
import time
import random
import datetime
import aiohttp
import asyncio
from urllib.parse import parse_qs, urlparse, urlencode
import execjs
import ctypes
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import binascii
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
HEADERS = {
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, '
'like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'referer': 'https://m.yangshipin.cn/',
}
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
def aes_encrypt(data_string):
key = binascii.a2b_hex("4E2918885FD98109869D14E0231A0BF4")
iv = binascii.a2b_hex("16B17E519DDD0CE5B79D7A63A4DD801C")
aes = AES.new(
key=key,
mode=AES.MODE_CBC,
iv=iv
)
raw = pad(data_string.encode('utf-8'), 16)
aes_bytes = aes.encrypt(raw)
return binascii.b2a_hex(aes_bytes).decode().upper()
def create_qa(data_string):
"""
string = "|d000035rirv|1622526980|mg3c3b04ba|1.3.2|df553a055bb06eda3653173ee5a010bf|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
原算法
Aa = "|d000035rirv|1622526980|mg3c3b04ba|1.3.2|df553a055bb06eda3653173ee5a010bf|4330701|https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
wl = -5516
$a=0
for (Se = 0; Se < Aa[St]; Se++)
Ma = Aa[bt](Se), Ae["charCodeAt"]()
$a = ($a << wl + 1360 + 9081 - 4920) - $a + Ma,
$a &= $a;
qa = $a
"""
a = 0
for i in data_string:
_char = ord(i)
a = (a << 5) - a + _char
# a &= a & 0xffffffff
a &= a
return ctypes.c_int32(a).value
def create_ckey(vid, rnd, app_ver, platform, guid):
wt = "mg3c3b04ba"
ending = "https://w.yangshipin.cn/|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|"
data_list = ["", vid, rnd, wt, app_ver, guid, platform, ending]
string = "|".join(data_list)
qa = create_qa(string)
encrypt_string = "|{}{}".format(qa, string)
ckey = "--01" + aes_encrypt(encrypt_string).upper()
return ckey
async def fetch_vkey(session, vid, rnd, app_ver, platform, flow_id, guid, ckey):
params = {
"callback": "txplayerJsonpCallBack_getinfo_711482",
"charge": "0",
"defaultfmt": "auto",
"otype": "json",
"guid": guid,
"flowid": flow_id,
"platform": platform,
"sdtfrom": "v7007",
"defnpayver": "0",
"appVer": app_ver,
"host": "w.yangshipin.cn",
"ehost": "https://w.yangshipin.cn/video",
"refer": "w.yangshipin.cn",
"sphttps": "1",
"_rnd": rnd, # _rnd: x.getTimeStampStr(),
"spwm": "4",
"vid": vid,
"defn": "auto",
"show1080p": "false",
"dtype": "1",
"clip": "4",
"fmt": "auto",
"defnsrc": "",
"fhdswitch": "",
"defsrc": "1",
"sphls": "",
"encryptVer": "8.1",
"cKey": ckey,
}
headers = {
'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, '
'like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'referer': 'https://m.yangshipin.cn/',
}
url = "https://playvv.yangshipin.cn/playvinfo"
async with session.get(url=url, params=params, headers=headers) as res:
text = await res.text()
fn, vkey = eval(text)
return fn, vkey
def txplayerJsonpCallBack_getinfo_711482(arg):
return arg['vl']['vi'][0]['fn'], arg['vl']['vi'][0]['fvkey']
async def play(session, video_url, vid, pid, guid, fn, vkey):
download_params = {
"sdtfrom": "v7007",
"guid": guid,
"vkey": vkey,
"platform": "2",
}
# 视频下载连接视频
download_url = "https://mp4playcloud-cdn.ysp.cctv.cn/{}?{}".format(fn, urlencode(download_params))
# 播放视频
params = {
"BossId": 2865,
"Pwd": 1698957057,
"_dc": random.random() # "&_dc=".concat(Math.random()))
}
data = {
"uin": "",
"vid": vid,
"coverid": "",
"pid": pid,
"guid": guid,
"unid": "",
"vt": "0",
"type": "3",
# "url": "https://w.yangshipin.cn/video?type=0&vid=d000035rirv",
"url": video_url,
"bi": "0",
"bt": "0",
"version": "1.3.2",
"platform": "4330701",
"defn": "0",
# "ctime": "2021-06-02 09:30:01",
"ctime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"ptag": "",
"isvip": "-1",
"tpid": "13",
"pversion": "h5",
"hc_uin": "",
"hc_vuserid": "",
"hc_openid": "",
"hc_appid": "",
"hc_pvid": "0",
"hc_ssid": "",
"hc_qq": "",
"hh_ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML like Gecko) Chrome/90.0.4430.212 Safari/537.36",
"ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML like Gecko) Chrome/90.0.4430.212 Safari/537.36",
"ckey": "",
"iformat": "0",
"hh_ref": video_url,
"vuid": "",
"vsession": "",
"format_ua": "other",
"common_rcd_info": "",
"common_ext_info": "",
"v_idx": "0",
"rcd_info": "",
"extrainfo": "",
"c_channel": "",
"vurl": download_url,
"step": "6",
"val": "164",
"val1": "1",
"val2": "1",
"idx": "0",
"c_info": "",
"isfocustab": "0",
"isvisible": "0",
"fact1": "",
"fact2": "",
"fact3": "",
"fact4": "",
"fact5": "",
"cpay": "0",
"tpay": "0",
"dltype": "1"
}
url = "https://btrace.yangshipin.cn/kvcollect"
async with session.post(url=url, params=params, data=data, headers=HEADERS) as res:
text = await res.text()
print(text)
async def handler(video_url):
try:
async with aiohttp.ClientSession() as session:
platform = "4330701"
app_ver = "1.3.5"
rnd = str(int(time.time()))
vid = parse_qs(urlparse(video_url).query)['vid'][0]
guid = javascript_file.call('createGUID')
pid = javascript_file.call('createGUID')
flow_id = "{}_{}".format(pid, platform)
ckey = create_ckey(vid, rnd, app_ver, platform, guid)
fn, vkey = await fetch_vkey(session, vid, rnd, app_ver, platform, flow_id, guid, ckey)
await play(session, video_url, vid, pid, guid, fn, vkey)
except Exception as e:
print(e)
async def engine(video_url, request_count):
tasks = [
asyncio.create_task(handler(video_url)) for _ in range(request_count)
]
await asyncio.wait(tasks)
def task(video_url, request_count):
# import platform
# if "Windows" in platform.platform():
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
asyncio.run(engine(video_url, request_count))
def run():
url = "https://w.yangshipin.cn/video?type=0&vid=u000058lp0z&ptag=yangshipincp"
# 要刷的数量
total_count = 1000
# 每个协程同时发送多少个请求
per_coroutine_request_count = 23
# 线程池中5个线程,即:5 * 20 = 100
pool = ThreadPoolExecutor(5) # pool = ProcessPoolExecutor(5)
# 1000/20=50,5
loop_count, div = divmod(total_count, per_coroutine_request_count)
# 循环50次 * 20 = 1000个请求
for i in range(loop_count):
pool.submit(task, url, per_coroutine_request_count)
pool.submit(task, url, div)
pool.shutdown() # 等待所有任务执行完毕
if __name__ == '__main__':
run()
my
import execjs
import time
import requests
import ctypes
import json
import random
import asyncio
import aiohttp
import datetime
from urllib.parse import urlparse, parse_qs, urlencode
from concurrent.futures import ThreadPoolExecutor
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import binascii
HEADERS = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
'referer': 'https://w.yangshipin.cn/',
}
javascript_file = execjs.compile('''
function createGUID() {
var e = (new Date).getTime().toString(36)
, t = Math.random().toString(36).replace(/^0./, "");
return "".concat(e, "_").concat(t)
}
''')
def create_qn(data_string):
"""
原算法
Vn = "|x0000354oy4|1675992251|mg3c3b04ba|1.25.0|ldxsr073_tz1om4v69f|4330701|https://w.yangshipin.cn/|mozilla/5.0 (windows nt ||Mozilla|Netscape|Win32|"
Ne = -5516
for (Ur = 0; Ur < Vn[Ut]; Ur++)
Xn = Vn[Lt](Ur),
Yn = (Yn << Ne + 1360 + 9081 - 4920) - Yn + Xn,
Yn &= Yn;
qn = Yn
"""
a = 0
for i in data_string:
_char = ord(i)
a = (a << 5) - a + _char
a &= a
return ctypes.c_int32(a).value
def aes_encrypt(data_string):
key = binascii.a2b_hex("4E2918885FD98109869D14E0231A0BF4")
iv = binascii.a2b_hex("16B17E519DDD0CE5B79D7A63A4DD801C")
aes = AES.new(
key=key,
mode=AES.MODE_CBC,
iv=iv
)
raw = pad(data_string.encode('utf-8'), 16)
aes_bytes = aes.encrypt(raw)
return binascii.b2a_hex(aes_bytes).decode()
def create_ckey(vid, app_version, guid, platform):
"""
--01 4DD7322BE036A532732A1CC71689F26BB95A5A39867D226EF19F3264A49FB259551B1B25CAA5B38EBA9ED56973E7AC220536D0456454C731E76D5511096E357CB6A5DD0917B9062739FD018CA6BAEF51B9F4A845CEF922A02293FF94AA6726E8DE4ED07EAA59D18C8CFCA03D1226B8D0B1362DFB97B0A993C8665133A236AEC212E9636EBB6B2BCADEFFC60C5D2016BF191BB30FEDB548D26B0EABF80675F92F
"""
rnd = str(int(time.time()))
sr = "mg3c3b04ba"
ending = "https://w.yangshipin.cn/|mozilla/5.0 (windows nt ||Mozilla|Netscape|Win32|"
# 1.拼接字符串
data_list = ["", vid, rnd, sr, app_version, guid, platform, ending]
data_string = "|".join(data_list)
# print(data_string)
# 根据data_string生成qa
qn = create_qn(data_string)
# print(qn)
# 待加密的明文
encrypt_string = "|{}{}".format(qn, data_string)
# 2.AES加密
ckey = "--01" + aes_encrypt(encrypt_string).upper()
return ckey
async def fetch_vkey(session, vid, app_ver, platform, flow_id, guid, ckey):
params = {
"callback": 'jsonp1',
"charge": "0",
"defaultfmt": "auto",
"otype": "json",
"guid": guid,
"flowid": flow_id,
"platform": platform,
"sdtfrom": "4330701",
"defnpayver": "1",
"appVer": app_ver,
"sphttps": "1",
"spwm": "4",
"vid": vid,
"defn": "auto",
"dtype": "3",
"defsrc": "1",
"encryptVer": "8.1",
"cKey": ckey,
}
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
'referer': 'https://w.yangshipin.cn/',
}
url = "https://playvv.yangshipin.cn/playvinfo"
async with session.get(url=url, params=params, headers=headers) as res:
text = await res.text()
return eval(text)
def jsonp1(info_dict):
return info_dict['vl']['vi'][0]['fn'], info_dict['vl']['vi'][0]['fvkey']
async def play(session, video_url, vid, pid, guid, fn, vkey):
print('执行play函数')
download_params = {
"sdtfrom": "4330701",
"guid": guid,
"vkey": vkey,
"platform": "2",
}
# 视频下载连接视频
vurl = "https://mp4playali-cdn.ysp.cctv.cn/{}?{}".format(fn, urlencode(download_params))
# print(vurl)
params = {
"BossId": 2865,
}
data = {
"ctime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"ua": "mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/107.0.0.0 safari/537.36",
"hh_ua": "mozilla/5.0 (windows nt 10.0; win64; x64) applewebkit/537.36 (khtml, like gecko) chrome/107.0.0.0 safari/537.36",
"platform": "4330701",
"guid": guid,
"Pwd": 1698957057,
"version": "wc-1.25.0",
"url": video_url,
"hh_ref": video_url,
"vid": vid,
"isfocustab": "1",
"isvisible": "1",
"idx": "0",
"val": "667",
"pid": pid,
"bi": "480",
"bt": "480",
"defn": "hd",
"step": "1011",
"val1": "0",
"val2": "0",
"fact1": "",
"fact2": "",
"fact3": "",
"fact4": "",
"fact5": ""
}
url = "https://btrace.yangshipin.cn/kvcollect",
async with session.post(url=url, params=params, data=data, headers=HEADERS) as res:
text = await res.text()
print(text)
async def handler(video_url):
print('执行handler函数')
try:
async with aiohttp.ClientSession() as session:
vid = parse_qs(urlparse(video_url).query)['vid'][0]
app_version = "1.25.0"
platform = "4330701"
guid = flow_id = javascript_file.call('createGUID')
pid = javascript_file.call('createGUID')
# 1.创建ckey
ckey = create_ckey(vid, app_version, guid, platform)
# print(ckey)
# 2.拿着ckey去发送请求从而获得
# fn是资源地址 "u000058lp0z.ZKuq10002.mp4"
fn, vkey = await fetch_vkey(session, vid, app_version, platform, flow_id, guid, ckey)
print(fn, vkey)
# 3.去播放
await play(session, video_url, vid, pid, guid, fn, vkey)
except Exception as e:
print('--》播放错误原因:', e)
async def engine(video_url, request_count):
print('执行engine函数')
# 创建100个任务
tasks = [asyncio.ensure_future(handler(video_url)) for _ in range(request_count)]
await asyncio.wait(tasks)
def task(video_url, request_count):
print('执行task函数')
tasks = [asyncio.create_task(handler(video_url)) for _ in range(request_count)]
print(tasks)
loop = asyncio.get_event_loop()
# loop.run_until_complete(engine(video_url, request_count))
loop.run_until_complete(asyncio.wait(tasks))
if __name__ == '__main__':
video_url = "https://w.yangshipin.cn/video?type=0&vid=v00001086qi"
# 总共刷多少个
total_count = 5
# 每个协程最大同时发送多少个请求
per_coroutine_request_count = 20
# 线程池中几个线程
pool = ThreadPoolExecutor(5)
# 计算出大约要多少个协程
loop_count, div = divmod(total_count, per_coroutine_request_count)
# 计算出的协程数量进行循环往线程池中添加任务
for i in range(loop_count):
pool.submit(task, video_url, per_coroutine_request_count)
pool.submit(task, video_url, div)
pool.shutdown()
print('刷单完成!')
总结
- 目前:用脚本手动去跑某个视频的播放。
- 平台(课程最后)
- 下单
- 自动获取订单并且去跑
提醒:自己测试的时候,网站是有缓存。