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('刷单完成!')

总结

  • 目前:用脚本手动去跑某个视频的播放。
  • 平台(课程最后)
    • 下单
    • 自动获取订单并且去跑

提醒:自己测试的时候,网站是有缓存。

posted @ 2023-02-11 13:53  凫弥  阅读(669)  评论(0编辑  收藏  举报