一、声明

本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除!

二、逆向目标

  • 网站:pc端荔枝网加密逆向

  • 网址:aHR0cHM6Ly93d3cuZ2R0di5jbi8=

  • 解决方案:

        补环境

三、加密参数定位分析

浏览器抓包请求分析

  搜索接口:请求url中包含api/search/v1/news

右键包含api/search/v1/news的目标请求,Copy - > Copy as cURL(bash),spidertoos转化成python代码

 运行报错,看请求参数中x-itouchtv-ca-timestamp 毫秒时间戳 参与了时间运算,对及时性要求比较高

  有5个相同格式字符串的加密参数

  x-itouchtv-ca-key : 待分析

  x-itouchtv-ca-signature: 待分析

  x-itouchtv-ca-timestamp:毫秒时间戳

  x-itouchtv-client: WEB_PC(定值)

  x-itouchtv-device-id: WEB_ec1082b0-d58f-11f0-930f-e74627bdcb69 (定值)

文章用hook WebAssembly.instantiateStreaming 和 堆栈追踪两种方式定位目标加密参数

hook方式定位加密参数

重新刷新浏览器,目标请求拦截,导航栏定位到wasm,发现请求获取wasm文件,基本确定了wasm加密

WebAssembly介绍,简单了解一下WebAssembly是什么,如何加载的,如何通过 WebAssembly 的 JavaScript API 来使用 WebAssembly,如何导出WebAssembly 函数

浏览器 下一个Script断点,刷新网站,断点断住

此时打开hook_wasm脚本,运行。脚本主要作用 hook WebAssembly 所有的导出函数。

// 保存原始方法
const originalInstantiateStreaming = WebAssembly.instantiateStreaming;

// 重写 WebAssembly.instantiateStreaming 方法
WebAssembly.instantiateStreaming = async function(resp, imports) {
    console.log('WASM instantiateStreaming called:', resp, imports);
    
    // 调用原始方法
    const result = await originalInstantiateStreaming.call(this, resp, imports);
    
    // 获取所有导出
    const exports = result.instance.exports;
    console.log('WASM exports:', Object.keys(exports));
    
    // 拦截每个导出函数
    Object.keys(exports).forEach(key => {
        if (typeof exports[key] === 'function') {
            const orig = exports[key];
            exports[key] = function(...args) {
                console.log('WASM export called:', key, args);
                return orig.apply(this, args);
            };
        }
    });
    
    return result;
};

放开Script断点,运行,此时控制打印出所有的WebAssembly 导出函数

用导出的函数名全局搜索,将搜索结果都打上断点,观察返回值

Hook方式定位加密参数生成位置分析完毕,接下来看看堆栈回溯的方式

堆栈回溯

  1. 浏览器 XHR/fetch Breakpoints 下载一个条件断点:api/search/v1/news,案例中是搜索接口,刷新浏览器,沿着堆栈向上追踪

取消xhr断点,在s.request 下一个断点,发现加密结果已经存在

继续追踪,参数t 已经出现加密的值了

分析这段代码,t是从哪儿来的?

return (0,
                c.default)(n, e, s).then((function(t) {
                    return new Promise((function(r, i) {
                        (0,
                        u.default)(f(f({
                            method: n || "POST",
                            url: e,
                            data: s,
                            timeout: 2e4
                        }, !v && {
                            responseType: y || "json"
                        }), {}, {
                            headers: t
                        })).then((function(t) {
                            d && d.log("fetch success:", p, t.config.method.toUpperCase(), "status ".concat(t.status), e),
                            r(t.data || g && t)
                        }
                        )).catch((function(t) {
                            if (t.response) {
                                var n = t.response || {}
                                  , r = n.data || {}
                                  , u = r.errorCode
                                  , c = r.errorMessage;
                                return "object" == ("undefined" == typeof window ? "undefined" : (0,
                                o.default)(window)) && u && (a.Modal.destroyAll(),
                                a.Modal.error({
                                    title: c
                                })),
                                d && d.error("fetch error:", p, n.config.method.toUpperCase(), "status ".concat(n.status), e),
                                i(n.data)
                            }
                            return d && d.error(t),
                            i(t)
                        }
                        ))
                    }
                    ))
                }
                )).catch((function(t) {
                    throw t
                }
                ))

t值的来源:

(0,c.default)(n, e, s) 就是promise异步函数的resolve 的值,所以加密值是由该函数生成

在(0,c.default)(n, e, s) 下断点进入函数内部

继续进入,在所有控制流返回值出打断点(调试过程中如果有其它断点干扰,先取消其它断点,只关注返回值处断点)

发现return e.t3 = e.sent 出现我们加密值 , e.sent 是上一步return 的返回值,也就是m函数的返回值

m(n, o, d || "", "WEB_PC", a, (null === (u = r) || void 0 === u || null === (c = u.env) || void 0 === c ? void 0 : c.SSR_API_SCOPE) || void 0);

断点m函数,进入函数内部

进入之后,又是一个switch-case控制流,在所有分支返回值处打上断点,观察返回值

t.abrupt("return", a.apply(void 0, u)); 函数生成加密值,进入函数内部,加密值是由G 函数产生的,很多请求都会走B.a这个函数,为了方便查询我们目前请求,可以下一个条件断点

进入w.a函数内部,是wasm

通过hook wasm导出函数 和堆栈回溯两种方式定位加密函数分析完毕,接下来完成补环境环节

四、补环境

加密结果是B.a函数的返回值

抠出加密函数B.a 重命名为encrypt,运行代码:

将vendor_w_e0e1da0d.js 加密js 复制到vscode->lz_source.js 文件中,同时按住Ctrl+k + 0,搜索所有的代码

搜索B.a定位到加密位置:

鼠标悬浮在M,跳转到M定义的位置

M 抠出来,重新运行

接下来的值都按照这种方式去抠。

w的值说一下:

return w = A.exports, 下一个断点

向上追踪

w = A.exports 中的A 由参数C得到,C = Q.instance,

case 13:
    return Q = A.sent,
    C = Q.instance,
    E = Q.module,
    A.abrupt("return", O(C, E));

Q 是case 9 的返回值(0, A.t0)(A.t1, A.t2) 得到

 case 9:
    return A.t1 = A.sent,
    A.t2 = B,
    A.next = 13,
    (0,
    A.t0)(A.t1, A.t2);

参数A.t1, A.t2 由case2 代码得到

case 2:
     B = t(),
    ("string" == typeof I || "function" == typeof Request && I instanceof Request || "function" == typeof URL && I instanceof URL) && (I = fetch(I)),
    A.t0 = a,
    A.next = 9,
    I;

A.t2 = B, B =t()函数 (可以直接抠)

A.t1 = A.sent , A.sent 是case2 返回值I 得到,I= fetch(I) ,fetch(I) 是用于发送wasm 请求的。

w的值分析完毕

接下来继续抠缺少的变量和函数

补完整之后,继续运行:

将try catch 中catch 分支日志打印,一共也就2处

补上剩下几个缺少的变量函数,运行代码,RuntimeError 错误消失

剩下的就是不环境部分了

环境部分基本不需要补什么,evn.js代码如下:

catvm = {}
;(() => {
    'use strict';
    // 取原型链上的toString
    const $toString = Function.toString;
    // 取方法名 reload
    const myFunction_toString_symbol = Symbol('('.concat('', ')_', (Math.random() + '').toString(36)));
    const myToString = function () {
        return typeof this == 'function' && this[myFunction_toString_symbol] || $toString.call(this);
    };

    function set_native(func, key, value) {
        Object.defineProperty(func, key, {
            "enumerable": false,  // 不可枚举
            "configurable": true, // 可配置
            "writable": true, // 可写
            "value": value
        })
    }

    delete Function.prototype['toString'];// 删除原型链上的toString
    set_native(Function.prototype, "toString", myToString); // 自定义一个getter方法,其实就是一个hook
    //套个娃,保护一下我们定义的toString,避免js对toString再次toString,如:location.reload.toString.toString() 否则就暴露了
    set_native(Function.prototype.toString, myFunction_toString_symbol, "function toString() { [native code] }");
    catvm.safefunction = (func) => {
        set_native(func, myFunction_toString_symbol, `function ${myFunction_toString_symbol,func.name || ''}() { [native code] }`);
    }; //导出函数到globalThis,更改原型上的toSting为自己的toString。这个方法相当于过掉func的toString检测点
}).call(this);

//原型名称
catvm.rename = function rename(obj,proValue)
{
    //定义对象名称
    Object.defineProperties(obj,{
        [Symbol.toStringTag]:{
            value:proValue,
            configurable:true
        }
   });
}
catvm.proxy = function (obj,objName) {
    // Proxy 可以多层代理,即 a = new proxy(a); a = new proxy(a);第二次代理
    // 后代理的检测不到先代理的
    return new Proxy(obj, {
        set(target, property, value) {
            // catvm.memory.log.push({"类型":"set-->","调用者":target,"调用属性":property,"设置值":value});
            console.table([{"类型":"set-->","调用者":objName,"调用属性":property,"设置值":value}]);
            return Reflect.set(...arguments); //这是一种反射语句,这种不会产生死循环问题
        },
        get(target, property, receiver) {
            if(target.name!=='toString' && property !=='Math' && property !== 'isNaN' && property !=='undefined'){
                // catvm.memory.log.push({"类型":"get<--","调用者":target,"调用属性":property,"获取值":target[property]});
                console.table([{"类型":"get<--","调用者":objName,"调用属性":property,"获取值":target[property]}]);
            }
            return target[property];  // target中访问属性不会再被proxy拦截,所以不会死循环
        }
    });
}

delete globalThis.global
delete globalThis.Buffer
// delete globalThis.process

window = globalThis;
self = window
self.self = window
window.self = window

Window = function Window(){}
Object.setPrototypeOf(window,Window.prototype)
catvm.rename(window,'Window')
catvm.rename(Window,'Window')
catvm.safefunction(Window)

Navigator = function Navigator(){}
Navigator.prototype.userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
navigator = {}
Object.setPrototypeOf(navigator,Navigator.prototype)
catvm.rename(Navigator,'Navigator')
catvm.safefunction(Navigator)

Location = function Location(){}
location = {
    host:'www.gdtv.cn',
    origin:'https://www.gdtv.cn',
    href:'https://www.gdtv.cn',
}
Object.setPrototypeOf(location,Location.prototype)
catvm.rename(Location,'Location')
catvm.safefunction(Location)

HTMLDocument= function HTMLDocument(){}
document = {location:location}
Object.setPrototypeOf(document,HTMLDocument.prototype)
catvm.rename(HTMLDocument,'HTMLDocument')
catvm.safefunction(HTMLDocument)

// window = catvm.proxy(window,'window')
// document = catvm.proxy(document,'document')
// location = catvm.proxy(location,'location')
// navigator = catvm.proxy(navigator,'navigator')

抠代码部分lizhi.js

const fs = require('fs');
const path = require('path');
require('./env');

// 方法1:拼接完整路径
var wasmPath = path.join(__dirname, 'lizhi.wasm');
var wasmBuffer = fs.readFileSync(wasmPath);

var P = Function
x = eval

function E(A, g, I) {
    return E = function () {
            if ("undefined" == typeof Reflect || !Reflect.construct)
                return !1;
            if (Reflect.construct.sham)
                return !1;
            if ("function" == typeof Proxy)
                return !0;
            try {
                return Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], (function () {}))),
                    !0
            } catch (A) {
                return !1
            }
        }() ? Reflect.construct.bind() : function (A, g, I) {
            var B = [null];
            B.push.apply(B, g);
            var Q = new(Function.bind.apply(A, B));
            return I && D(Q, I.prototype),
                Q
        },
        E.apply(null, arguments)
}
N = new TextDecoder("utf-8", {
    ignoreBOM: !0,
    fatal: !0
})

function K(A, g) {
    return A >>>= 0,
        N.decode(k().subarray(A, A + g))
}

function S() {
    for (var A = arguments.length, g = new Array(A), I = 0; I < A; I++)
        g[I] = arguments[I];
    var B = function () {
        try {
            return E(P, g)
        } catch (A) {
            console.log("S=A",A)
            return function () {
                return null
            }
        }
    }();
    return B.toString = function () {
            return ""
        },
        B
}

function R(A, g) {
    try {
        return A.apply(this, g)
    } catch (A) {
        console.log("R==A",A)
        w.__wbindgen_export_3(Y(A))
    }
}

function Y(A) {
    o === M.length && M.push(M.length + 1);
    var g = o;
    return o = M[g],
        M[g] = A,
        g
}
var c = null;

function s() {
    return null !== c && 0 !== c.byteLength || (c = new Int32Array(w.memory.buffer)),
        c
}

function U(A) {
    return null == A
}
function I(A) {
                                return I = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(A) {
                                    return typeof A
                                }
                                : function(A) {
                                    return A && "function" == typeof Symbol && A.constructor === Symbol && A !== Symbol.prototype ? "symbol" : typeof A
                                }
                                ,
                                I(A)
                            }

function i(A) {
    return M[A]
}

function G(A) {
    var g = i(A);
    return function (A) {
            A < 132 || (M[A] = o,
                o = A)
        }(A),
        g
}
var h = 0,
    y = "undefined" != typeof TextEncoder ? new TextEncoder("utf-8") : {
        encode: function () {
            throw Error("TextEncoder not available")
        }
    }

function F(A, g) {
    return y.encodeInto(A, g)
}
var J = null;

function k() {
    return null !== J && 0 !== J.byteLength || (J = new Uint8Array(w.memory.buffer)),
        J
}

function t() {
    var g = {
        wbg: {}
    };
    return g.wbg.__wbindgen_object_drop_ref = function (A) {
            G(A)
        },
        g.wbg.__wbg_self_1ff1d729e9aae938 = function () {
            return R((function () {
                return Y(self.self)
            }), arguments)
        },
        g.wbg.__wbg_window_5f4faef6c12b79ec = function () {
            return R((function () {
                return Y(window.window)
            }), arguments)
        },
        g.wbg.__wbg_globalThis_1d39714405582d3c = function () {
            return R((function () {
                return Y(globalThis.globalThis)
            }), arguments)
        },
        g.wbg.__wbg_global_651f05c6a0944d1c = function () {
            return R((function () {
                return Y(A.global)
            }), arguments)
        },
        g.wbg.__wbindgen_is_undefined = function (A) {
            return void 0 === i(A)
        },
        g.wbg.__wbg_newnoargs_581967eacc0e2604 = function (A, g) {
            return Y(S(K(A, g)))
        },
        g.wbg.__wbg_call_cb65541d95d71282 = function () {
            return R((function (A, g) {
                return Y(i(A).call(i(g)))
            }), arguments)
        },
        g.wbg.__wbindgen_object_clone_ref = function (A) {
            return Y(i(A))
        },
        g.wbg.__wbg_instanceof_Window_9029196b662bc42a = function (A) {
            var g;
            try {
                g = i(A) instanceof Window
            } catch (A) {
                console.log("t==A",A)
                g = !1
            }
            return g
        },
        g.wbg.__wbg_document_f7ace2b956f30a4f = function (A) {
            var g = i(A).document;
            return U(g) ? 0 : Y(g)
        },
        g.wbg.__wbg_location_56243dba507f472d = function (A) {
            return Y(i(A).location)
        },
        g.wbg.__wbg_host_15090f3de0544fea = function () {
            return R((function (A, g) {
                var I = L(i(g).host, w.__wbindgen_export_0, w.__wbindgen_export_1),
                    B = h;
                s()[A / 4 + 1] = B,
                    s()[A / 4 + 0] = I
            }), arguments)
        },
        g.wbg.__wbg_origin_50aa482fa6784a0a = function () {
            return R((function (A, g) {
                var I = L(i(g).origin, w.__wbindgen_export_0, w.__wbindgen_export_1),
                    B = h;
                s()[A / 4 + 1] = B,
                    s()[A / 4 + 0] = I
            }), arguments)
        },
        g.wbg.__wbg_href_d62a28e4fc1ab948 = function () {
            return R((function (A, g) {
                var I = L(i(g).href, w.__wbindgen_export_0, w.__wbindgen_export_1),
                    B = h;
                s()[A / 4 + 1] = B,
                    s()[A / 4 + 0] = I
            }), arguments)
        },
        g.wbg.__wbg_newwithargs_a0432b7780c1dfa1 = function (A, g, I, B) {
            return Y(S(K(A, g), K(I, B)))
        },
        g.wbg.__wbindgen_string_new = function (A, g) {
            return Y(K(A, g))
        },
        g.wbg.__wbg_call_01734de55d61e11d = function () {
            return R((function (A, g, I) {
                return Y(i(A).call(i(g), i(I)))
            }), arguments)
        },
        g.wbg.__wbindgen_string_get = function (A, g) {
            var I = i(g),
                B = "string" == typeof I ? I : void 0,
                Q = U(B) ? 0 : L(B, w.__wbindgen_export_0, w.__wbindgen_export_1),
                C = h;
            s()[A / 4 + 1] = C,
                s()[A / 4 + 0] = Q
        },
        g.wbg.__wbg_eval_8c72ad5eafe427f2 = function () {
            return R((function (A, g) {
                return Y(x(K(A, g)))
            }), arguments)
        },
        g.wbg.__wbindgen_typeof = function (A) {
            return Y(I(i(A)))
        },
        g.wbg.__wbindgen_boolean_get = function (A) {
            var g = i(A);
            return "boolean" == typeof g ? g ? 1 : 0 : 2
        },
        g.wbg.__wbg_new_56693dbed0c32988 = function () {
            return Y(new Map)
        },
        g.wbg.__wbg_set_bedc3d02d0f05eb0 = function (A, g, I) {
            return Y(i(A).set(i(g), i(I)))
        },
        g.wbg.__wbindgen_number_new = function (A) {
            return Y(A)
        },
        g.wbg.__wbg_new0_c0be7df4b6bd481f = function () {
            return Y(new Date)
        },
        g.wbg.__wbg_getTime_5e2054f832d82ec9 = function (A) {
            return i(A).getTime()
        },
        g.wbg.__wbg_new_cd59bfc8881f487b = function (A) {
            return Y(new Date(i(A)))
        },
        g.wbg.__wbg_getTimezoneOffset_8aee3445f323973e = function (A) {
            return i(A).getTimezoneOffset()
        },
        g.wbg.__wbindgen_throw = function (A, g) {
            throw new Error(K(A, g))
        },
        g
}

function L(A, g, I) {
    if (void 0 === I) {
        var B = y.encode(A),
            Q = g(B.length, 1) >>> 0;
        return k().subarray(Q, Q + B.length).set(B),
            h = B.length,
            Q
    }
    for (var C = A.length, E = g(C, 1) >>> 0, D = k(), w = 0; w < C; w++) {
        var M = A.charCodeAt(w);
        if (M > 127)
            break;
        D[E + w] = M
    }
    if (w !== C) {
        0 !== w && (A = A.slice(w)),
            E = I(E, C, C = w + 3 * A.length, 1) >>> 0;
        var i = k().subarray(E + w, E + C);
        E = I(E, C, w += F(A, i).written, 1) >>> 0
    }
    return h = w,
        E
}
var H = 128;
var M = new Array(128).fill(void 0);
M.push(void 0, null, !0, !1);
var o = M.length;

function encrypt(A, g, I, B, Q, C) {
    try {
        var E = L(A, w.__wbindgen_export_0, w.__wbindgen_export_1),
            D = h,
            i = L(g, w.__wbindgen_export_0, w.__wbindgen_export_1),
            o = h,
            Y = L(I, w.__wbindgen_export_0, w.__wbindgen_export_1),
            N = h,
            J = L(B, w.__wbindgen_export_0, w.__wbindgen_export_1),
            k = h,
            K = L(Q, w.__wbindgen_export_0, w.__wbindgen_export_1),
            y = h;
        return G(w.a(E, D, i, o, Y, N, J, k, K, y, function (A) {
            if (1 == H)
                throw new Error("out of js stack");
            return M[--H] = A,
                H
        }(C)))
    } finally {
        M[H++] = void 0
    }
}

/*
错误的情况(不使用 async):
function call_encrypt() {
    WebAssembly.instantiate(buffer).then(res => {
        console.log("结果打印在这里"); // 这一步在未来才会发生
    });
    // Node.js 执行到这里发现后面没代码了,会直接“关门下班”
    // 此时上面的 console.log 还没来得及跑,进程就没了
}
-------------------------------------------
function call_encrypt(A, g, I, B, Q, C){
    WebAssembly.instantiate(wasmBuffer, t()).then(
        (results) => {
            w = results.instance.exports;
            // console.log("w=", w)
            const result = encrypt(A, g, I, B, Q, C)
            console.log('result', result)
            return result
        }
    );
}
-----------------
async function call_encrypt() {
// await 的意思是:主程序在这里停一下,等 WASM 加载完了再往下走
const res = await WebAssembly.instantiate(buffer); 
const result = encrypt(...);
console.log(result); // 确保结果出来了再打印
}
*/

async function get_result(A, g, I, B, Q, C) {
    const results = await WebAssembly.instantiate(wasmBuffer, t());
    w = results.instance.exports;
    return encrypt(A, g, I, B, Q, C);
}
// 测试 res Map(6) { 'Content-Type' => 'application/json', 'X-ITOUCHTV-Ca-Timestamp' => 1767001066145, 'X-ITOUCHTV-Ca-Signature' => 'boAgv1Qvydkbh9bFp2ub2Q5ZF6qj8DJV+f1wykQc+PA=', 'X-ITOUCHTV-Ca-Key' => '89541943007407288657755311868534', 'X-ITOUCHTV-CLIENT' => 'WEB_PC', 'X-ITOUCHTV-DEVICE-ID' => 'WEB_52a60410-d643-11f0-a6fe-4fcb7e8bd931' }
// A = "POST"
// g = "https://gdtv-api.gdtv.cn/api/search/v1/news"
// I = "WEB_52a60410-d643-11f0-a6fe-4fcb7e8bd931"
// B = "WEB_PC"
// Q = '{"keyword":"纪录片","pageNum":1,"type":-1,"pageSize":15}'
// C = undefined

// result = get_result(A, g, I, B, Q, C)
// console.log('result', result.then(res => console.log('res', res)))

// 接收命令行参数并输出结果,python调用
const args = process.argv.slice(2);
get_result(args[0], args[1], args[2], args[3], args[4], undefined).then(res => {
    if (res instanceof Map) {
        // 如果是 Map 对象,先转成普通 Object 再转 JSON 字符串
        const obj = Object.fromEntries(res);
        process.stdout.write(JSON.stringify(obj));
    } else if (typeof res === 'object') {
        // 如果已经是普通对象,直接转 JSON
        process.stdout.write(JSON.stringify(res));
    } else {
        // 如果是字符串或其他,强制转字符串输出
        process.stdout.write(String(res));
    }
});

五、代码实现

Python 代码调用gdtv_keyword_search.py

import subprocess
import json
import requests


def get_wasm_encryption(method, url, device_id, platform, body):
    js_path = 'lizhi.js'  # 你的 JS 文件名
    args = ['node', js_path, method, url, device_id, platform, body]
    try:
        # 运行并捕获输出
        response = subprocess.check_output(args, stderr=subprocess.STDOUT).decode('utf-8')
        # 将 JS 返回的 JSON 字符串转为 Python 字典
        try:
            encrypt_data = json.loads(response)
            return encrypt_data
        except json.JSONDecodeError:
            return response  # 如果不是 JSON,返回原始字符串
    except subprocess.CalledProcessError as e:
        print(f"Node 调用崩溃: {e.output.decode('utf-8')}")
        return None


headers = {
    "accept": "application/json, text/plain, */*",
    "accept-language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
    "cache-control": "no-cache",
    "content-type": "application/json",
    "origin": "https://www.gdtv.cn",
    "pragma": "no-cache",
    "priority": "u=1, i",
    "referer": "https://www.gdtv.cn/",
    "sec-ch-ua": "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-site",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
    "x-itouchtv-ca-key": "89541943007407288657755311868534",
    "x-itouchtv-ca-signature": "w0xkhOEYlm9Qtga1jbS/foXg6kEAwCHezrDssv/PBbE=",
    "x-itouchtv-ca-timestamp": "1766988096294",
    "x-itouchtv-client": "WEB_PC",
    "x-itouchtv-device-id": "WEB_52a60410-d643-11f0-a6fe-4fcb7e8bd931"
}
url = "https://gdtv-api.gdtv.cn/api/search/v1/news"
data = {
    "keyword": "纪录片",
    "pageNum": 1,
    "type": -1,
    "pageSize": 15
}
data = json.dumps(data, separators=(',', ':'), ensure_ascii=False)

A = "POST"
g = "https://gdtv-api.gdtv.cn/api/search/v1/news"
I = "WEB_52a60410-d643-11f0-a6fe-4fcb7e8bd931"
B = "WEB_PC"

# 调用示例
enc_res = get_wasm_encryption(A, g, I, B, data)
print('enc_res', enc_res)
headers['x-itouchtv-ca-key'] = enc_res['X-ITOUCHTV-Ca-Key']
headers['x-itouchtv-ca-signature'] = enc_res['X-ITOUCHTV-Ca-Signature']
headers['x-itouchtv-ca-timestamp'] = str(enc_res['X-ITOUCHTV-Ca-Timestamp'])
response = requests.post(url, headers=headers, data=data)
print(response.status_code, response.text)

# 运行结果:200 {"pageNum":0,"pageSize":0,"series":null,"tvColumns":{"total":3,"list":[{"pk":983,"tvChannelPk":46,"tvChannelName":"大湾区卫视(海外版)","name":"南派纪录片","desc":null,"coverUrl":"https://img.gdtv.cn/image/202012/0.63134060122414762554df517bd3bd0f8OSS1609401331.png","updatedAt":1609401371000,"category":0,"newsList":[]},{"pk":919,"tvChannelPk":94,"tvChannelName":"纪录片","name":"纪录片精选","desc":null,"coverUrl":"https://img.gdtv.cn/image/202007/0.723672065024739220ee4d8aed36d5934OSS1593758786.jpg","updatedAt":1593758801000,"category":0,"newsList":[{"id":"22f5c2717116e5e5dbd2348d8351d9ad","title":"2025-01-22 龙舟新传","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2025/01/a1163788b681a7bf2fd250c0b621a0bb.png","contentType":3,"releasedAt":1737531371000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202502/173755881488.m3u8\"}","timeLength":1379,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"b80291bcdffcbae7a5a686a8892c8e60","title":"2025-01-16 榜样","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2025/01/f7ea9cf2c5bc07bbbf6b95e7b9138def.jpg","contentType":3,"releasedAt":1736989200000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202502/173704212150.m3u8\"}","timeLength":5440,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"20a9e96a0e9afa631147de89922f72a0","title":"赤坎华侨古镇:第二集 钟声依旧","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2024/11/d109b25bfe8cada19aba6514eed0d3af.png","contentType":3,"releasedAt":1730691400000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202411/173069140080.m3u8\"}","timeLength":1800,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"70491cdbddbaa397b7be35cb7f080812","title":"赤坎华侨古镇:第一集 风云再起","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2024/11/a0848091f5350aed68fbbe8ea526a86e.png","contentType":3,"releasedAt":1730691294000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202411/173069129423.m3u8\"}","timeLength":1800,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"8df88f7cd76a5c6800d70480203b3022","title":"2024-10-03 跨越山海 共赴未来——广东对口援藏30周年 第一集《巨变》","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2024/10/06a28fbaefd06b9db0df917c0fe3a8e7.png","contentType":3,"releasedAt":1727960700000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202410/172804766443.m3u8\"}","timeLength":2084,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"2b0734135fd415ba0455a3be1a5ffee4","title":"2024-10-17 跨越山海 共赴未来——广东对口援藏30周年 第三集《奔赴》","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2024/10/1769ca909695f1a0659cc30bda496859.png","contentType":3,"releasedAt":1729170300000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202410/172924652246.m3u8\"}","timeLength":2105,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"18ee4449f53654023d00673e08ae8b30","title":"2024-10-10 跨越山海 共赴未来——广东对口援藏30周年 第二集《相依》","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2024/10/472d72bfd7858bc86559ef4bbdf8d1d6.png","contentType":3,"releasedAt":1729242277000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202410/172924227792.m3u8\"}","timeLength":2060,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"e61d7327922cdecfb5cd71728e8aa0ab","title":"2024-09-27 广东省全民国防教育主题宣讲比赛","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2024/09/fec35c433d0e0a1290c2788f81b971a8.jpg","contentType":3,"releasedAt":1727448686000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202410/172749114560.m3u8\"}","timeLength":6574,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"ef74b7c4ccd0500f35b5753fe839c579","title":"2024-09-17 凯文·罗兰的龙舟奇遇","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2024/09/a8085bfc564e7e18416a775193c1620f.png","contentType":3,"releasedAt":1727073508000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202409/172707350827.m3u8\"}","timeLength":1410,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"9b05e75a737ffde1a48be67745dfea82","title":"2024-07-19 奋斗者的幸福:藤县狮舞的前世今生","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2024/07/3e00bcc3e7767ddc3bb053a04f085962.jpg","contentType":3,"releasedAt":1721394300000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202407/172147525028.m3u8\"}","timeLength":2392,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"1e69753db3886cf2ef9074edac1ae4e0","title":"2024-07-12 奋斗者的幸福:水围村,从1368年走来","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2024/07/cdc78c39493f8c4cb3f1a02176691888.png","contentType":3,"releasedAt":1720789500000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202407/172105500092.m3u8\"}","timeLength":2910,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"3d557df061023a7ed644990c93d45f87","title":"2024-05-25 中华白海豚(下集)","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/mediaserver/img/2024/05/e00aa95ba751c43e1f0e23e71a571cf2.jpg","contentType":3,"releasedAt":1716642300000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202502/171668948534.m3u8\"}","timeLength":3000,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"8324375f272e2afb66831c4e43caec89","title":"2024-05-24 中华白海豚(上集)","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/mediaserver/img/2024/05/7a66024707c172de71be0b0f252da7a8.jpg","contentType":3,"releasedAt":1716555900000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202502/171663458639.m3u8\"}","timeLength":3000,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"2bdfb4057039642efb19e4d0f8c10494","title":"2023-12-30  大道之行","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2024/01/0cc873fecc5a87f869ebf5e93e327653.png","contentType":3,"releasedAt":1704445969000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202401/170444596984.m3u8\"}","timeLength":918,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"effdbf1a4d0c2c1c7e4f723c5064ab7f","title":"2023-12-30 海“斯”十年","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/mediaserver/img/2024/01/71910a4c33e0f1730ad20096cd8d01f4.jpg","contentType":3,"releasedAt":1703870530000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202401/170418707172.m3u8\"}","timeLength":316,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null}]},{"pk":984,"tvChannelPk":94,"tvChannelName":"纪录片","name":"“决战脱贫攻坚 决胜全面小康”主题纪录片","desc":null,"coverUrl":"https://img.gdtv.cn/image/202012/0.16967900569574423710c159d9466e0e3dOSS1609418596.png","updatedAt":1612775573000,"category":0,"newsList":[]}]},"topics":{"total":3,"list":[{"id":"7508f77979d7afe407cc4f1effd841f5","title":"纪录片频道","coverUrl":"https://img.gdtv.cn/image/202210/0.8110101250543261292b673d7f200722faOSS1665827377.jpg","summary":"","type":1,"memberNum":0,"newsList":null},{"id":"22c4dfd9d381cf00820dde45a68a1b5c","title":"微纪录片《拾·获》","coverUrl":"https://img.gdtv.cn/image/202312/0.33787050533916063326bff7c765fdb452OSS1703149646.jpg","summary":"","type":1,"memberNum":0,"newsList":null},{"id":"79535144c9376bcac2e4173aef3bc05b","title":"微纪录片《“国宝”时刻》","coverUrl":"https://img.gdtv.cn/image/202510/0.024823453176867405218d4b3e41d3bbd69OSS1761899745.png","summary":"文物超高清影像记录工程,用视听语言讲述文物故事,用超高清技术赋能文化传承。","type":1,"memberNum":0,"newsList":null}]},"newsItems":{"total":556,"list":[{"id":"0b3dd4dcd1265869b41caa2bec6b898a","title":"2025残特奥纪录片《怒放》今日上线","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/mediaserver/img/2025/12/0788a44c1a7baa04bece4c00760483ca.jpg","contentType":3,"releasedAt":1767017760000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202512/176701816225.m3u8\"}","timeLength":31,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"7884224f199ffd133d5b5786db3f4fd0","title":"2025残特奥纪录片《怒放》今日上线","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/mediaserver/img/2025/12/9d2b8ab3487c4d02e9f58a7b24ab819f.jpg","contentType":3,"releasedAt":1767015600000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202512/176701625933.m3u8\"}","timeLength":33,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"7716f12c247beead311e84e2449308f2","title":"2025残特奥纪录片《怒放》今日上线","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/livmedia/img/2025/12/65ee5bf49aa94ff04024236119f7251d.png","contentType":3,"releasedAt":1767012600000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202512/176701310864.m3u8\"}","timeLength":33,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"3d7f27070f78a9ca9be063f10ef6065d","title":"2025残特奥会纪录片《怒放》今天上线 致敬不屈的生命之光","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/mediaserver/img/2025/12/694ad1aee6ac4291f2edd0fbc6ec2d14.jpg","contentType":3,"releasedAt":1767006900000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202512/176706022426.m3u8\"}","timeLength":100,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"7ea7f5057ba1ab00d5d315e0e1930b85","title":"2025残特奥纪录片《怒放》今日上线","titleStyle":null,"titleColor":null,"subTitle":null,"preSubTitle":null,"coverUrl":"https://img2-cloud.itouchtv.cn/tv/program/cover/b3a31b97063592f7a7163238a02c8772.jpg","contentType":3,"releasedAt":1767005700000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vfile2.grtn.cn/2025/1767/0061/1554/176700611554.ssm/176700611554.mp4\"}","timeLength":33,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"d683f3471401dac41a5c742834579b45","title":"微纪录片|一网兜住的安心","titleStyle":null,"titleColor":null,"subTitle":null,"preSubTitle":null,"coverUrl":"https://img.gdtv.cn/image/202512/0.94045148020821132152_32uko5qlr15.jpg","contentType":0,"releasedAt":1766979650000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":null,"timeLength":0,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"1bdc0df0c1ae98523d6e4ba9a9a754bf","title":"致敬不屈的生命之光!残特奥会纪录片《怒放》,12月29日、12月30日重磅上线","titleStyle":null,"titleColor":null,"subTitle":null,"preSubTitle":null,"coverUrl":"https://img.gdtv.cn/image/202512/0.702262377152849310dwxdqoEaxQIxrkKjAZzu.jpeg","contentType":0,"releasedAt":1766934965000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":null,"timeLength":0,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"4c80718f25230317cda1795e3dcf63ca","title":"央视重磅推出!残特奥会纪录片《怒放》:致敬不屈的生命之光","titleStyle":null,"titleColor":null,"subTitle":null,"preSubTitle":null,"coverUrl":"https://img.gdtv.cn/image/202512/0.04236040693436482561.jpg","contentType":1,"releasedAt":1766933546000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/video/202512/28da7de860f8ea0fOSS1766933503__hd.mp4\",\"sd\":\"https://vod.gdtv.cn/video/202512/28da7de860f8ea0fOSS1766933503__sd.mp4\",\"ud\":\"https://vod.gdtv.cn/video/202512/28da7de860f8ea0fOSS1766933503__ud.mp4\"}","timeLength":60,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"fd2fc3b302a5da75cbe2352e7c08a40b","title":"央视重磅推出!残特奥会纪录片《怒放》:致敬不屈的生命之光","titleStyle":null,"titleColor":null,"subTitle":null,"preSubTitle":null,"coverUrl":"https://img.gdtv.cn/image/202512/0.480693340973551241.jpg","contentType":0,"releasedAt":1766932920000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":null,"timeLength":0,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"04b76b45154ef01326ff26f73e620d01","title":"微纪录片|一路守望的安宁","titleStyle":null,"titleColor":null,"subTitle":null,"preSubTitle":null,"coverUrl":"https://img.gdtv.cn/image/202512/0.393541164010459626QHHCfjMbJIdYLgqeBXz2.jpeg","contentType":0,"releasedAt":1766740948000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":null,"timeLength":0,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"32929b2d95e76942458d80df34221a52","title":"岭南经纬织就文明对话,《大地云纱》纪录片全球首播开启佛山文化国际传播新叙事\n","titleStyle":null,"titleColor":null,"subTitle":null,"preSubTitle":null,"coverUrl":"https://img.gdtv.cn/image/202512/0.86977589349698921.jpg","contentType":0,"releasedAt":1766470958000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":null,"timeLength":0,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"3a461f73b52cd687acd8a3aeb4e2df57","title":"见证广东百县千镇万村精彩蝶变!纪录片《山海之变》今起播出","titleStyle":null,"titleColor":null,"subTitle":"","preSubTitle":null,"coverUrl":"https://img.grtn.cn/material/mediaserver/img/2025/12/d23eb3bf13266f7e15848645e0c298ba.jpg","contentType":3,"releasedAt":1766410680000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vod.gdtv.cn/m3u8/202512/176641141511.m3u8\"}","timeLength":35,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"001538fbb44902d26212648f6f41c0f7","title":"见证广东百县千镇万村精彩蝶变!纪录片《山海之变》12月22日起广东卫视播出","titleStyle":null,"titleColor":null,"subTitle":null,"preSubTitle":null,"coverUrl":"https://img2-cloud.itouchtv.cn/tv/program/cover/9c8d13dbebe6327792731b89487c8fee.jpg","contentType":3,"releasedAt":1766400840000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":"{\"hd\":\"https://vfile2.grtn.cn/2025/1766/4013/3376/176640133376.ssm/176640133376.mp4\"}","timeLength":34,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"60369cc5c6d4ecc335081753b7a0409b","title":"岭南经纬织就文明对话《大地云纱》纪录片全球首播 开启佛山文化国际传播新叙事","titleStyle":null,"titleColor":null,"subTitle":"——佛山传媒文旅集团视频中心倾力打造非遗影像力作,以香云纱为媒书写中国故事","preSubTitle":"\n","coverUrl":"https://img.gdtv.cn/image/202512/0.0892360377057305275770ca422f37f8b2OSS1766398389.jpg","contentType":0,"releasedAt":1766398447000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":null,"timeLength":0,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null},{"id":"9a581da4d11ad9ab45580bc3ac4d6a1f","title":"重磅纪录片|此心系文脉","titleStyle":null,"titleColor":null,"subTitle":null,"preSubTitle":null,"coverUrl":"https://img.gdtv.cn/image/202512/0.229026139712824261612_4p7p1gcva3j.png","contentType":0,"releasedAt":1766128749000,"readCount":0,"author":null,"objectType":0,"memberNum":0,"videoUrl":null,"timeLength":0,"imageCount":0,"recentVisitTime":0,"keyword":null,"serialsInfo":null,"crawlUrl":null,"newsList":null}]}}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐