2 Commits ce467112d1 ... e62137eb97

Autore SHA1 Messaggio Data
  3407802468@qq.com e62137eb97 gk airline first commit 5 mesi fa
  3407802468@qq.com ce467112d1 'first' 6 mesi fa
56 ha cambiato i file con 4848 aggiunte e 5254 eliminazioni
  1. 371 265
      3.31GK/akm/akm_5.19.js
  2. 828 0
      3.31GK/akm/akm_5.26.js
  3. 6 1
      3.31GK/akm/arg_dvc_revert_env.js
  4. 229 0
      3.31GK/akm/decrypt_sensor_data.js
  5. 198 0
      3.31GK/akm/obj_compare.js
  6. 2 2
      3.31GK/akm/parse_arguments.js
  7. 0 0
      3.31GK/akm/test.js
  8. 51 0
      3.31GK/analyse.txt
  9. 155 0
      3.31GK/ast/ast.js
  10. 3 0
      3.31GK/ast/decode.js
  11. 4 0
      3.31GK/ast/encode.js
  12. 6 0
      3.31GK/demo.py
  13. 48 0
      3.31GK/flight_date_search.py
  14. 368 0
      3.31GK/frame_code/clean_gk_flights_datas.py
  15. 668 0
      3.31GK/frame_code/gk_flights_spider.py
  16. 107 0
      3.31GK/frame_code/gk_flights_spider_que_work.py
  17. 54 0
      3.31GK/frame_code/insert_flights_gk_city_airport_codes.py
  18. 391 0
      3.31GK/frame_code/insert_flights_gk_route.py
  19. 304 0
      3.31GK/other_code/city_pair.py
  20. 18 12
      3.31GK/other_code/request_curl_cffi.py
  21. 1 1
      3.31GK/other_code/request_httpx.py
  22. 289 0
      3.31GK/other_code/request_pyhttpx.py
  23. 22 20
      3.31GK/other_code/requests_multi_thread.py
  24. 38 26
      3.31GK/other_code/response_data_parse.py
  25. 0 0
      3.31GK/other_code/控制流平坦化-状态机为变量/ast.js
  26. 0 0
      3.31GK/other_code/控制流平坦化-状态机为变量/encode.js
  27. 0 0
      3.31GK/other_code/控制流平坦化-状态机为变量/test.js
  28. 432 0
      3.31GK/req_tls_client.py
  29. 255 0
      3.31GK/request_test.py
  30. 0 85
      3.31Gk航司/akm逆向/demo.py
  31. 0 40
      3.31Gk航司/tls - ja3 指纹.py
  32. 0 8
      3.31Gk航司/其他/.idea/.gitignore
  33. 0 8
      3.31Gk航司/其他/.idea/3.31Gk航司.iml
  34. 0 38
      3.31Gk航司/其他/.idea/inspectionProfiles/Project_Default.xml
  35. 0 6
      3.31Gk航司/其他/.idea/inspectionProfiles/profiles_settings.xml
  36. 0 7
      3.31Gk航司/其他/.idea/misc.xml
  37. 0 8
      3.31Gk航司/其他/.idea/modules.xml
  38. 0 6
      3.31Gk航司/其他/1.html
  39. 0 197
      3.31Gk航司/其他/ast/ast.js
  40. 0 264
      3.31Gk航司/其他/ast/decode.js
  41. 0 59
      3.31Gk航司/其他/ast/encode.js
  42. 0 3191
      3.31Gk航司/其他/ast/收集函数加密/ast.js
  43. 0 59
      3.31Gk航司/其他/ast/收集函数加密/decode.js
  44. 0 59
      3.31Gk航司/其他/ast/收集函数加密/encode.js
  45. 0 3
      3.31Gk航司/其他/bm_sz 生成/分析
  46. 0 30
      3.31Gk航司/其他/bm_sz 生成/第一次请求akm.py
  47. 0 64
      3.31Gk航司/其他/cookie参数测试.py
  48. 0 71
      3.31Gk航司/其他/demo2.py
  49. 0 120
      3.31Gk航司/其他/html解析.py
  50. 0 3
      3.31Gk航司/其他/test.js
  51. 0 71
      3.31Gk航司/其他/verify.py
  52. 0 94
      3.31Gk航司/其他/分析.txt
  53. 0 20
      3.31Gk航司/其他/获取加密cookie.py
  54. 0 176
      3.31Gk航司/请求-requests版.py
  55. 0 168
      3.31Gk航司/请求-tls_client.py
  56. 0 72
      3.31Gk航司/请求测试.py

+ 371 - 265
3.31Gk航司/akm逆向/逆向.js → 3.31GK/akm/akm_5.19.js

@@ -7,7 +7,6 @@ navigator = {
 
 /**--------------------------------------- 加密 ajr  ------------------------------------**/
 
-
 XH = function (DV) {
     return gG.apply(this, [60, arguments]);
 }
@@ -836,275 +835,369 @@ function get_dvc(startTs, ajr) {
     window.bmak = {
         startTs: startTs
     }
-    val = arg1.Gb(0, ajr, 0, 0)
+    val = arg1.Gb(0, ajr, 0, 0)  // 这3个参数 与外面其他参数有联系, 2者保持一致 否则请求失败
     console.log('加密ajr生成的dvc => ', val)
     return val
 }
 
 /**-------------------------------------------------- 31条风控参数的生成---------------------------------------------------------------**/
-
-
-
-function getObj31(startTs) {
-
-    function get_ajr(startTimestamp) {
-        var lfv = function (Jw) {
-            var rTv = function (bxv, g8v) {
-                return bxv >>> g8v | bxv << 32 - g8v;
-            };
-            var kw = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
-            var Jl = 0x6a09e667;
-            var BXv = 0xbb67ae85;
-            var SVv = 0x3c6ef372;
-            var FCv = 0xa54ff53a;
-            var VTv = 0x510e527f;
-            var tEv = 0x9b05688c;
-            var ttv = 0x1f83d9ab;
-            var hVv = 0x5be0cd19;
-            var SUv = unescape(encodeURIComponent(Jw));
-            var hXv = SUv["length"] * 8;
-            SUv += String["fromCharCode"](0x80);
-            var Sfv = SUv["length"] / 4 + 2;
-            var pw = Math["ceil"](Sfv / 16);
-            var nfv = new (Array)(pw);
-            for (var Ol = 0; Ol < pw; Ol++) {
-                nfv[Ol] = new (Array)(16);
-                for (var fLv = 0; fLv < 16; fLv++) {
-                    nfv[Ol][fLv] = SUv["charCodeAt"](Ol * 64 + fLv * 4) << 24 | SUv["charCodeAt"](Ol * 64 + fLv * 4 + 1) << 16 | SUv["charCodeAt"](Ol * 64 + fLv * 4 + 2) << 8 | SUv["charCodeAt"](Ol * 64 + fLv * 4 + 3) << 0;
-                }
+function get_ajr(startTimestamp) {
+    var lfv = function (Jw) {
+        var rTv = function (bxv, g8v) {
+            return bxv >>> g8v | bxv << 32 - g8v;
+        };
+        var kw = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
+        var Jl = 0x6a09e667;
+        var BXv = 0xbb67ae85;
+        var SVv = 0x3c6ef372;
+        var FCv = 0xa54ff53a;
+        var VTv = 0x510e527f;
+        var tEv = 0x9b05688c;
+        var ttv = 0x1f83d9ab;
+        var hVv = 0x5be0cd19;
+        var SUv = unescape(encodeURIComponent(Jw));
+        var hXv = SUv["length"] * 8;
+        SUv += String["fromCharCode"](0x80);
+        var Sfv = SUv["length"] / 4 + 2;
+        var pw = Math["ceil"](Sfv / 16);
+        var nfv = new (Array)(pw);
+        for (var Ol = 0; Ol < pw; Ol++) {
+            nfv[Ol] = new (Array)(16);
+            for (var fLv = 0; fLv < 16; fLv++) {
+                nfv[Ol][fLv] = SUv["charCodeAt"](Ol * 64 + fLv * 4) << 24 | SUv["charCodeAt"](Ol * 64 + fLv * 4 + 1) << 16 | SUv["charCodeAt"](Ol * 64 + fLv * 4 + 2) << 8 | SUv["charCodeAt"](Ol * 64 + fLv * 4 + 3) << 0;
             }
-            var VCv = hXv / Math["pow"](2, 32);
-            nfv[pw - 1][14] = Math["floor"](VCv);
-            nfv[pw - 1][15] = hXv;
-            for (var Fbv = 0; Fbv < pw; Fbv++) {
-                var GTv = new (Array)(64);
-                var khv = Jl;
-                var jXv = BXv;
-                var Ydv = SVv;
-                var jtv = FCv;
-                var cl = VTv;
-                var Ehv = tEv;
-                var Vfv = ttv;
-                var ddv = hVv;
-                for (var Jvv = 0; Jvv < 64; Jvv++) {
-                    var qCv = void 0
-                        , lvv = void 0
-                        , Kq = void 0
-                        , vtv = void 0
-                        , Dnv = void 0
-                        , NCv = void 0;
-                    if (Jvv < 16)
-                        GTv[Jvv] = nfv[Fbv][Jvv];
-                    else {
-                        qCv = rTv(GTv[Jvv - 15], 7) ^ rTv(GTv[Jvv - 15], 18) ^ GTv[Jvv - 15] >>> 3;
-                        lvv = rTv(GTv[Jvv - 2], 17) ^ rTv(GTv[Jvv - 2], 19) ^ GTv[Jvv - 2] >>> 10;
-                        GTv[Jvv] = GTv[Jvv - 16] + qCv + GTv[Jvv - 7] + lvv;
-                    }
-                    lvv = rTv(cl, 6) ^ rTv(cl, 11) ^ rTv(cl, 25);
-                    Kq = cl & Ehv ^ ~cl & Vfv;
-                    vtv = ddv + lvv + Kq + kw[Jvv] + GTv[Jvv];
-                    qCv = rTv(khv, 2) ^ rTv(khv, 13) ^ rTv(khv, 22);
-                    Dnv = khv & jXv ^ khv & Ydv ^ jXv & Ydv;
-                    NCv = qCv + Dnv;
-                    ddv = Vfv;
-                    Vfv = Ehv;
-                    Ehv = cl;
-                    cl = jtv + vtv >>> 0;
-                    jtv = Ydv;
-                    Ydv = jXv;
-                    jXv = khv;
-                    khv = vtv + NCv >>> 0;
+        }
+        var VCv = hXv / Math["pow"](2, 32);
+        nfv[pw - 1][14] = Math["floor"](VCv);
+        nfv[pw - 1][15] = hXv;
+        for (var Fbv = 0; Fbv < pw; Fbv++) {
+            var GTv = new (Array)(64);
+            var khv = Jl;
+            var jXv = BXv;
+            var Ydv = SVv;
+            var jtv = FCv;
+            var cl = VTv;
+            var Ehv = tEv;
+            var Vfv = ttv;
+            var ddv = hVv;
+            for (var Jvv = 0; Jvv < 64; Jvv++) {
+                var qCv = void 0
+                    , lvv = void 0
+                    , Kq = void 0
+                    , vtv = void 0
+                    , Dnv = void 0
+                    , NCv = void 0;
+                if (Jvv < 16)
+                    GTv[Jvv] = nfv[Fbv][Jvv];
+                else {
+                    qCv = rTv(GTv[Jvv - 15], 7) ^ rTv(GTv[Jvv - 15], 18) ^ GTv[Jvv - 15] >>> 3;
+                    lvv = rTv(GTv[Jvv - 2], 17) ^ rTv(GTv[Jvv - 2], 19) ^ GTv[Jvv - 2] >>> 10;
+                    GTv[Jvv] = GTv[Jvv - 16] + qCv + GTv[Jvv - 7] + lvv;
                 }
-                Jl = Jl + khv;
-                BXv = BXv + jXv;
-                SVv = SVv + Ydv;
-                FCv = FCv + jtv;
-                VTv = VTv + cl;
-                tEv = tEv + Ehv;
-                ttv = ttv + Vfv;
-                hVv = hVv + ddv;
+                lvv = rTv(cl, 6) ^ rTv(cl, 11) ^ rTv(cl, 25);
+                Kq = cl & Ehv ^ ~cl & Vfv;
+                vtv = ddv + lvv + Kq + kw[Jvv] + GTv[Jvv];
+                qCv = rTv(khv, 2) ^ rTv(khv, 13) ^ rTv(khv, 22);
+                Dnv = khv & jXv ^ khv & Ydv ^ jXv & Ydv;
+                NCv = qCv + Dnv;
+                ddv = Vfv;
+                Vfv = Ehv;
+                Ehv = cl;
+                cl = jtv + vtv >>> 0;
+                jtv = Ydv;
+                Ydv = jXv;
+                jXv = khv;
+                khv = vtv + NCv >>> 0;
             }
-            return [Jl >> 24 & 0xff, Jl >> 16 & 0xff, Jl >> 8 & 0xff, Jl & 0xff, BXv >> 24 & 0xff, BXv >> 16 & 0xff, BXv >> 8 & 0xff, BXv & 0xff, SVv >> 24 & 0xff, SVv >> 16 & 0xff, SVv >> 8 & 0xff, SVv & 0xff, FCv >> 24 & 0xff, FCv >> 16 & 0xff, FCv >> 8 & 0xff, FCv & 0xff, VTv >> 24 & 0xff, VTv >> 16 & 0xff, VTv >> 8 & 0xff, VTv & 0xff, tEv >> 24 & 0xff, tEv >> 16 & 0xff, tEv >> 8 & 0xff, tEv & 0xff, ttv >> 24 & 0xff, ttv >> 16 & 0xff, ttv >> 8 & 0xff, ttv & 0xff, hVv >> 24 & 0xff, hVv >> 16 & 0xff, hVv >> 8 & 0xff, hVv & 0xff];
-        };
-        var gTv = function (RNv) {
-            return Math["floor"](Math["random"]() * RNv["length"]);
-        };
-        var Fw = function (kzv) {
-            var W3v = '';
-            for (var F6v = 0; F6v < kzv["length"]; F6v++) {
-                W3v += kzv[F6v]["toString"](16)["length"] === 2 ? kzv[F6v]["toString"](16) : "0"["concat"](kzv[F6v]["toString"](16));
+            Jl = Jl + khv;
+            BXv = BXv + jXv;
+            SVv = SVv + Ydv;
+            FCv = FCv + jtv;
+            VTv = VTv + cl;
+            tEv = tEv + Ehv;
+            ttv = ttv + Vfv;
+            hVv = hVv + ddv;
+        }
+        return [Jl >> 24 & 0xff, Jl >> 16 & 0xff, Jl >> 8 & 0xff, Jl & 0xff, BXv >> 24 & 0xff, BXv >> 16 & 0xff, BXv >> 8 & 0xff, BXv & 0xff, SVv >> 24 & 0xff, SVv >> 16 & 0xff, SVv >> 8 & 0xff, SVv & 0xff, FCv >> 24 & 0xff, FCv >> 16 & 0xff, FCv >> 8 & 0xff, FCv & 0xff, VTv >> 24 & 0xff, VTv >> 16 & 0xff, VTv >> 8 & 0xff, VTv & 0xff, tEv >> 24 & 0xff, tEv >> 16 & 0xff, tEv >> 8 & 0xff, tEv & 0xff, ttv >> 24 & 0xff, ttv >> 16 & 0xff, ttv >> 8 & 0xff, ttv & 0xff, hVv >> 24 & 0xff, hVv >> 16 & 0xff, hVv >> 8 & 0xff, hVv & 0xff];
+    };
+    var gTv = function (RNv) {
+        return Math["floor"](Math["random"]() * RNv["length"]);
+    };
+    var Fw = function (kzv) {
+        var W3v = '';
+        for (var F6v = 0; F6v < kzv["length"]; F6v++) {
+            W3v += kzv[F6v]["toString"](16)["length"] === 2 ? kzv[F6v]["toString"](16) : "0"["concat"](kzv[F6v]["toString"](16));
+        }
+        return W3v;
+    };
+    var jx = function (Hp4) {
+        var Ml4 = 0;
+        for (var Kl4 = 0; Kl4 < Hp4["length"]; Kl4++) {
+            Ml4 = Ml4 + Hp4["charCodeAt"](Kl4);
+        }
+        return Ml4;
+    };
+    var Gx = function (nD4) {
+        var pE4 = 1;
+        var hV4 = [];
+        var lV4 = Math["sqrt"](nD4);
+        while (pE4 <= lV4 && hV4["length"] < 6) {
+            if (nD4 % pE4 === 0) {
+                if (nD4 / pE4 === pE4) {
+                    hV4["push"](pE4);
+                } else {
+                    hV4["push"](pE4, nD4 / pE4);
+                }
             }
-            return W3v;
-        };
-
-        var fDv = Fw(lfv(btoa(startTimestamp)));
-        var tfv = [];
-        var dnv = "";
-        for (var XVv = 0; XVv < 5; XVv++) {
-            var Pgv = gTv(fDv);
-            tfv["push"](Pgv);
-            dnv = dnv + fDv[Pgv];
+            pE4 = pE4 + 1;
         }
-        var zCv = [dnv, tfv];
-        return zCv["join"]("|")
+        return hV4;
+    };
+
+    var fDv = Fw(lfv(btoa(startTimestamp)));
+    // console.log(fDv)
+
+    var tfv = [];
+    var dnv = "";
+    for (var XVv = 0; XVv < 5; XVv++) {
+        var Pgv = gTv(fDv);
+        tfv["push"](Pgv);
+        dnv = dnv + fDv[Pgv];
     }
+    var jz = jx(dnv);
+    var tz = Gx(jz);
 
-    function fpc(val) {
-        var TSK = function (INK) {
-            if (INK == null)
-                return -1;
-            var I8K = 0;
-            for (var IjK = 0; IjK < INK["length"]; IjK++) {
-                var UQK = INK["charCodeAt"](IjK);
-                if (UQK < 128) {
-                    I8K = I8K + UQK;
-                }
-            }
-            return I8K;
+    var zCv = [tz, tfv];
+    return zCv["join"]("|")
+}
+
+function mst(startTs, ajr) {
+    function dDd(YS) {
+        var P3 = function (ZA) {
+            var SW = ZA[0] - ZA[1];
+            var ng = ZA[2] - ZA[3];
+            var sb = ZA[4] - ZA[5];
+            var CJ = Math["sqrt"](SW * SW + ng * ng + sb * sb);
+            return Math["floor"](CJ);
         };
-        return "".concat(TSK(val));
-    }
+        var H7d = Math["floor"](Math["random"]() * 100000 + 10000);
+        var vZ = String(YS * H7d);
+        var sQd = 0;
+        var P4d = [];
+        var Ffd = vZ["length"] >= 18;
+        while (P4d["length"] < 6) {
+            P4d["push"](parseInt(vZ["slice"](sQd, sQd + 2), 10));
+            sQd = Ffd ? sQd + 3 : sQd + 2;
+        }
+        var FMd = P3(P4d);
+        return [H7d, FMd];
+    };
+
+    var dbd = dDd(startTs);
+    console.log('2arr => ', dbd)
+    let dvc = get_dvc(startTs, ajr)  // 生成 dvc 的2个入参与下面保持一致
+
+    return [
+        {
+            'kevl': 1
+        },
+        {'mevl': 32},
+        {'tevl': 32},
+        {'devl': 0},
+        {'dmvl': 0},
+        {'pevl': 0},
+        {'tovl': 0},
+        {'delt': 0},  // ----111
+        {'it': 0},
+        {'sts': startTs},
+        {'fct': -999999},  // HAd['td']
+        {'dd2': parseInt(parseInt(startTs / 4064256, 10) / 23, 10)},
+        {'kc': 0},
+        {'mc': 0},
+        {'ww8': 0},
+        {'pc': 0},
+        {'tc': 0},
+        {'ssts': 6}, // ------------111
+        {'tst': 0},
+        {'rval': '-1'}, // HAd['rVal']
+        {'rcfp': '-1'}, // HAd['rCFP']
+        {'nfas': 30261693},
+        {'jsrf': "PiZtE"},
+        {'jsrf1': dbd[0]}, //开始时间戳 计算的值  会变
+        {'jsrf2': dbd[1]},
+        {'signals': '0'},
+        {'mwd': "0"},
+        {'hea': ''},
+        {'dvc': ''['concat'](dvc, ',')['concat'](0, ',')['concat']("j+h+i+a+b+l+k+f+e+g+")},  // !!! ------------
+        {'srd': "0"}
+    ];
 
-    function get_din(startTs) {
-
-        ` **************** adp 生成过程(可写死) ***************
-    
-    var Q56 = window['callPhantom'] ? 1 : 0;                                        // 值为 0 ,  检测无头浏览器
-    var kR6 = window['ActiveXObject'] && 'ActiveXObject' in window ? 1 : 0;         // 值为 0 ,  识别 IE 浏览器(ActiveXObject 是 IE 特有的属性
-    var pW6 = typeof window['document']['documentMode'] == 'number' ? 1 : 0;        // 值为 0 ,  检测 IE 文档模式(document.documentMode 是 IE 特有属性)
-    var cc6 = window['chrome'] && window['chrome']['webstore'] ? 1 : 0;             // 值为 0 ,  检测 Chrome 浏览器
-    var UR6 = window['navigator']['onLine'] ? 1 : 0;                                // 值为 1 ,  检测网络状态,  navigator.onLine可判断浏览器是否在线
-    var mk6 = window['opera'] ? 1 : 0;                                              // 值为 0 ,  检测旧版 Opera 浏览器(opera 是旧版 Opera 特有)
-    var VZ6 = typeof window['InstallTrigger'] !== 'undefined' ? 1 : 0;              // 值为 0 ,  检测 Firefox 浏览器(InstallTrigger 是 Firefox 特有属性)
-    var rQ6 = window['HTMLElement'] && window['Object']['prototype']['toString'].call(window['HTMLElement'])['indexOf']('Constructor') > 0 ? 1 : 0;  // 值为 0 ,
-    var g36 = typeof window['RTCPeerConnection'] === 'function' || typeof window['mozRTCPeerConnection'] === 'function'  // 值为 1 , 判断浏览器是否支持 WebRTC
-    var Ng6 = 'mozInnerScreenY' in window ? window['mozInnerScreenY'] : 0;          // 值为 0 ,  检测 Firefox 特定属性
-    var OL6 = typeof window['navigator']['vibrate'] === 'function' ? 1 : 0;         // 值为 1 ,  检查设备是否支持振动
-    var Wc6 = typeof window['navigator']['getBattery'] === 'function' ? 1 : 0;      // 值为 1 ,  检查电池API支持
-    var U96 = !window['Array']['prototype']['forEach'] ? 1 : 0;                     // 值为 0 ,  检测 ES5 数组方法支持
-    var EC6 = 'FileReader' in window ? 1 : 0;                                       // 值为 1 ,  检测是否支持文件读取
-    
-    var nS6 = 'cpen:'['concat'](Q56, ',i1:')['concat'](kR6, ',dm:')['concat'](pW6, ',cwen:')['concat'](cc6, ',non:')['concat'](UR6, ',opc:')['concat'](mk6, ',fc:')['concat'](VZ6, ',sc:')['concat'](rQ6, ',wrc:')['concat'](g36, ',isc:')['concat'](Ng6, ',vib:')['concat'](OL6, ',bat:')['concat'](Wc6, ',x11:')['concat'](U96, ',x12:')['concat'](EC6);
-    `
-
-        // PMK ------------------------------------------ ran 生成 ----------------------------------------------------------
-        var ZEK = Math.random()
-        var KDK = parseInt(ZEK * 1000 / 2, 10)
-        var PMK = "".concat(ZEK).slice(0, 11) + KDK
-
-        return [
-            {"wdr": 0},                         // window.webdriver ? 1 : 0; =>  0
-            {"xag": 12147},                     // 不会js文件是不一样的  网页固定值 RcK(973, [])
-            {"asw": 1920},                      // window.screen.availWidth
-
-            {"nal": "zh-CN"},                   // navigator['language']
-            {"wow": 1920},                      // window.outerWidth
-
-            // 将时间戳 window.bmak.startTs 除以固定数值 (2016*2016)4064256,并将结果转换为十进制整数
-            {"hz1": parseInt(startTs / 4064256, 10)},
-
-            {"nps": "20030107"},                // navigator['productSub']
-            {"pha": 0},                         // window._phantom ? 1 : 0;  =>  0
-            {"ibr": 0},                         // 网页固定值
-            {"adp": "cpen:0,i1:0,dm:0,cwen:0,non:1,opc:0,fc:0,sc:0,wrc:1,isc:0,vib:1,bat:1,x11:0,x12:1"}, // SKK()
-            {"hal": startTs / 2},               // ZqK = window.bmak.startTs / 2
-            {"ucs": "8106"},                    // CCK 生成逻辑 ''.concat(TSK(navigator.userAgent))  =》 '8106'
-            {"she": 1080},                      // window.screen.height => 1080
-            {"wih": 919},                       // window.innerHeight   =>  919
-            {"ash": 1040},                      // window.screen.availHeight
-            {"dau": 0},                         // window.domAutomation ? 1 : 0; => 0
-            {"wiw": 1920},                      // window.innerWidth    => 1920  616??
-            {"nap": "Gecko"},                   // navigator['product']
-            {"npl": 5},                         // navigator['plugins']['length']
-            {"swi": 1920},                      // window.screen.width  =>
-            {"tsd": 0},                         // 网页固定值
-            {"ua": navigator.userAgent},
-            {"ran": PMK},                       // 随机值(应该可以写死)
-        ]
-    }
+}
 
-    function mst(startTs, ajr) {
-        function dDd(YS) {
-            var P3 = function (ZA) {
-                var SW = ZA[0] - ZA[1];
-                var ng = ZA[2] - ZA[3];
-                var sb = ZA[4] - ZA[5];
-                var CJ = Math["sqrt"](SW * SW + ng * ng + sb * sb);
-                return Math["floor"](CJ);
-            };
-            var H7d = Math["floor"](Math["random"]() * 100000 + 10000);
-            var vZ = String(YS * H7d);
-            var sQd = 0;
-            var P4d = [];
-            var Ffd = vZ["length"] >= 18;
-            while (P4d["length"] < 6) {
-                P4d["push"](parseInt(vZ["slice"](sQd, sQd + 2), 10));
-                sQd = Ffd ? sQd + 3 : sQd + 2;
+
+function fpc(val) {
+    var TSK = function (INK) {
+        if (INK == null)
+            return -1;
+        var I8K = 0;
+        for (var IjK = 0; IjK < INK["length"]; IjK++) {
+            var UQK = INK["charCodeAt"](IjK);
+            if (UQK < 128) {
+                I8K = I8K + UQK;
             }
-            var FMd = P3(P4d);
-            return [H7d, FMd];
-        };
+        }
+        return I8K;
+    };
+    return "".concat(TSK(val));
+}
 
-        var dbd = dDd(startTs);
-
-        let dvc = get_dvc(startTs, ajr)
-
-        return [
-            {'kevl': 1},
-            {'mevl': 32},
-            {'tevl': 32},
-            {'devl': 0},
-            {'dmvl': 0},  // 变化的
-            {'pevl': 0},
-            {'tovl': 0},  // 变化的
-            {'delt': 0},
-            {'it': 0},
-            {'sts': startTs},
-            {'fct': -999999},  // HAd['td']
-            {'dd2': parseInt(parseInt(startTs / 4064256, 10) / 23, 10)},
-            {'kc': 0},
-            {'mc': 0},
-            {'ww8': 0},
-            {'pc': 0},
-            {'tc': 0},
-            {'ssts': 0},
-            {'tst': 0},
-            {'rval': '-1'}, // HAd['rVal']
-            {'rcfp': '-1'}, // HAd['rCFP']
-            {'nfas': 30261693},
-            {'jsrf': "PiZtE"},
-            {'jsrf1': dbd[0]}, //开始时间戳 计算的值  会变
-            {'jsrf2': dbd[1]},
-            {'signals': '0'},
-            {'mwd': "0"},
-            {'hea': ''},
-            {'dvc': ''['concat'](dvc, ',')['concat'](0, ',')['concat']("i+j+g+d+k+h+f+l+")},  // 试一试能不能写死 ------------
-            {'srd': "0"}
-        ];
-    }
+function get_din(startTs) {
+    // 顺序不能乱写,要和网站一样
+
+
+    // PMK ------------------------------------------ ran 生成 ----------------------------------------------------------
+    var ZEK = Math.random()
+    var KDK = parseInt(ZEK * 1000 / 2, 10)
+    var PMK = "".concat(ZEK).slice(0, 11) + KDK
+
+    return [
+        {
+            "swi": 1920
+        },
+        {
+            "wiw": 0
+        },
+        {
+            "pha": 0
+        },
+        {
+            "asw": 1920
+        },
+        {
+            "nap": "Gecko"
+        },
+        {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"
+        },
+        {
+            "ibr": 0
+        },
+        {
+            "dau": 0
+        },
+        {
+            "ash": 1040
+        },
+        {
+            "nps": "20030107"
+        },
+        {
+            "she": 1080
+        },
+        {
+            "tsd": 0
+        },
+        {
+            "hz1": parseInt(startTs / 4064256, 10)
+        },
+        {
+            "ucs": "8106"
+        },
+        {
+            "ran": PMK
+        },
+        {
+            "xag": 11891
+        },
+        {
+            "hal": startTs / 2
+        },
+        {
+            "nal": "zh-CN"
+        },
+        {
+            "wih": 0
+        },
+
+        {
+            "npl": 5
+        },
+        {
+            "wow": 1920
+        },
+
+        {
+            "wdr": 0
+        },
+
+        {
+            "adp": "cpen:0,i1:0,dm:0,cwen:0,non:1,opc:0,fc:0,sc:0,wrc:1,isc:0,vib:1,bat:1,x11:0,x12:1"
+        },
+
+    ]
+}
+
+
+function getObj31(startTs) {
 
     // 可写死的值
-    let ver = 'CEzH4wWd3bpFHKMyH4qSK0U6W2Ueydin9l2pukTJElc=',
-        fpt = ";-1;dis;;true;true;true;-480;true;24;24;true;false;-1",
-        ajr = get_ajr(startTs),  //用到 2 次,且要一致
-        url = "https://www.jetstar.com/hk/zh/home?adults=1&children=0&flexible=1&flight-type=2&infants=0&origin=PVG&tab=1",
-        dsi = [{"get": ""}, {"set": "0"}, {"ico": "070f409b82df3bdd2f51a6415c7895353c153c47fe6dd8a0f87f3d14c46ccb2b"}, {"ift": "3"}, {"xof": "4,11,1,1,8"}, {"xot": "4,11,1,1,8"}, {"wev": "Google Inc. (Intel);wev;Google Inc. (Intel)"}, {"wre": "Google Inc. (Intel);wre;Google Inc. (Intel)"}, {"wdr": "0"}, {"iks": ""}, {"lds": "1"}, {"sst": ""}],
-        // mev 可写死, 但可能会触发验证码??
+    let ver = "DgDcH7HprZHwfUNBN4CSgeKfT7hmmQsJ4rqotwEhn7E=", // 不用和网站保持一致,但下面加密需要一致
+        fpt = ";-1;dis;,7;true;true;true;-480;true;24;24;true;false;-1",
+        ajr = get_ajr(startTs),  // 用到 2 次,且要一致 要注意,
+        url = "https://www.jetstar.com/hk/zh/home?adults=1&destination=LST&flexible=1&flight-type=1&origin=PVG&selected-departure-date=2025-06-31&tab=1",
+        dsi = [
+            {
+                "get": ""
+            },
+            {
+                "set": "0"
+            },
+            {
+                "ico": "070f409b82df3bdd2f51a6415c7895353c153c47fe6dd8a0f87f3d14c46ccb2b"
+            },
+            {
+                "ift": "3"
+            },
+            {
+                "xof": "4,5,1,1,8"
+            },
+            {
+                "xot": "4,5,1,1,8"
+            },
+            {
+                "wev": "Google Inc. (Intel);wev;Google Inc. (Intel)"
+            },
+            {
+                "wre": "Google Inc. (Intel);wre;Google Inc. (Intel)"
+            },
+            {
+                "wdr": "0"
+            },
+            {
+                "iks": ""
+            },
+            {
+                "lds": "1"
+            },
+            {
+                "sst": ""
+            }
+        ],
+        // mev 可写死
         mev = "0,1,114,1356,242;1,1,694,1351,250;2,1,783,1295,311;3,1,838,1281,331;4,1,1306,1275,333;5,1,1311,1266,333;6,1,1322,1255,333;7,1,1337,1233,337;8,1,1354,1216,340;9,1,1370,1209,340;10,1,1394,1202,340;11,1,1403,1201,340;12,1,2892,1191,340;13,1,2905,1183,340;14,1,2921,1181,339;15,1,3038,1177,338;16,1,3072,1175,336;17,1,3445,1174,336;18,1,3629,1170,336;19,1,3656,1169,336;20,1,3673,1167,337;21,1,3689,1163,338;22,1,3706,1152,338;23,1,3722,1135,338;24,1,3739,1113,328;25,1,3757,1080,302;26,1,3772,1052,281;27,1,3789,1006,251;28,1,3806,939,209;29,1,3823,865,174;30,1,3840,834,150;31,1,3857,820,141;32,1,3873,818,134;33,1,3889,818,123;34,1,3906,818,112;35,1,3922,818,103;36,1,3940,819,98;37,1,3956,820,96;38,1,4084,822,96;39,1,4106,827,105;40,1,4123,832,109;41,1,4139,843,112;42,1,4156,866,112;43,1,4173,908,105;44,1,4190,968,105;45,1,4253,1340,56;46,1,4281,1388,35;47,1,4294,1393,31;48,1,4373,1390,30;49,1,4390,1378,27;50,1,4406,1368,23;51,1,4424,1357,19;52,1,4440,1348,16;53,1,4457,1346,14;54,1,4490,1344,13;55,1,4507,1337,10;56,1,4523,1332,7;57,1,4533,1327,4;58,1,5324,1072,69;59,1,5343,1062,69;60,1,5357,1054,69;61,1,5374,1046,69;62,1,5390,1034,68;63,1,5407,1021,64;64,1,5424,1014,63;65,1,5443,1005,61;66,1,5458,994,60;67,1,5474,977,55;68,1,5491,965,51;69,1,5507,958,47;70,1,5525,950,45;71,1,5542,944,45;72,1,5557,943,45;73,3,5633,943,45,-1;74,4,5725,943,45,-1;75,2,5728,943,45,-1;76,1,8014,509,619;77,1,8021,509,622;78,1,8029,502,628;79,1,8103,447,670;80,1,8145,447,674;81,1,8156,447,675;82,1,8172,448,675;83,1,8332,449,675;84,1,8340,456,675;85,1,8348,465,672;86,1,8356,476,670;87,1,8364,487,668;88,1,8372,498,665;89,1,8380,511,658;90,1,8389,521,655;91,1,8396,530,652;92,1,8404,532,650;93,1,8414,533,649;94,1,8426,534,649;95,3,8544,534,649,-1;"
     ;
 
     return {
         "ver": ver,
         "fpt": fpt,
-        "fpc": fpc(fpt),
+        "fpc": "4542",
         "ajr": ajr,
         "din": get_din(startTs),
         "eem": "do_en,dm_en,t_en",
         "ffs": "",
-        "vev": "2,490;3,5328;2,6723;3,8541;",
+        "vev": "",
         "inf": "",
         "ajt": '0,0',   // 逆向
-
         "kev": "",
         "dme": "0,521,-1,-1,-1,-1,-1,-1,-1,-1,-1;",
         "mev": mev,
@@ -1118,7 +1211,7 @@ function getObj31(startTs) {
         "pmo": "",
         "dpw": "",
         "pac": "",
-        "per": '8',     // 逆向
+        "per": '',     // 逆向
         "dsi": dsi,
         "wsl": "2172649472,76515477,62483333,100,1,1,1,1,0,1,,,,,,0,,,1,1",
         "hls": "-1,,,1,1",
@@ -1280,26 +1373,12 @@ var vJ9 = function () {
 };
 
 
-var Mv = function (bm_sz) {
-    var CV = [8888888, 5885432];  // 第2个数字会变化
-    if (bm_sz) {
-        var vT = decodeURIComponent(bm_sz)["split"]("~");
-        if (vT["length"] >= 4) {
-            var Wl = parseInt(vT[2], 10);
-            Wl = isNaN(Wl) ? 8888888 : Wl;
-            CV[0] = Wl;
-        }
-    }
-    return CV
-};
-
-
 // 加密函数 ----------------------------------------------
 function fun1(En9, W59) {
     var UM9 = En9['split'](":")
     ;
     for (hw9 = 0; hw9 < UM9["length"]; hw9++) {
-        hj9 = (W59 >> 8 & 65535) % 115;
+        hj9 = (W59 >> 8 & 65535) % UM9['length'];
         W59 *= 65793;
         W59 &= 4294967295;
         W59 += 4282663;
@@ -1345,11 +1424,10 @@ function fun2(Ig, Bx) {
     return tv
 }
 
-var startTs = Date.now()
-
 
-function encrypt1() {
-    MZN = [8888888, 4725438]  // 第一次获取bmsz 没有cookie
+function encrypt1(startTs) {
+   // 第2个数字会变化,但第一次请求无所谓/不校验参数,主要是第2次
+    MZN = [8888888, 1531122]  // 第一次获取bmsz 没有cookie
 
     args = getObj31(startTs);
     U19 = JSON["stringify"](args);   // 第1次生成: 将指纹对象转json字符串
@@ -1357,7 +1435,7 @@ function encrypt1() {
     U19 = fun2(U19, MZN[0])          // 第3次生成: 第一次请求获取响应 bm_sz 时,数字是 8888888; 第二次请求时,数字是从 bm_sz 提取的
 
     var GK9 = "5,23,0,0,1,37";
-    ver = 'CEzH4wWd3bpFHKMyH4qSK0U6W2Ueydin9l2pukTJElc='
+    ver = "k3IcpyOXkyy0a/iK4ZqHj7pAozOO2DxZ/6UxfQmjQlc="
     var wC9 = `3;0;1;0;8888888;${ver}`;  // 写死
 
 
@@ -1366,7 +1444,22 @@ function encrypt1() {
     return U19
 }
 
-function encrypt2(bm_sz) {
+var Mv = function (bm_sz) {
+    // var CV = [8888888, 3978328];
+    var CV = [8888888, 1531122];  // 第2个数字会变化,  这个要和网页保持一致
+    if (bm_sz) {
+        var vT = decodeURIComponent(bm_sz)["split"]("~");
+        if (vT["length"] >= 4) {
+            var Wl = parseInt(vT[2], 10);
+            Wl = isNaN(Wl) ? 8888888 : Wl;
+            CV[0] = Wl;
+        }
+    }
+    return CV
+};
+
+function encrypt2(startTs, bm_sz) {
+    // ver 这个不可以写死 要网页保持一致
 
     MZN = Mv(bm_sz);  // 根据cookie bm_sz 动态生成 加密数字数组
 
@@ -1381,8 +1474,9 @@ function encrypt2(bm_sz) {
 
     // lE() BB DN9 PC9 是时间戳差值, mP是变化的数字,  参考最终输出结果: 36,82,0,0,2,561
     // var GK9 = '36,82,0,0,2,252';
-    var GK9 = "43,0,0,0,0,0"; // 时间戳差值
-    var wC9 = `3;0;1;0;${MZN[0]};CEzH4wWd3bpFHKMyH4qSK0U6W2Ueydin9l2pukTJElc=`;  // 写死
+    var GK9 = "58,0,0,0,0,0"; // 时间戳差值  不能写死 要写活  否则依然不返回数据
+
+    var wC9 = `3;0;1;0;${MZN[0]};k3IcpyOXkyy0a/iK4ZqHj7pAozOO2DxZ/6UxfQmjQlc=`;  // 写死
 
 
     U19 = ''.concat(wC9, ';')['concat'](GK9, ';')['concat'](U19);   // 4
@@ -1391,6 +1485,18 @@ function encrypt2(bm_sz) {
     return U19
 }
 
-bmsz = "94AB9BB58EBF3F381F6802C6E29DB66D~YAAQHWrRF7nppKaWAQAArrDlqRusyqLPBJpje5/eaQ+MRilUiqUFvEe7WhtGff1u+Bh5a2sNnYN7ZTYQ1Yo/EfkFGWr8/990MI90zpdU1pw6VgBDFy92/gi7o/d+brBbDE61NcpIHVdat/JMVq1SSg9fBH4XWJuDafxzIHGFP1zss5rjB1V5chVqCUSDo4aqTCMYxIZHQlCIVYOsiqmeDQGCFAzRdVxalnFomDAGSxgwuUoQkGx51/lCrmlL09cStbM8DDV9Xocmn/Tm99nMaGtZKQlELumhsYMU1wCC2S2inmoKEgVABwBPGnorq+TRRINMrOGym0In78QEW5mJU9uJCbEX0EBf0yExof0tdnVtgaizkNQMFSe1mJShRPRaM2rnjJ2MpI51nsq33WwTs08uDWwb0zDLqvozPw==~3425078~4407875"
+bmsz = "4CAD10423F8A35B6E37F51EF1EEA6CA7~YAAQEmrRF5FUTsCWAQAA9BeIzRtrxbcezduYhT1TRRNIfjTKoAtMCD9F7IvB4nK3P+pZ5fJfR7NBJEGBRsCI2oKcCeL7g7d4jx9h1DqkGoija9qzmkJTE+gaZa7kDP/EYWEQ+Nr/zW1c4U8S/mLJ2EfbvWbdxnTtYXrOReVr1KnMiP+7uHVxj/zfdFeqxD2piq4KO7F+0BEiS8HglrAU40ooD9+aRaDddwRgdXhFiZnM1wPR87X0W/HyCXO/PQGqSZlXJmx68HEeB27tuuc8829uLtSqE4CnbhNHCwBi62NQrarM1EOVWj4tbX4YwPJrjn453r8ctG32XBaYxa7PPvRGG0TMhRA7gmoAllM=~3752496~3750214"
+encrypt2(1747203574683, bmsz)
+
+
+// console.log(get_din(1747635578956))
+
+
+window.bmak = {
+    startTs: 1747644658226
+}
+// console.log(arg1.Gb(194677, "1,669,3,223|11,35,55,50,17,20,44,60,63,30", 0, 4835188))
+
 
-encrypt2(bmsz)
+// console.log(getObj31(1747723568540));
+console.log(mst(1748247821448))

File diff suppressed because it is too large
+ 828 - 0
3.31GK/akm/akm_5.26.js


+ 6 - 1
3.31Gk航司/akm逆向/扣算法2.js → 3.31GK/akm/arg_dvc_revert_env.js

@@ -851,5 +851,10 @@ function encrypt(startTs, ajr) {
     return val
 }
 
-encrypt(1746598767024, "c7903|49,25,26,15,37")
+// encrypt(1746598767024, "c7903|49,25,26,15,37")
+
+window.bmak = {
+        startTs: 1747035271519
+    }
+console.log(arg1.Gb(1557393, "1,650,2,325,5,130|16,9,62,55,0,40,32,37,22,38", 11, 30301659))
 

+ 229 - 0
3.31GK/akm/decrypt_sensor_data.js

@@ -0,0 +1,229 @@
+// 解密 sensor_data 值的密文部分 --------------------
+
+
+dec = '"QBkFI91H;-p!E9Do85,f+i/Z%l^-c!a0d/(e.t<fPL:FL;TJYYP0KvDo<2v[5^8k"i"_)K"m"FZ#qfX#wri6D$ju&dWL3)sWNgo! E3X<Bc66$B2.A44c"N"<x?"<+tUPyZAXy)Y6`8}o0q"A>D"h_U"^Aa"v"iifq"6yC"R&[")56DLNH`PZ)"wv[-":"d+w0M@"BZh"!qz"r3:ny")>"&""x"D|B"+", #dIZyfMRIz7c"9Wj"vUD"E9bmYor"(1"_CqDQ"wy"*Eu<h$]`rkM 5tca2!"+9V"/"f"<:r"2dv"K}H#}@x!@"D("n"Ae"7"{zs"&"","M$_"6"$"S(T"3G"]"~"Tx2"B1%"]""j".nW";R%E_"R3U"z&-cu"Y+8R"v"EWHkB;CAkR8+9VRd"3"r9X"fJh-Ooe]Dr"u7`"K""l"v+k"9""M"W$D"-=k.L"<$z~"%G)Fh[Lvr*"btb"q":X"f"S6Q"W""$"(g-"90sWSG&Tz*e>`f"@%h"M+@xy"{X!"7"o} rx"lN%"<(3"{""Z"WJ}"R""e"Ul"`hKQ<F-"Z5^"G/5^%":tw]"8"5DE7c(lQ"2J7"#6 "U""X$8"29c"}l7 6"H;"gI7=33JB"G%)">3zNe"2/1"q""3"iVg"7"C^_p~W""E"L#:"1P9{%nb`J"n=j"LuA0|9FMT$)6w-t,7G?GAE0wIp+nUg]p3XF=dneq}YhmijU/DQN@/4dEVIfB:xM:=~<O;[fEw*EPL/a.9F%XbP=D[GN-{e2HyS7nGg%KxO^&~LlT*2H).%>.^fvotP{&GvV"e"3a0"H]oY9<2;#mf"w{KO"7"Fke#wf!3Lo^zd&O`FwyslaQ4fm.<el=-2fSRrN.~pfnt%#!"JGA"%{e"M"r.gB^"0A["{x4"[v^*y;"t>I;"pgBwo"5%-">SAJi"7)o&"Y""f"Q~@"x@cxj"0]"|"5_-%._6dp4f1y;+|RAq>S(nz-0UfJbvD%h86*hfrt=|C}mD1(j{v5U?+87d#My.QB[-mx@}<K92A##t4kyx[b|Vi|-g)q:,];QUq7os!dA rUVH"z*S"0SB"z!Jy["qM9W"p.lM)O3flQbP_O* R"yl,"k<qg>7uf5v,JDHMwX",t<"XGK]`oCpSy f#Y"%ic2v7aXPwC3*"z"y/ "A Tz{eES"n[D"["?"4"H?x"c""R"Ums"6"S#+"V"S4F"V"4"`9P"`5a"o"#H"Usy"XzMs"~<2PeH|qmcW/G[a"_iku>"z"Ni1]D|_>LuBY;gBADi,cwRgE`6SDYY<cma]: [t-bo<9B@X$l)Y=w9 hyS%H2.%H"=(NM7:]<"e}E"oh(z{H=T"W.J"?I"7T%"|(m:_t@qgu!"OM["E""*"xrz","$H".sp"kW~I"Y[U[u6j,-B,}QxqFw|"fKzG"z.82#"yrLd"f""@zu"em=",!+Z{".AF"k""6"U}|"c`0"ZnG"<~)f4*0N"<ZT"Jr9a("*O3"Pw)Ar6"-3TVJ1l"F"TFvw+".%3"f{Q&L"}""."lLr"a.-"orJu"'
+
+arr = [3359553, 1111998]
+console.log(decrypt(dec, arr))
+
+
+function decrypt(dec, num_arr) {
+    // mU 和 Dz:加密函数中使用的映射数组。
+    var mU = [
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            -1,
+            0,
+            1,
+            -1,
+            2,
+            3,
+            4,
+            5,
+            -1,
+            6,
+            7,
+            8,
+            9,
+            10,
+            11,
+            12,
+            13,
+            14,
+            15,
+            16,
+            17,
+            18,
+            19,
+            20,
+            21,
+            22,
+            23,
+            24,
+            25,
+            26,
+            27,
+            28,
+            29,
+            30,
+            31,
+            32,
+            33,
+            34,
+            35,
+            36,
+            37,
+            38,
+            39,
+            40,
+            41,
+            42,
+            43,
+            44,
+            45,
+            46,
+            47,
+            48,
+            49,
+            50,
+            51,
+            52,
+            53,
+            54,
+            55,
+            56,
+            57,
+            -1,
+            58,
+            59,
+            60,
+            61,
+            62,
+            63,
+            64,
+            65,
+            66,
+            67,
+            68,
+            69,
+            70,
+            71,
+            72,
+            73,
+            74,
+            75,
+            76,
+            77,
+            78,
+            79,
+            80,
+            81,
+            82,
+            83,
+            84,
+            85,
+            86,
+            87,
+            88,
+            89,
+            90,
+            91
+        ],
+        Dz = " !#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~"
+
+
+    function reverseFun1(bF9, num) {
+        // 将加密后的字符串拆分为数组
+        const UM9Reversed = bF9.split(':');
+        const n = UM9Reversed.length;
+
+        // 模拟加密过程,记录所有交换对
+        const swapPairs = [];
+        let currentW59 = num;
+
+        for (let hw9 = 0; hw9 < n; hw9++) {
+            // 计算第一个索引 hj9
+            const hj9 = (currentW59 >> 8 & 0xFFFF) % n;
+
+            // 第一次更新 W59
+            currentW59 = (currentW59 * 65793) & 0xFFFFFFFF;
+            currentW59 += 4282663;
+            currentW59 &= 0x7FFFFF; // 8388607 是 23 位掩码
+
+            // 计算第二个索引 JO9
+            const JO9 = (currentW59 >> 8 & 0xFFFF) % n;
+
+            // 记录交换对
+            swapPairs.push({hj9, JO9});
+
+            // 第二次更新 W59
+            currentW59 = (currentW59 * 65793) & 0xFFFFFFFF;
+            currentW59 += 4282663;
+            currentW59 &= 0x7FFFFF;
+        }
+
+        // 逆序交换对并执行交换
+        swapPairs.reverse().forEach(({hj9, JO9}) => {
+            // 交换元素还原
+            const temp = UM9Reversed[hj9];
+            UM9Reversed[hj9] = UM9Reversed[JO9];
+            UM9Reversed[JO9] = temp;
+        });
+
+        // 拼接为原始字符串
+        return UM9Reversed.join(':');
+    }
+
+    function reverseFun2(tv, BxInitial) {
+        let Ig = '';
+        const L = Dz.length;
+        let currentBx = BxInitial;
+        for (let sm = 0; sm < tv.length; sm++) {
+            const c = tv.charAt(sm);
+            // 计算当前tE和UE
+            const tE = (currentBx >> 8) & 0xFFFF;
+            const UE = tE % L;
+            // 更新Bx为下一次迭代
+            currentBx = (currentBx * 65793) & 0xFFFFFFFF;
+            currentBx += 4282663;
+            currentBx &= 0x7FFFFF; // 保留23位
+
+            // 处理当前字符
+            const k = Dz.indexOf(c);
+            if (k === -1) {
+                Ig += c;
+                continue;
+            }
+
+            let pz = (k - UE) % L;
+            if (pz < 0) pz += L;
+
+            // 查找所有可能的Ad(32~126)
+            let found = false;
+            for (let Ad = 32; Ad < 127; Ad++) {
+                if (mU[Ad] === pz) {
+                    Ig += String.fromCharCode(Ad);
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) Ig += c; // 未找到,保留原字符
+        }
+        return Ig;
+    }
+
+    let dec1 = reverseFun2(dec, num_arr[0])
+    // console.log(a)
+    return reverseFun1(dec1, num_arr[1])
+}
+
+

+ 198 - 0
3.31GK/akm/obj_compare.js

@@ -0,0 +1,198 @@
+function isEqual(obj1, obj2) {
+    const keys1 = Object.keys(obj1);
+    const keys2 = Object.keys(obj2);
+
+    if (keys1.length !== keys2.length) return false;
+
+    for (const key of keys1) {
+        // if (Array.isArray(obj1[key])) {
+        //     compareArrays(obj1[key], obj2[key])
+        // } else {
+            if (obj1[key] !== obj2[key]) {
+                console.log(key)
+
+            }
+        // }
+        ;
+    }
+
+    return true;
+}
+
+
+function compareArrays(oldArray, newArray) {
+    const oldMap = new Map(oldArray.map(item => [item.id, item]));
+    const newMap = new Map(newArray.map(item => [item.id, item]));
+
+    const added = newArray.filter(item => !oldMap.has(item.id));
+    const deleted = oldArray.filter(item => !newMap.has(item.id));
+
+    const modified = [];
+    for (const newItem of newArray) {
+        const oldItem = oldMap.get(newItem.id);
+        if (oldItem) {
+            const changes = {};
+            let hasChange = false;
+            for (const key in newItem) {
+                if (!Object.is(newItem[key], oldItem[key])) {
+                    changes[key] = {old: oldItem[key], new: newItem[key]};
+                    hasChange = true;
+                }
+            }
+            if (hasChange) {
+                modified.push({id: newItem.id, changes});
+            }
+        }
+    }
+
+    console.log('新增:', added);
+    console.log('删除:', deleted);
+    console.log('修改:', modified);
+    return {added, deleted, modified};
+}
+
+obj1 =[
+    {
+        "swi": 1920
+    },
+    {
+        "wiw": 804
+    },
+    {
+        "pha": 0
+    },
+    {
+        "asw": 1920
+    },
+    {
+        "nap": "Gecko"
+    },
+    {
+        "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"
+    },
+    {
+        "ibr": 0
+    },
+    {
+        "dau": 0
+    },
+    {
+        "ash": 1040
+    },
+    {
+        "nps": "20030107"
+    },
+    {
+        "she": 1080
+    },
+    {
+        "tsd": 0
+    },
+    {
+        "hz1": 429998
+    },
+    {
+        "ucs": "8106"
+    },
+    {
+        "ran": "0.17157431385"
+    },
+    {
+        "xag": 12147
+    },
+    {
+        "hal": 873811374209
+    },
+    {
+        "nal": "zh-CN"
+    },
+    {
+        "wih": 919
+    },
+    {
+        "npl": 5
+    },
+    {
+        "wow": 1920
+    },
+    {
+        "wdr": 0
+    },
+    {
+        "adp": "cpen:0,i1:0,dm:0,cwen:0,non:1,opc:0,fc:0,sc:0,wrc:1,isc:0,vib:1,bat:1,x11:0,x12:1"
+    }
+]
+obj2 = [
+        {
+            "asw": 1920
+        },
+        {
+            "npl": 5
+        },
+        {
+            "nap": "Gecko"
+        },
+        {
+            "ucs": "8106"
+        },
+        {
+            "wiw": 0
+        },
+        {
+            "swi": 1920
+        },
+        {
+            "nal": "zh-CN"
+        },
+        {
+            "dau": 0
+        },
+        {
+            "pha": 0
+        },
+        {
+            "wdr": 0
+        },
+        {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"
+        },
+        {
+            "adp": "cpen:0,i1:0,dm:0,cwen:0,non:1,opc:0,fc:0,sc:0,wrc:1,isc:0,vib:1,bat:1,x11:0,x12:1"
+        },
+        {
+            "ibr": 0
+        },
+        {
+            "wih": 0
+        },
+        {
+            "hz1": 429875  //
+        },
+        {
+            "xag": 11891
+        },
+        {
+            "hal": 873562480929
+        },
+        {
+            "ash": 1040
+        },
+        {
+            "she": 1080
+        },
+        {
+            "tsd": 0
+        },
+        {
+            "ran": "0.0113193795"
+        },
+        {
+            "nps": "20030107"
+        },
+        {
+            "wow": 1920
+        }
+    ]
+
+
+isEqual(obj1, obj2)

+ 2 - 2
3.31Gk航司/akm逆向/分析.js → 3.31GK/akm/parse_arguments.js

@@ -45,7 +45,7 @@ function getObj() {
         "doe": "0,522,-1,-1,-1;",                                  // 可写死
         "pur": url,                                                // 可写死 网页url 不能有反斜杠 \ 和双引号 "    示例值:
 
-        "mst": mst(startTs, ajr),                                                                         //   数组:30位  -------------------------分析
+        "mst": mst(startTs, ajr),                                                                         //   数组:30位  -------------------------analyse.txt
 
         "o9": 0,                        // 可写死, 网页固定值
         "sde": "0,0,0,0,1,0,0",         // 可写死
@@ -260,7 +260,7 @@ function mst(startTs, ajr) {
     var Bmd = Date.now() - startTs;
 
     // window.bmak.startTs = startTs
-    require('./扣算法2')
+    require('./arg_dvc_revert_env')
 
     var dbd = dDd(startTs);
     console.log('ajr', ajr)

+ 0 - 0
3.31Gk航司/akm逆向/test.js → 3.31GK/akm/test.js


+ 51 - 0
3.31Gk航司/分析 → 3.31GK/analyse.txt

@@ -1,7 +1,17 @@
+
+加密参数:
+    bmsz cookie
+    同一个 bmsz 最多请求 4 次,第5次就报 (92) HTTP/2 stream 3 was not closed cleanly 错误
+
+
 第一次请求获取 bmsz  响应{"success": false}  可以不带任何参数。。不严格
 第二次携带bmsz 请求响应为{"success": true}  (响应只有一个abck) 才表示验证逻辑没问题,
     但并没有通过风控验证(可能是指纹不对, 通过风控后才能请求数据)
 
+mt
+
+
+
 
 
 替换js时,只能替换当前最新的js文件, 用旧文件(如前一天)用作替换文件时,不会生效
@@ -48,5 +58,46 @@
             dvc
         vev
         wsl
+        极道万岁!!!
+
+
+// din 参数顺序不能乱,要和网站保持一致
+
+
+
+机场城市信息接口
+
+    https://digitalapi.jetstar.com/v1/resource/flight-search-options  这个是
+    https://digitalapi.jetstar.com/v1/resource/airports-and-terminals  这个接口不是
+
+新ip要过验证码?  => ja3 切换的太频繁的话会一直出发验证码
+
+
+
+响应数据在 html的   <script type="application/json" id="bundle-data-v2"  文件中
+
+
+清洗
+    票价是根据经济舱 和商务舱的余票数 显示的,网页上显示的就是提取出来的票数
+    只不过不同的服务包票价 的余票都指向 同一个余票
+    网页显示的都是经济舱的不同票价服务包
+    商务舱 暂时没看到有余票的  观察一次如果商务舱有余票,网站也没上是否会显示商务舱票价与其对于票数
+
+
+抓取规则
+    抓个最低不带行李的价格再抓一个最低带行李的就行
+
+
+
+同样的参数,同样的加密 浏览器能过, py过不了  // 自己制造的问题
+
+
+
+余票
+运营航班号 和航班号一样
+航站楼  不用理会
+税金 提取  同一航班 一样
 
 
+线上跑不起来的原因:
+    一共提取 563个 ja3-string 有三百多个都是重复的

+ 155 - 0
3.31GK/ast/ast.js

@@ -0,0 +1,155 @@
+const fs = require('fs')
+const parser = require('@babel/parser') // 解析 JavaScript 代码
+const traverse = require('@babel/traverse').default // 遍历 AST
+const generator = require('@babel/generator').default // 生成代码
+const t = require('@babel/types')
+
+
+// 定义文件路径
+const input_js = './encode.js'
+const output_js = './decode.js'
+
+// 读取文件内容并解析成 AST
+const js_code = fs.readFileSync(input_js, {encoding: 'utf-8'})
+
+
+const ast = parser.parse(js_code)  // 解析代码为 AST
+
+// ------ 得出来 3元表达式
+// 只获取指纹数组的代码,全部获取还原后并不准确
+// 查找所有 lA()[Sr(l2)](rs, U3, pb)  和  Zb()[G9(Yx)].apply(null, [cg, N9])
+encode = {}
+const visitor_call = {
+    ConditionalExpression(path) {
+        js = path.toString()
+        encode[js] = null;
+
+    },
+    CallExpression(path) {
+        // 检查是否在三元表达式内部
+        const isInsideTernary = path.findParent(p =>
+            p.isConditionalExpression()
+        );
+        if (isInsideTernary) return;
+
+        let {callee,} = path.node
+        // let argumentsPathList = path.get('arguments')
+        if (!t.isMemberExpression(callee)) return;
+
+
+        // 匹配2种混淆表达式
+        let {object, property} = callee
+        if (!t.isCallExpression(object) && !t.isMemberExpression(object)) return;
+
+        // 处理 参数中有 三元表达式的(没必要)
+        // argumentsPathList.forEach(argPath => {
+        //     argPath.traverse({
+        //         ConditionalExpression(innerPath) {
+        //             js = innerPath.toString()
+        //             console.log('找到条件表达式完', js)
+        //         }
+        //     })
+        // })
+
+        // 更细节的处理
+        if (t.isCallExpression(object) && t.isIdentifier(object.callee) && object.arguments.length === 0) {
+            js = path.toString()
+            encode[js] = null; // 要设置值为 null 否则转 json字符串时会无值,因为值为 undefind 的json转不了
+        }
+        if (t.isMemberExpression(object) && t.isIdentifier(property)) {
+            // 跳过嵌套的成员表达式 只还原这种 Zb()[G9(Yx)].apply(null, [cg, N9])
+            if (!t.isCallExpression(object.object)) return;
+
+            js = path.toString()
+            encode[js] = null;
+
+        }
+
+
+        // if(!t.isCallExpression(object) || !t.isMemberExpression(object)) return;
+        //
+        // if(!) return;
+
+
+        // encode.push({key: js})
+
+    },
+    Program: {
+        exit() {
+            // console.log(encode)
+            const jsonData = JSON.stringify(encode);
+            console.log(jsonData); // 输出 JSON 字符串
+        }
+    }
+};
+
+decode = {
+    "zK()[GQ(fp)](d5, X0)": "Object",
+    "RP(typeof RT()[N5(Sj)], 'undefined') ? RT()[N5(xQ)].call(null, EN, BX7, Z2, OR) : RT()[N5(JI)](pN, tH7, QG, CF)": "keys",
+    "HR(typeof pQ()[vP(b5)], 'undefined') ? pQ()[vP(TN)].apply(null, [jK, jc, B0, YU]) : pQ()[vP(OR)](DA7, Pd, cW, EN)": "map"
+}
+const visitor2 = {
+    CallExpression(path) {
+        let {callee,} = path.node
+        // let argumentsPathList = path.get('arguments')
+        if (!t.isMemberExpression(callee)) return;
+
+        // 匹配2种混淆表达式
+        let {object, property} = callee
+        if (!t.isCallExpression(object) && !t.isMemberExpression(object)) return;
+
+                // console.log(path.toString())
+
+        // 更细节的处理
+        if (t.isCallExpression(object) && t.isIdentifier(object.callee) && object.arguments.length === 0) {
+            js = path.toString()
+            if (decode[js] !== null) {
+                value = decode[js]
+                console.log(js, '=>', value)
+                path.replaceWith(t.valueToNode(value))
+            }
+
+
+        }
+        if (t.isMemberExpression(object) && t.isIdentifier(property)) {
+            // 跳过嵌套的成员表达式 只还原这种 Zb()[G9(Yx)].apply(null, [cg, N9])
+            if (!t.isCallExpression(object.object)) return;
+
+            js = path.toString()
+            // try {
+            if (decode[js] !== null) {
+                value = decode[js]
+                console.log(js, '=>', value)
+                path.replaceWith(t.valueToNode(value))
+            }
+            // } catch (e) {
+            //     console.log(e)
+            // }
+
+
+        }
+
+    },
+    ConditionalExpression(path) {
+        js = path.toString()
+        if (decode[js] !== null) {
+            value = decode[js]
+            console.log(js, '=>', value)
+            path.replaceWith(t.valueToNode(value))
+        }
+
+    }
+
+};
+
+// traverse(ast, visitor_call)  // 获取混淆的表达式
+traverse(ast, visitor2)   // 还原
+
+
+// 使用 Babel 生成新的代码
+let {code} = generator(ast)
+
+
+// 将生成的代码写入指定的文件
+fs.writeFile(output_js, code, (err) => {
+})

+ 3 - 0
3.31GK/ast/decode.js

@@ -0,0 +1,3 @@
+hA7 = V6["Object"]["keys"](j77)["map"](function (fC7) {
+  j77[fC7];
+})[EN];

+ 4 - 0
3.31GK/ast/encode.js

@@ -0,0 +1,4 @@
+
+                 hA7 = V6[zK()[GQ(fp)](d5, X0)][RP(typeof RT()[N5(Sj)], 'undefined') ? RT()[N5(xQ)].call(null, EN, BX7, Z2, OR) : RT()[N5(JI)](pN, tH7, QG, CF)](j77)[HR(typeof pQ()[vP(b5)], 'undefined') ? pQ()[vP(TN)].apply(null, [jK, jc, B0, YU]) : pQ()[vP(OR)](DA7, Pd, cW, EN)](function (fC7) {j77[fC7];
+                })[EN];
+

+ 6 - 0
3.31GK/demo.py

@@ -0,0 +1,6 @@
+# 提取网站源数据
+inner_data = find_info_data.get('inner_data')
+
+# 取gk航班
+flights = inner_data.get('Trips', [])[0].get("Flights", [])
+

+ 48 - 0
3.31GK/flight_date_search.py

@@ -0,0 +1,48 @@
+import requests
+
+
+headers = {
+    "accept": "application/json, text/plain, */*",
+    "accept-language": "zh-CN,zh;q=0.9",
+    "cache-control": "no-cache",
+    "culture": "zh-HK",
+    "origin": "https://www.jetstar.com",
+    "pragma": "no-cache",
+    "priority": "u=1, i",
+    "referer": "https://www.jetstar.com/",
+    "sec-ch-ua": "\"Google Chrome\";v=\"135\", \"Not-A.Brand\";v=\"8\", \"Chromium\";v=\"135\"",
+    "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/135.0.0.0 Safari/537.36"
+}
+
+def search_flight_date():
+    """查询航班日期, 即那天有航班"""
+    url = "https://digitalapi.jetstar.com/v1/farecache/flights/batch/availability-with-fareclasses"
+    params = {
+        "flightCount": "1",
+        "includeSoldOut": "true",
+        "requestType": "StarterOnly",
+        "from": "2025-05-26",  # 采集开始时间
+        "end": "2025-05-27",   # 采集结束时间,可随意写
+        "departures": "CTS",
+        "arrivals": "KOJ",
+        "direction": "outbound",
+        "paxCount": "1",
+        "includeFees": "false"
+    }
+    response = requests.get(url, headers=headers, params=params, verify=False)
+    response.raise_for_status()
+    print(response.json())
+    # for i in response.json():
+    #     print(i)
+    json_data = response.json()[0]['routes']
+    for key, val in json_data.items():
+        flight_dates = list(val.get('flights', {}).keys())
+        print(f'航段: {key} 对应有航班的日期为: {flight_dates}')
+
+
+search_flight_date()

+ 368 - 0
3.31GK/frame_code/clean_gk_flights_datas.py

@@ -0,0 +1,368 @@
+import re
+import time
+import queue
+import threading
+from datetime import datetime
+
+from bson.objectid import ObjectId
+from my_logger import Logger
+from flights_mongodb import mongo_con_parse
+from flights_utils import time_format_conversion, get_now_time, put_data_by_queue, get_data_by_queue
+from settings import CRAWL_DATE_CONF_STATUS_TAB
+from yz_clean_utils import delete_mongodb_clean_datas, save_mongodb_clean_datas, \
+    get_city_code, format_pc_kg_data
+import json
+
+lock = threading.Lock()
+
+
+def convert_time_format(input_str):
+    """"2025年5月30日 (週五) 下午3:35 => 20250530153500 """
+    # 移除括號內的星期信息(如 "週五")
+    cleaned_str = re.sub(r'\s*\(.*?\)', '', input_str)
+
+    # 將中文上午/下午轉換為 AM/PM 標記
+    cleaned_str = cleaned_str.replace("上午", "AM").replace("下午", "PM")
+
+    # 解析日期時間
+    dt = datetime.strptime(cleaned_str, "%Y年%m月%d日 %p%I:%M")
+
+    # 格式化為目標格式,並補齊秒數 (00)
+    return dt.strftime("%Y%m%d%H%M%S")
+
+
+class CleanGKDatas():
+
+    def __init__(self):
+        self.website = "gk"
+        self.logger = Logger('./logs/{}_flights_clear.log'.format(self.website), 'debug').logger
+        self.db = mongo_con_parse()
+        self.info_tab = "flights_{}_info_tab".format(self.website)
+        self.clean_info_tab = "clean_{}".format(self.info_tab)
+        self.thread_numbers = 1
+        self.task_queue = queue.Queue()
+        self.count = 0
+
+    def processing_data_one_search(self, find_info_data, thread_number=0, verify_flag=False):
+        # global has_baggage, baggage
+        from_airport_code = ''
+        to_airport_code = ''
+        search_date = ''
+        end_flight_datas = []
+        try:
+            # print(find_info_data)
+            # 每一次搜索
+            from_city_code = find_info_data.get("search_from_city_code")
+            to_city_code = find_info_data.get("search_to_city_code")
+
+            crawl_date = find_info_data.get("crawl_date")
+            search_date = find_info_data.get("search_date")
+            # 转为保存数据库的出发日期(in_strftime_str:传入时间的格式) 注:为时间
+            search_dep_time_base = time_format_conversion(search_date, in_strftime_str="%Y-%m-%d")
+
+            # 提取网站源数据
+            inner_data = find_info_data.get('inner_data')
+
+            # 取gk航班
+            flights = inner_data.get('Trips', [])[0].get("Flights", [])
+
+            # 处理不同的航班
+            for each_flight in flights:
+
+                mid_flight_datas = []
+
+                DisplayFlightInfo = each_flight.get("DisplayFlightInfo", {})  # 航班信息
+
+                from_airport_code = DisplayFlightInfo.get('OriginAirport')  # 出发机场
+                to_airport_code = DisplayFlightInfo.get('DestinationAirport')  # 到达机场代码
+
+                """提取票价"""
+                # 不同票价的余票 先设置为舱位的余票,因为每个票价没有对应的余票,
+                # 所以先检查经济舱是否有余票,无余票就跳过 (商务舱不用管, 因为查询参数传入的是经济舱/ 而且网站响应商务舱的余票好像一直是 0)
+
+                EconomyFlightInfo = DisplayFlightInfo.get('EconomyFlightInfo')  # 经济舱信息  里面是 余票数
+                if EconomyFlightInfo['RemainingSeats'] == 0:
+                    print('跳过(经济舱)余票数为 0 的航班')
+                    continue
+                # 余票
+                seatCount = EconomyFlightInfo['RemainingSeats']
+
+                Bundles = each_flight['Bundles']  # 票价列表
+                # 税金(手续费)和基本价提取
+                EconomyPriceBreakdown = json.loads(each_flight['EconomyPriceBreakdown'])  # 里面有税金, 是json字符串要转为对象
+                price = EconomyPriceBreakdown['TotalFare']  # 基础票价
+                adult_tax = EconomyPriceBreakdown['TotalCharges']  # 同一个航班是不变的
+
+                # 提取每个票价
+                for each_bundle in Bundles:
+                    # 服务包代码
+                    fareBasis = each_bundle['ServiceBundleCode']
+
+                    #  只采集 最低不带行李的价格 和 一个最低带行李 的票价
+                    # S000: 基本票價   P200: 基本加值套票 行李 + 座位 + 餐膳
+                    if fareBasis not in ['S000', 'P200']:
+                        continue
+
+                    Amount = each_bundle['Amount']  # 增值服务费, 后面算总价要加上这个
+
+                    # 托运行李
+                    if fareBasis == 'S000':
+                        pc_amount, kg_amount = '0', '0'  # 无托运行李
+                        has_baggage, baggage = format_pc_kg_data(pc_amount, kg_amount)
+                    if fareBasis == 'P200':
+                        pc_amount, kg_amount = '1', '20'  # 1件行李20公斤
+                        has_baggage, baggage = format_pc_kg_data(pc_amount, kg_amount)
+
+                    """处理中转"""
+                    segment_elements = []
+                    Legs = DisplayFlightInfo.get('Legs')  # 中转航段信息, 最多有3个
+
+                    # 可能是直达或转乘
+                    for each_leg in Legs:
+                        '''理论航班号信息'''
+                        CarrierCode = each_leg['FlightDesignator']['CarrierCode']    # 航空公司
+                        FlightNumber = each_leg['FlightDesignator']['FlightNumber']  # 航班号
+                        flight_number = f"{CarrierCode}{FlightNumber}"  # 拼接航班号
+
+                        '''实际航班号信息, gk没有这些, ??? 该如何??? => 略 '''
+                        # operatingAirlineCode = each_leg['operatingAirlineCode']  # 营运航空公司代码
+                        # operatingFlightno = each_leg['operatingFlightno']
+                        # operating_flight_number = f"{operatingAirlineCode}{operatingFlightno}"
+
+                        '''机型'''
+                        # 空中巴士 A320-200 (代碼 32J,全經濟艙配置)
+                        aircraftCode = each_leg['Equipment']['Type']
+
+                        '''出发/到达时间'''
+                        departDate = each_leg["DisplayStd"]  # 计划起飞时间  2025年5月31日 (週六) 上午2:15
+                        arrivalDate = each_leg["DisplaySta"]  # 计划到达时间
+
+                        dep_time = convert_time_format(departDate)  # 时间格式转换
+                        arr_time = convert_time_format(arrivalDate)
+
+                        '''出发/到达机场和城市'''
+                        depart_airport = each_leg['DepartureStation']  # 出发机场
+                        depart_city = get_city_code(self.db, self.website, depart_airport)  # 数据库查询对应城市代码
+
+                        arrival_airport = each_leg['ArrivalStation']  # 到达机场
+                        arrival_city = get_city_code(self.db, self.website, arrival_airport)
+
+                        '''舱位类型'''
+                        CabinType = each_leg['CabinType']
+
+                        # 航站楼
+                        # DisplayDepartureAirportTerminal = each_leg['DisplayDepartureAirportTerminal']  # 出发
+                        # DisplayArrivalAirportTerminal = each_leg['DisplayArrivalAirportTerminal']      # 到达
+
+                        segment_element_demo = {
+                            "flight_number": flight_number,  # 航班号
+                            "operating_flight_number": flight_number,  # 实际营运航班号 (gk没有这个和上面写为同一个)
+                            "dep_air_port": depart_airport,  # 出发机场code str
+                            "dep_city_code": depart_city,  # 出发城市code
+                            "dep_time": dep_time,               # 出发时间 格式YYYYMMDDHHMM str
+                            "arr_air_port": arrival_airport,  # 抵达机场code str
+                            "arr_city_code": arrival_city,  # 抵达城市code
+                            "arr_time": arr_time,  # 抵达时间 格式YYYYMMDDHHMM str
+                            "cabin": CabinType,  # 舱位单字母
+                            "carrier": CarrierCode,  # 航空公司代码
+                            "aircraft_code": aircraftCode,  # 机型 str
+                            "cabin_class": 1,  # 舱位等级, 因为捷星日本航空(GK)的航班目前均为全经济舱​​,故这里也可写死
+                            "stop_cities": "",
+                            "has_baggage": has_baggage,  # 是否有托运行李
+                            "baggage": baggage,  # 行李配重 1-23 表示一件行李 23kg
+                            "fareBasis": fareBasis,  # 在同一航班的不同舱位中是唯一值,主要用来区分同一航班的不同舱位,
+                        }
+                        segment_elements.append(segment_element_demo)
+
+                    # 查询出发时间(如果响应没有,可能是入参传递的)
+                    search_dep_time = segment_elements[0].get("dep_time") if segment_elements else search_dep_time_base
+
+                    flight_datas = {
+                        "from_city_code": from_city_code,
+                        "search_dep_time": search_dep_time,
+                        "to_city_code": to_city_code,
+                        "currency": 'JPY',  # 网站默认返回搜索地区的国家货币价格, 采集的全都是 日本的航班 故可写死
+                        "adult_price": int(Amount+price),  # 基本价格
+                        "adult_tax": int(adult_tax),  # 税金
+                        "adult_total_price": int(Amount+price+adult_tax),  # 再加 基本价和税金
+                        "route": "",
+                        "seats_remaining": seatCount,
+                        "segments": segment_elements,
+                        "source_website": self.website,
+                        "crawl_date": crawl_date
+                    }
+
+                    # print(flight_datas)
+
+                    if verify_flag:
+                        flight_datas["verify_date"] = crawl_date  # 验价分支
+                        verify_time = get_now_time()
+                        flight_datas["verify_time"] = verify_time
+                        # print(flight_datas)
+                    mid_flight_datas.append(flight_datas)
+                # 注意:这里已经跳出bundle循环,将当前航班的所有票价记录(mid_flight_datas)扩展到总结果
+                end_flight_datas.extend(mid_flight_datas)
+
+            if verify_flag:
+                # 验价分支,
+                search_from_city_code = find_info_data.get("search_from_city_code")
+                search_to_city_code = find_info_data.get("search_to_city_code")
+                search_date = find_info_data.get("search_date")
+                end_search_date = time_format_conversion(
+                    search_date,
+                    in_strftime_str="%Y-%m-%d",
+                    out_strftime_str="%Y%m%d"
+                )
+
+                delete_many_filter = {
+                    "from_city_code": search_from_city_code,
+                    "to_city_code": search_to_city_code,
+                    "search_dep_time": {"$regex": r"^{}".format(end_search_date)}
+                }
+                delete_mongodb_clean_datas(self.db, self.clean_info_tab, self.logger, delete_many_filter)
+                # 重新保存最新的采集数据
+                if len(end_flight_datas) > 0:
+                    save_mongodb_clean_datas(self.db, self.clean_info_tab, self.website, self.logger, end_flight_datas, thread_number, True)
+
+        except Exception as e:
+            self.logger.error(f"thread_number:{thread_number} clean error: {from_airport_code}---{to_airport_code}---{search_date}---{str(e)}")
+        finally:
+            return end_flight_datas
+
+    def processing_data(self, thread_number):
+        while 1:
+            log_ob_ids = []
+            try:
+                ids = get_data_by_queue(self.task_queue)
+                ob_ids = [ObjectId(i) for i in ids]
+                log_ob_ids = ob_ids
+                # 批量查询 _id 包含在给定列表 ob_ids 中的文档
+                find_info_datas = self.db.get_collection(self.info_tab).find(
+                    {"_id": {"$in": ob_ids}}
+                )
+                final_flight_datas = []
+                # 每一次搜索航线
+                for find_info_data in find_info_datas:
+                    with lock:
+                        self.count += 1
+                    if self.count % 50 == 0:
+                        self.logger.info("thread_number:{0}, clean count: {1}".format(
+                            thread_number, self.count))
+                    # print(find_info_data)
+                    # exit()
+                    end_flight_datas = self.processing_data_one_search(find_info_data, thread_number)
+                    final_flight_datas.extend(end_flight_datas)
+
+                # 更改这些info表里的数据清理状态为1
+                update_result = self.db.get_collection(self.info_tab).update_many(
+                    {"_id": {"$in": ob_ids}},
+                    {"$set": {"clean_status": 1}}
+                )
+                self.logger.info(f"Updated documents: {update_result.modified_count}")
+                if len(final_flight_datas) > 0:
+                    save_mongodb_clean_datas(self.db, self.clean_info_tab, self.website, self.logger, final_flight_datas, thread_number, True)
+
+            except Exception as e:
+                self.logger.error(f"thread_number:{thread_number}, log_ob_ids:{log_ob_ids}, clean unknown err:{str(e)}")
+            finally:
+                self.task_queue.task_done()
+
+    def run_threading(self):
+        for thread_number in range(1, self.thread_numbers+1):
+            t = threading.Thread(
+                target=self.processing_data,
+                args=(thread_number,)
+            )
+            t.daemon = True
+            t.start()
+        self.task_queue.join()
+
+    def split_datas(self, datas, num):
+        return [datas[i:i + num] for i in range(0, len(datas), num)]
+
+    def run(self):
+        # 每次清除之前清洗的数据
+        # 查询已经采集完成但未清洗的数据批次
+        while 1:
+            # 取最新采集的数据
+            find_crawl_conf_datas = self.db.get_collection(
+                CRAWL_DATE_CONF_STATUS_TAB).find(  # find查询
+                {
+                    "website": self.website,
+                    # "crawl_status": 1,  # 反复测试清洗逻辑
+                    "clean_status": 0
+                },  # 查询条件
+                sort=[('_id', -1)]  # 排序规则,按 _id 降序
+            ).limit(1)  # 仅返回第一条记录(即最新的一条文档)
+
+            for find_crawl_conf_data in find_crawl_conf_datas:
+                self.count = 0
+                self.logger.info("start clean crawl_date: {}".format(
+                    find_crawl_conf_data.get("crawl_date")
+                ))
+                find_info_datas = self.db.get_collection(self.info_tab).find(
+                    {
+                        "crawl_date": find_crawl_conf_data.get("crawl_date"),
+                        "website": self.website,
+                        # "clean_status": 1,  # 反复测试清洗逻辑
+                        "clean_status": 0
+                    }
+                )
+                find_id_datas = [str(i.get("_id")) for i in find_info_datas]
+                find_id_datas_splits = self.split_datas(find_id_datas, 5)
+                # 一个队列里最多放5份info数据
+                for find_id_data_split in find_id_datas_splits:
+                    put_data_by_queue(self.task_queue, find_id_data_split)
+
+                self.run_threading()  # 多线程清理
+                self.logger.info("batch clean all counts: {}".format(self.count))
+
+                # 判断整体结束的条件
+                if find_crawl_conf_data.get("crawl_status") == 1:
+                    self.update_clean_date_status(find_crawl_conf_data)
+                    self.logger.info("end clean crawl_date: {}".format(
+                        find_crawl_conf_data.get("crawl_date")
+                    ))
+                    # 整体结束后, 统一计算本次清理的记录数, 为零则告警
+                    clean_crawl_date_counts = self.db.get_collection(
+                        self.clean_info_tab).count_documents(
+                        {
+                            "crawl_date": find_crawl_conf_data.get("crawl_date")
+                        }
+                    )
+                    self.logger.info("crawl_date: {0}, insert counts: {1}".format(
+                        find_crawl_conf_data.get("crawl_date"), clean_crawl_date_counts
+                    ))
+
+                    # 发送钉钉通知
+                    try:
+                        from clean_datas_send_notice import CheckCrawlDatas
+                        C = CheckCrawlDatas()
+                        C.send_website_spiders_crawl_date_counts(
+                            self.website, find_crawl_conf_data.get("crawl_date"),
+                            clean_crawl_date_counts
+                        )
+                    except Exception as e:
+                        self.logger.info("send dingding error: {0}".format(str(e)))
+
+            time.sleep(10 * 1)
+
+    def update_clean_date_status(self, find_crawl_conf_data):
+        # 更新 采集批次时间 状态
+        self.db.get_collection(CRAWL_DATE_CONF_STATUS_TAB).update_one(
+             {
+                 "_id": ObjectId(find_crawl_conf_data.get("_id"))
+             },
+             {
+                 "$set":
+                     {
+                         "clean_status": 1
+                     }
+             }
+        )
+
+
+if __name__ == "__main__":
+    C = CleanGKDatas()
+    C.run()
+

+ 668 - 0
3.31GK/frame_code/gk_flights_spider.py

@@ -0,0 +1,668 @@
+import threading
+import queue
+import time
+import json
+import re
+import execjs
+import random
+import retrying
+from lxml import etree
+
+import datetime
+import requests
+import tls_client
+from urllib.parse import urljoin
+from bson.objectid import ObjectId
+from flights_utils import get_now_time, put_data_by_queue, get_data_by_queue, \
+    time_format_conversion
+from my_logger import Logger
+from flights_mongodb import mongo_con_parse
+from settings import CRAWL_DATE_CONF_STATUS_TAB, FLIGHTS_WEBSITES_ROUTE_CONF_TAB, PROXY_TAIL
+
+
+def generate_date_range(days):
+    """
+    生成 n 天的日期范围
+    """
+    # 获取今天的日期(结束日期)
+    start_date = datetime.datetime.today()
+    # 计算开始日期:结束日期 - (days-1) 天(确保包含今天)
+    end_date = start_date + datetime.timedelta(days=days)
+    # 格式化输出
+    return (
+        start_date.strftime("%Y-%m-%d"),
+        end_date.strftime("%Y-%m-%d")
+    )
+
+
+class GKSpider():
+
+    def __init__(self):
+        self.website = 'gk'  # 网站
+        self.is_proxy = True
+        self.is_online = True  #
+        if self.is_proxy:
+            if self.is_online:
+                # proxies = {
+                #     'http': f'http://B_3351_HK___5_ss-{ip}:ev2pjj@proxy.renlaer.com:7778',
+                #     'https': f'http://B_3351_HK___5_ss-{ip}:ev2pjj@proxy.renlaer.com:7778'
+                # }
+                self.proxy_meta = f"http://B_3351_HK___5_ss-xxxxxxxxxxxx:{PROXY_TAIL}"  # AU / HK
+                self.time_sleep = 0.5
+            else:
+                self.proxy_meta = "http://127.0.0.1:7897"
+                # self.time_sleep = 5.5
+                self.time_sleep = 0.5
+            self.proxies = {
+                "http": self.proxy_meta,
+                "https": self.proxy_meta,
+            }
+        else:
+            self.proxies = None
+            self.time_sleep = 5.5
+
+        self.search_flights_api = "https://booking.jetstar.com/hk/zh/booking/search-flights"
+        with open('./js_files/akm逆向5.26.js', encoding='utf-8') as f:
+            js = f.read()
+        self.ctx = execjs.compile(js)
+        self.task_queue = queue.Queue()
+        self.cookies_queue = queue.Queue()
+        self.ja3_queue = queue.Queue()  # 要回收可用ja3  频繁切换ja3会增加触发验证码几率
+        self.headers = {
+            "accept": "application/json, text/plain, */*",
+            "accept-language": "zh-CN,zh;q=0.9",
+            "cache-control": "no-cache",
+            "culture": "zh-HK",
+            "origin": "https://www.jetstar.com",
+            "pragma": "no-cache",
+            "priority": "u=1, i",
+            "referer": "https://www.jetstar.com/",
+            "sec-ch-ua": "\"Google Chrome\";v=\"135\", \"Not-A.Brand\";v=\"8\", \"Chromium\";v=\"135\"",
+            "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/135.0.0.0 Safari/537.36"
+        }
+
+        if self.is_online:
+            self.cookie_thread_num = 3
+            self.thread_numbers = 8
+            self.crawl_days = 10
+        else:
+            self.cookie_thread_num = 3
+            self.thread_numbers = 8
+            self.crawl_days = 5
+
+        self.cookie_queue_num = 4  # 队列中 cookie 的数量
+        self.ja3_queue_num = 4  # 队列中的 ja3 数量
+
+        self.retry_number = 2  # 5
+        self.db = mongo_con_parse()
+        self.info_tab = "flights_{}_info_tab".format(self.website)
+        self.logger = Logger('./logs/{}_flights_spiders.log'.format(self.website), 'debug').logger
+
+    def init_crawl_date_data(self):
+        # 初始化 采集批次时间 状态
+        # 开始采集 创建一个批次时间   采集完成更新采集状态
+        self.db.get_collection(CRAWL_DATE_CONF_STATUS_TAB).insert_one(
+            {
+                "website": self.website,
+                "crawl_date": self.crawl_date,
+                "crawl_status": 0,  # 采集状态
+                "clean_status": 0,  # 数据清洗状态
+                "to_csv_status": 0  # 导出文件状态
+            }
+        )
+
+    def init_crawl_conf(self):
+        # 获取采集时间
+        self.crawl_date = get_now_time()
+        self.logger.info("本次数据采集批次为: {}".format(self.crawl_date))
+        # 初始化 采集批次时间 状态
+        self.init_crawl_date_data()
+
+        # 从航线表里提取记录(提取采集航线表的)
+        search_routes = self.db.get_collection(
+            FLIGHTS_WEBSITES_ROUTE_CONF_TAB
+        ).find(
+            {
+                "source_website": self.website,  # 数据来源网站
+                "website_status": 1,  # 网站是否采集状态
+                "flight_route_status": 1  # 航线是否采集状态
+            },
+            {
+                "_id": 0  # 排除返回结果中的_id字段,因为MongoDB默认会返回_id,但这里用户可能不需要这个字段
+            }
+        )
+        self.logger.info("获取需要采集的航线.并喂给队列")
+        for search_route in search_routes:
+            put_data_by_queue(self.task_queue, search_route)
+
+    def general_proxies(self):
+        if self.is_online:
+            proxy_meta = self.proxy_meta
+            random_no = ''.join(random.choices('0123456789', k=12))
+            # region = ''.join(random.choices(["US"], k=1))
+            # 香港 新加坡 台湾 都能服务  新加坡最快最稳定
+            # proxy_meta_mid = re.sub(r"_(US)_", f"_{region}_", proxy_meta)
+            proxy_meta_new = re.sub(r"-(x+):", f"-{random_no}:", proxy_meta)
+            # print(f"proxy_meta_new: {proxy_meta_new}")
+            proxies = {
+                "http": proxy_meta_new,
+                "https": proxy_meta_new,
+            }
+        else:
+            proxies = self.proxies
+        return proxies
+
+    @retrying.retry(stop_max_attempt_number=3, wait_fixed=3000)
+    def request_new_cookie(self):
+        statusTs = int(time.time() * 1000)
+
+        try:
+            ua, ja3_string = self.ja3_queue.get()
+            proxy = self.general_proxies()
+
+            get_ck_session = tls_client.Session(
+                ja3_string=ja3_string,
+            )
+            headers = {
+                'user-agent': ua,
+                'Accept-Encoding': 'gzip, deflate, br',
+                'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
+                'Connection': 'keep-alive',
+                'Content-Type': 'application/x-www-form-urlencoded',
+                'accept-language': 'zh-CN,zh;q=0.9',
+                'cache-control': 'no-cache',
+                'pragma': 'no-cache',
+                'priority': 'u=0, i',
+                'referer': 'https://booking.jetstar.com/',
+                'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
+                'sec-ch-ua-mobile': '?0',
+                'sec-ch-ua-platform': '"Windows"',
+                'sec-fetch-dest': 'document',
+                'sec-fetch-mode': 'navigate',
+                'sec-fetch-site': 'same-origin',
+                'sec-fetch-user': '?1',
+                'upgrade-insecure-requests': '1'
+            }
+            # akm js file url
+            akm_url = "https://www.jetstar.com/xsRfGu1Zb-8uTxanFA/9kX3LGbVJLVb/FB0BajANQQk/YE94/HSh0EkU"
+            data = {
+                'sensor_data': self.ctx.call('encrypt1', statusTs)
+            }
+            response1 = get_ck_session.post(akm_url, headers=headers, data=data,
+                                            proxy=proxy
+                                            )
+
+            # print(response1.status_code)
+            # print(response1.text)
+            # print(response1.cookies.get_dict())
+            # print('111', response.headers)
+            bmsz = response1.cookies.get_dict()['bm_sz']
+            # print('bmsz => ', bmsz)
+
+            data2 = {
+                "sensor_data": self.ctx.call('encrypt2', statusTs, bmsz)
+            }
+
+            data2 = json.dumps(data2)
+            response2 = get_ck_session.post(akm_url, headers=headers, data=data2,
+                                            proxy=proxy
+                                            )
+
+            # print(response2.text)
+            # print(response2.cookies.get_dict())
+            if response2.status_code == 201:
+                self.logger.debug('成功获取 cookie bm-sz: {}'.format(bmsz[-16:]))
+
+                # 返回第一次请求响应的cookie
+                return response1.cookies.get_dict()
+            else:
+                self.logger.error('状态码错误{}, {}'.format(response2.status_code, response2.text))
+        except Exception as e:
+            print('request cookie error, 重试中..', e)
+            raise
+
+    @retrying.retry(stop_max_attempt_number=3, wait_fixed=3000)
+    def get_ja3(self):
+        url = "http://8.218.51.130:9003/api/v1/ja3"
+        payload = {}
+        headers = {
+            'cid': '750B5141EDBF7FA6F73A99C768130099'
+        }
+        response = requests.get(url, headers=headers, data=payload, timeout=15)
+        if response.status_code == 200:
+            # print(response.json())
+            res_json = response.json()
+            if res_json.get("code") == 0:
+                ja3 = res_json.get("data").get("ja3_str")
+                ua = res_json.get("data").get("ua")
+                if "--" not in ja3 and ",," not in ja3:
+                    return ua, ja3
+
+    def _refresh_ja3(self):
+        while True:
+            if self.ja3_queue.qsize() < self.ja3_queue_num:
+                try:
+                    ua, ja3 = self.get_ja3()
+                    # logger.debug('获取ja3成功...')
+                    self.ja3_queue.put((ua, ja3))
+                except Exception as e:
+                    self.logger.error(f'ja3接口错误: {e}')
+
+            time.sleep(3)
+
+    def _refresh_cookie(self):
+        while True:
+            if self.cookies_queue.qsize() < self.cookie_queue_num:
+                cookie = self.request_new_cookie()
+                self.cookies_queue.put(cookie)
+
+            time.sleep(3)
+
+    @retrying.retry(stop_max_attempt_number=5, wait_fixed=3000)
+    def tls_client_get_request(self, url, params, max_redirects=3):
+        ua, ja3_string = self.ja3_queue.get()
+        bmsz_cookie = self.cookies_queue.get()
+        proxy = self.general_proxies()
+
+        req_session = tls_client.Session(
+            ja3_string=ja3_string,  # 直接注入自定义指纹
+        )
+        headers = {
+            'user-agent': ua,
+            'Accept-Encoding': 'gzip, deflate, br',
+            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
+            'Connection': 'keep-alive',
+            'Content-Type': 'application/x-www-form-urlencoded',
+            'accept-language': 'zh-CN,zh;q=0.9',
+            'cache-control': 'no-cache',
+            'pragma': 'no-cache',
+            'priority': 'u=0, i',
+            'referer': 'https://booking.jetstar.com/',
+            'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
+            'sec-ch-ua-mobile': '?0',
+            'sec-ch-ua-platform': '"Windows"',
+            'sec-fetch-dest': 'document',
+            'sec-fetch-mode': 'navigate',
+            'sec-fetch-site': 'same-origin',
+            'sec-fetch-user': '?1',
+            'upgrade-insecure-requests': '1'
+        }
+        redirect_count = 0
+        current_url = url
+
+        while redirect_count < max_redirects:
+            response = req_session.get(current_url, headers=headers, cookies=bmsz_cookie, params=params,
+                                       timeout_seconds=15,  # timeout
+                                       proxy=proxy
+                                       )
+
+            # print(response.status_code)
+            # print(response.text)
+
+            # 检查是否为重定向状态码
+            if response.status_code in (301, 302, 303, 307, 308):
+                # 获取 Location 头(需处理相对路径)
+                location = response.headers.get("Location")
+                # if not location:
+                #     break
+                current_url = urljoin(current_url, location)
+                redirect_count += 1
+
+            elif response.status_code == 200:
+                html = etree.HTML(response.text)
+                data = html.xpath("//script[@id='bundle-data-v2']/text()")
+                if data:
+                    json_data = json.loads(data[0])
+                    # 请求成功,归还Cookie 和 ja3
+                    self.cookies_queue.put(bmsz_cookie)  # 成功时放回cookie
+                    self.ja3_queue.put((ua, ja3_string))  # 回收可用ja3  频繁切换ja3会增加触发验证码几率
+
+                    return json_data  # 返回提取后的数据
+                else:
+                    self.logger.warning(f'触发验证码或拒绝访问错误, 重试中... => {response.text}')
+                    raise
+            else:
+                self.logger.error(f'状态码错误, {response.status_code}, 响应内容:{response.text}')
+
+        raise Exception(f"超过最大重定向次数, 检查({max_redirects})")
+
+    @retrying.retry(stop_max_attempt_number=3, wait_fixed=3000)
+    def get_cookie_with_verify_price(self):
+        """验价,刷cookie"""
+        statusTs = int(time.time() * 1000)
+        try:
+            ua, ja3_string = self.get_ja3()
+            proxy = self.general_proxies()
+
+            get_ck_session = tls_client.Session(
+                ja3_string=ja3_string,
+            )
+            headers = {
+                'user-agent': ua,
+                'Accept-Encoding': 'gzip, deflate, br',
+                'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
+                'Connection': 'keep-alive',
+                'Content-Type': 'application/x-www-form-urlencoded',
+                'accept-language': 'zh-CN,zh;q=0.9',
+                'cache-control': 'no-cache',
+                'pragma': 'no-cache',
+                'priority': 'u=0, i',
+                'referer': 'https://booking.jetstar.com/',
+                'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
+                'sec-ch-ua-mobile': '?0',
+                'sec-ch-ua-platform': '"Windows"',
+                'sec-fetch-dest': 'document',
+                'sec-fetch-mode': 'navigate',
+                'sec-fetch-site': 'same-origin',
+                'sec-fetch-user': '?1',
+                'upgrade-insecure-requests': '1'
+            }
+            # akm js file url
+            akm_url = "https://www.jetstar.com/xsRfGu1Zb-8uTxanFA/9kX3LGbVJLVb/FB0BajANQQk/YE94/HSh0EkU"
+            data = {
+                'sensor_data': self.ctx.call('encrypt1', statusTs)
+            }
+            response1 = get_ck_session.post(akm_url, headers=headers, data=data,
+                                            proxy=proxy
+                                            )
+
+            # print(response1.status_code)
+            # print(response1.text)
+            # print(response1.cookies.get_dict())
+            # print('111', response.headers)
+            bmsz = response1.cookies.get_dict()['bm_sz']
+            # print('bmsz => ', bmsz)
+
+            data2 = {
+                "sensor_data": self.ctx.call('encrypt2', statusTs, bmsz)
+            }
+
+            data2 = json.dumps(data2)
+            response2 = get_ck_session.post(akm_url, headers=headers, data=data2,
+                                            proxy=proxy
+                                            )
+
+            # print(response2.text)
+            # print(response2.cookies.get_dict())
+            if response2.status_code == 201:
+                self.logger.debug('成功获取 cookie bm-sz: {}'.format(bmsz[-16:]))
+
+                # 返回第一次请求响应的cookie
+                return response1.cookies.get_dict()
+            else:
+                self.logger.error('状态码错误{}, {}'.format(response2.status_code, response2.text))
+        except Exception as e:
+            print('request cookie error, 重试中..', e)
+            raise
+
+    @retrying.retry(stop_max_attempt_number=5, wait_fixed=3000)
+    def get_flights_with_verify_price(self, from_city_code, to_city_code, search_date, thread_number=0, max_redirects=3):
+        """验价逻辑, 不用队列"""
+        sleep_r = self.time_sleep if self.time_sleep >= 1 else 1
+        time.sleep(sleep_r)
+
+        params = {
+            "s": "true",
+            "adults": "1",
+            "children": "0",
+            "infants": "0",
+            "selectedclass1": "economy",
+            "currency": "CNY",
+            "mon": "true",
+            "channel": "DESKTOP",
+            "origin1": from_city_code,  # "PVG"
+            "destination1": to_city_code,
+            "departuredate1": search_date
+        }
+        ua, ja3_string = self.get_ja3()
+        bmsz_cookie = self.get_cookie_with_verify_price()
+        proxy = self.general_proxies()
+
+        req_session = tls_client.Session(
+            ja3_string=ja3_string,  # 直接注入自定义指纹
+        )
+        headers = {
+            'user-agent': ua,
+            'Accept-Encoding': 'gzip, deflate, br',
+            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
+            'Connection': 'keep-alive',
+            'Content-Type': 'application/x-www-form-urlencoded',
+            'accept-language': 'zh-CN,zh;q=0.9',
+            'cache-control': 'no-cache',
+            'pragma': 'no-cache',
+            'priority': 'u=0, i',
+            'referer': 'https://booking.jetstar.com/',
+            'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
+            'sec-ch-ua-mobile': '?0',
+            'sec-ch-ua-platform': '"Windows"',
+            'sec-fetch-dest': 'document',
+            'sec-fetch-mode': 'navigate',
+            'sec-fetch-site': 'same-origin',
+            'sec-fetch-user': '?1',
+            'upgrade-insecure-requests': '1'
+        }
+        redirect_count = 0
+        current_url = self.search_flights_api
+
+        while redirect_count < max_redirects:
+            response = req_session.get(current_url, headers=headers, cookies=bmsz_cookie, params=params,
+                                       timeout_seconds=15,  # timeout
+                                       proxy=proxy
+                                       )
+
+            # print(response.status_code)
+            # print(response.text)
+
+            # 检查是否为重定向状态码
+            if response.status_code in (301, 302, 303, 307, 308):
+                # 获取 Location 头(需处理相对路径)
+                location = response.headers.get("Location")
+                # if not location:
+                #     break
+                current_url = urljoin(current_url, location)
+                redirect_count += 1
+
+            elif response.status_code == 200:
+                html = etree.HTML(response.text)
+                data = html.xpath("//script[@id='bundle-data-v2']/text()")
+                if data:
+                    json_data = json.loads(data[0])
+
+                    return {"inner_data": json_data}  # 返回提取后的数据
+                else:
+                    self.logger.warning(f'触发验证码或拒绝访问错误, 重试中... => {response.text}')
+                    raise
+            else:
+                self.logger.error(f'状态码错误, {response.status_code}, 响应内容:{response.text}')
+
+        raise Exception(f"超过最大重定向次数, 检查({max_redirects})")
+
+    def get_flights(self, from_city_code, to_city_code, search_date, thread_number=0):
+        sleep_r = self.time_sleep if self.time_sleep >= 1 else 1
+        time.sleep(sleep_r)
+
+        params = {
+            "s": "true",
+            "adults": "1",
+            "children": "0",
+            "infants": "0",
+            "selectedclass1": "economy",
+            "currency": "CNY",
+            "mon": "true",
+            "channel": "DESKTOP",
+            "origin1": from_city_code,  # "PVG"
+            "destination1": to_city_code,
+            "departuredate1": search_date
+        }
+
+        try:
+            resp_json = self.tls_client_get_request(self.search_flights_api, params)
+
+            self.logger.info(f'获取数据成功 {from_city_code}-{to_city_code} {search_date} => {str(resp_json)[:200]}')
+            return {"inner_data": resp_json}
+
+        except Exception as e:
+            self.logger.error(
+                f"thread_number:{thread_number} {from_city_code}-{to_city_code}-{search_date}- 5次重试全部失败 {str(e)}")
+
+    @retrying.retry(stop_max_attempt_number=3, wait_fixed=3000)
+    def search_flight_date(self, from_city_code, to_city_code, start_date, end_date):
+        """查询航班日期, 即那天有航班"""
+        url = "https://digitalapi.jetstar.com/v1/farecache/flights/batch/availability-with-fareclasses"
+        params = {
+            "flightCount": "1",
+            "includeSoldOut": "true",
+            "requestType": "StarterOnly",
+            "from": start_date,  # 采集开始时间
+            "end": end_date,  # 采集结束时间,可随意写
+            "departures": from_city_code,
+            "arrivals": to_city_code,
+            "direction": "outbound",
+            "paxCount": "1",
+            "includeFees": "false"
+        }
+
+        response = requests.get(url, headers=self.headers, params=params, verify=False)
+        response.raise_for_status()
+        # for i in response.json():
+        #     print(i)
+        json_data = response.json()[0]['routes']
+
+        # 只有一个键值对
+        for key, val in json_data.items():
+            flight_dates = list(val.get('flights', {}).keys())
+            # print(f'航段: {key} 对应有航班的日期为: {flight_dates}')
+            return flight_dates
+
+    def thread_task(self, thread_number):
+        while True:
+            try:
+                # 从队列取出 航线数据
+                queue_data = get_data_by_queue(self.task_queue)
+                search_route = queue_data  # 从队列里取出本次航线
+                from_city_code = search_route['from_city_code']
+                to_city_code = search_route['to_city_code']
+
+                # 生成采集天数的日期范围, 额外多一天
+                start_date, end_date = generate_date_range(self.crawl_days)
+                # 从网站接口查询那天有航班, 日期格式要转换
+                search_date_list = self.search_flight_date(from_city_code, to_city_code, start_date, end_date)
+                if not search_date_list:
+                    self.logger.info(f'{start_date}~{end_date} 内的航段 {from_city_code}-{to_city_code} 无航班')
+                    continue
+
+                for search_date in search_date_list:
+                    self.logger.info(f"线程:{thread_number}, 正在采集 => {search_date} {from_city_code}-{to_city_code}")
+                    # 日期格式转换 20250531 => 2025-05-31
+                    search_date = time_format_conversion(
+                        search_date,
+                        in_strftime_str="%Y%m%d",
+                        out_strftime_str="%Y-%m-%d"
+                    )
+
+                    flights_json = self.get_flights(from_city_code, to_city_code, search_date, thread_number)
+                    if flights_json:
+                        Trips = flights_json.get('inner_data', {}).get("Trips", [])
+                        if not Trips:
+                            self.logger.info(
+                                f'Trip 为空, {search_date}:{from_city_code}-{to_city_code}----{flights_json}')
+                            continue
+
+                        Flights = Trips[0].get('Flights', [])
+                        if len(Flights) > 0:
+                            self.logger.info("获取航班信息{1}:{2}-{3}成功, thread_number:{0}".format(thread_number, search_date,
+                                                                                             from_city_code,
+                                                                                             to_city_code))
+
+                            self.save_mongodb_datas(flights_json, from_city_code, to_city_code, search_date)
+                        else:
+                            self.logger.info(
+                                f"获取航班信息为空 {search_date}:{from_city_code}-{to_city_code},thread_number:{thread_number}")
+
+                    else:
+                        self.logger.info("thread_number:{0},请求航班信息失败/ 该航线数据可能需要重新抓取{1}:{2}-{3}".format(
+                            thread_number, search_date, from_city_code, to_city_code))
+
+            except Exception as e:
+                self.logger.error(f"thread_number:{thread_number}- 未知错误--unknown err:{str(e)}")
+
+            finally:
+                self.task_queue.task_done()
+
+    def run(self):
+        # 往队列上传任务,初始化 采集批次时间状态
+        self.init_crawl_conf()
+
+        thread_list = []
+
+        # 刷cookie
+        for _ in range(1, self.cookie_thread_num + 1):
+            t_get_cookie = threading.Thread(target=self._refresh_cookie)
+            thread_list.append(t_get_cookie)
+
+        # 刷ja3
+        t_get_ja3 = threading.Thread(target=self._refresh_ja3)
+        thread_list.append(t_get_ja3)
+
+        # 采集data
+        for thread_number in range(1, self.thread_numbers + 1):
+            t_get_data = threading.Thread(target=self.thread_task, args=(thread_number,))
+            thread_list.append(t_get_data)
+
+        for t_obj in thread_list:
+            t_obj.setDaemon(True)
+            t_obj.start()
+
+        self.task_queue.join()
+        # 更新采集状态
+        self.update_crawl_date_status()
+        # 关闭数据库连接
+        self.db.client.close()
+
+    def save_mongodb_datas(self, info_data, from_city_code, to_city_code, search_date):
+        # 将采集到的数据入库  并打上相应的数据
+        info_data["website"] = self.website
+        info_data["crawl_date"] = self.crawl_date
+        info_data["search_from_city_code"] = from_city_code
+
+        # info_data["search_from_airport_code"] = from_airport_code
+
+        info_data["search_to_city_code"] = to_city_code
+
+        # info_data["search_to_airport_code"] = to_airport_code
+
+        info_data["search_date"] = search_date  # 搜索日期,采集航班的日期
+        info_data["clean_status"] = 0  # 给每一条数据标记清理状态
+        self.db.get_collection(self.info_tab).insert_one(info_data)
+
+    def update_crawl_date_status(self):
+        # 更新 采集批次时间 状态
+        find_data = self.db.get_collection(CRAWL_DATE_CONF_STATUS_TAB).find_one(
+            {
+                "website": self.website,
+                "crawl_date": self.crawl_date,
+                "crawl_status": 0
+            }
+        )
+        if find_data:
+            self.db.get_collection(CRAWL_DATE_CONF_STATUS_TAB).update_one(
+                {
+                    "_id": ObjectId(find_data.get("_id"))  # 通过文档的 _id 精确匹配
+                },
+                {
+                    "$set":
+                        {
+                            "crawl_status": 1  # 将 crawl_status 设为 1(表示已爬取)
+                        }
+                }
+            )
+
+
+if __name__ == "__main__":
+    spider = GKSpider()
+    spider.run()

+ 107 - 0
3.31GK/frame_code/gk_flights_spider_que_work.py

@@ -0,0 +1,107 @@
+import threading
+import json
+import time
+from my_logger import Logger
+from flights_utils import time_format_conversion
+from flights_redis import RedisHelper
+from flights_mongodb import mongo_con_parse
+from settings import CRAWL_DATE_CONF_STATUS_TAB
+from insert_flights_gk_route import get_airport_data, find_route_airport_pair
+from gk_flights_spider import GKSpider
+from clean_gk_flights_datas import CleanGKDatas
+
+
+class GKSpidersQueWork(GKSpider, CleanGKDatas):
+
+    def __init__(self):
+        super().__init__()
+        self.website = "gk"
+        self.que_key = "flight_website_{}".format(self.website)
+        self.redis_ = RedisHelper()
+        self.db = mongo_con_parse()
+        self.info_tab = "flights_{}_info_tab".format(self.website)
+        self.clean_info_tab = "clean_{}".format(self.info_tab)
+        # self.thread_numbers = 5
+        self.thread_numbers = 1
+        self.logger = Logger(
+            './logs/{}_flights_spiders_que_work.log'.format(self.website),
+            'debug').logger
+
+    def get_clean_1_crawl_date(self):
+        website_crawl_date = None
+        website_crawl_dates = self.db.get_collection(
+                        CRAWL_DATE_CONF_STATUS_TAB).distinct(
+                            "crawl_date",
+                            {
+                                "website": self.website,
+                                "clean_status": 1,
+                                "crawl_status": 1
+                            }
+                        )
+        if len(website_crawl_dates) > 0:
+            website_crawl_dates.sort()
+            website_crawl_date = website_crawl_dates[-1]
+        return website_crawl_date
+
+    def thread_task(self, thread_number):
+        while True:
+            que_data = self.redis_.get_nowait(self.que_key)
+            if que_data:
+                task_json = json.loads(que_data)
+                from_city_code = task_json.get("from_city_code")
+                to_city_code = task_json.get("to_city_code")
+                search_date = task_json.get("search_date")
+                # 查询日期转换
+                search_date = time_format_conversion(
+                    search_date,
+                    in_strftime_str="%Y%m%d",
+                    out_strftime_str="%Y-%m-%d"
+                )
+                self.logger.info(f"正在采集: {search_date}:{from_city_code}-{to_city_code}")
+                
+                # 采集航班数据
+                flights_json = self.get_flights_with_verify_price(from_city_code, to_city_code, search_date, thread_number)
+                if flights_json:
+                    self.logger.info(
+                        "thread_number_name:{0},获取航班信息成功: {1}:{2}-{3}".format(
+                            thread_number, search_date, from_city_code,
+                            to_city_code))
+                    self.logger.info(
+                        "thread_number_name:{0}, {1}:{2}-{3}, resp json: {4}".format(
+                            thread_number, search_date, from_city_code, to_city_code,
+                            json.dumps(flights_json)[:60])
+                    )
+                    # 清洗
+                    flights_json["website"] = self.website
+                    # 获取采集日期
+                    crawl_date = self.get_clean_1_crawl_date()
+                    flights_json["crawl_date"] = crawl_date
+                    flights_json["search_from_city_code"] = from_city_code
+                    flights_json["search_to_city_code"] = to_city_code
+                    flights_json["search_date"] = search_date
+
+                    # 直接进入清洗流程(并开启验价,验价会先删除该航段当天的所有数据,再重新获取)
+                    self.processing_data_one_search(flights_json, thread_number, True)
+
+                    self.logger.info("thread_number_name:{0},保存航班信息结束: {1}:{2}-{3}".format(thread_number, search_date,
+                                                                                           from_city_code,
+                                                                                           to_city_code))
+                else:
+                    self.logger.info("thread_number:{0},获取航班信息{1}:{2}-{3}失败".format(
+                        thread_number, search_date, from_city_code, to_city_code))
+
+            time.sleep(0.5)
+
+    def run_threading(self):
+        for thread_number in range(1, self.thread_numbers+1):
+            t = threading.Thread(
+                target=self.thread_task,
+                args=(thread_number,)
+            )
+            t.start()
+        self.task_queue.join()
+
+
+if __name__ == "__main__":
+    R = GKSpidersQueWork()
+    R.run_threading()

+ 54 - 0
3.31GK/frame_code/insert_flights_gk_city_airport_codes.py

@@ -0,0 +1,54 @@
+import requests
+
+from flights_mongodb import mongo_con_parse
+from settings import FLIGHTS_CITY_AIRPORT_CODE_TAB
+
+
+def insert_codes():
+
+    """
+        网站没有城市代码,得自己找 根据航段找...
+        采集航段中
+            # 能查到的城市码就这几个 
+                城市码和机场码不一致: 'NRT', KIX'
+                存疑 HKO "北海道 (所有机场)", EKK "四國 (所有機場)" 应该是网站为了区分地区自定义的
+                城市机场码一致的 'OKA', 'CTS', 'TAK', 'KMJ', 'KOJ', 'KMI', 'AKJ', 'OIT', 'MYJ', 'NGO', 'FUK', 'NGS' KCZ
+            # 没有的城市/机场码: OSA SPK TYO SHI
+            这里直接手动定义
+    """
+    airport_code_li = [
+        {"city_code": "TYO", "country_code": "JP", "airport_code": "NRT"},
+        {"city_code": "OSA", "country_code": "JP", "airport_code": "KIX"},
+
+        {"city_code": "HKO", "country_code": "JP", "airport_code": "HKO"},
+        {"city_code": "EKK", "country_code": "JP", "airport_code": "EKK"},
+
+        {"country_code": "JP", "city_code": "OKA", "airport_code": "OKA"},
+        {"country_code": "JP", "city_code": "CTS", "airport_code": "CTS"},
+        {"country_code": "JP", "city_code": "TAK", "airport_code": "TAK"},
+        {"country_code": "JP", "city_code": "KMJ", "airport_code": "KMJ"},
+        {"country_code": "JP", "city_code": "KOJ", "airport_code": "KOJ"},
+        {"country_code": "JP", "city_code": "KMI", "airport_code": "KMI"},
+        {"country_code": "JP", "city_code": "AKJ", "airport_code": "AKJ"},
+        {"country_code": "JP", "city_code": "OIT", "airport_code": "OIT"},
+        {"country_code": "JP", "city_code": "MYJ", "airport_code": "MYJ"},
+        {"country_code": "JP", "city_code": "NGO", "airport_code": "NGO"},
+        {"country_code": "JP", "city_code": "FUK", "airport_code": "FUK"},
+        {"country_code": "JP", "city_code": "NGS", "airport_code": "NGS"},
+        {"country_code": "JP", "city_code": "KCZ", "airport_code": "KCZ"},
+
+
+    ]
+    print(len(airport_code_li))
+
+    db = mongo_con_parse()
+    website = "gk"
+    db.get_collection(FLIGHTS_CITY_AIRPORT_CODE_TAB).delete_many({"website": website})  # 清空原来属于该航司的数据
+    for item in airport_code_li:
+        item["website"] = website
+        db.get_collection(FLIGHTS_CITY_AIRPORT_CODE_TAB).insert_one(item)
+    print('insert finish...')
+
+
+if __name__ == "__main__":
+    insert_codes()

+ 391 - 0
3.31GK/frame_code/insert_flights_gk_route.py

@@ -0,0 +1,391 @@
+from flights_mongodb import mongo_con_parse
+from settings import FLIGHTS_WEBSITES_ROUTE_CONF_TAB, FLIGHTS_CITY_AIRPORT_CODE_TAB
+
+db = mongo_con_parse()
+website = "gk"
+
+
+def get_from_to_data(input_str):
+    input_str_list = input_str.split("\t")
+    from_airport_code = input_str_list[0]
+    to_airport_code = input_str_list[1]
+    return {
+        "from_airport_code": from_airport_code,
+        "to_airport_code": to_airport_code
+    }
+
+
+def get_city_data(airport_code):
+    city_code = None
+    find_data = db.get_collection(FLIGHTS_CITY_AIRPORT_CODE_TAB).find_one(  # 这里拿出每个机场码所对应的城市码
+        {
+            "airport_code": airport_code,
+            "website": website
+        }
+    )
+    if find_data:
+        city_code = find_data.get("city_code")
+    return city_code
+
+
+def get_airport_data(city_code):
+    airport_code_list = []
+    find_data = db.get_collection(FLIGHTS_CITY_AIRPORT_CODE_TAB).find(  # 这里要拿出每个城市所有对应的机场码
+        {
+            "city_code": city_code,
+            "website": website
+        }
+    )
+    for item in find_data:
+        airport_code = item.get("airport_code")
+        airport_code_list.append(airport_code)
+    return airport_code_list
+
+
+# 根据城市码获取机场对
+def find_route_airport_pair(from_city_code, to_city_code):
+    airport_code_pair_list = []
+    find_data = db.get_collection(FLIGHTS_WEBSITES_ROUTE_CONF_TAB).find(  # 这里拿出在航线表里定义的城市码对关联的机场码对
+        {
+            "from_city_code": from_city_code,
+            "to_city_code": to_city_code,
+            "source_website": website
+        }
+    )
+    for item in find_data:
+        from_airport_code = item.get("from_airport_code")
+        to_airport_code = item.get("to_airport_code")
+        airport_code_pair_list.append((from_airport_code, to_airport_code))  # 存元组
+    return airport_code_pair_list
+
+
+def insert_routes():
+    # 这里是城市代码, 网站没有的城市/机场码: OSA SPK TYO SHI, 删去它们的航段
+    routes = """
+    KCZ	FUK
+    KCZ	KOJ
+    KCZ	KMJ
+    KCZ	KMI
+    KCZ	OIT
+    KCZ	OKA
+    KCZ	AKJ
+    KCZ	NGS
+    FUK	KCZ
+    FUK	MYJ
+    FUK	NGO
+    FUK	OKA
+    FUK	TAK
+    FUK	AKJ
+    KOJ	KCZ
+    KOJ	KMJ
+    KOJ	MYJ
+    KOJ	NGO
+    KOJ	OKA
+    KOJ	TAK
+    KOJ	AKJ
+    KMJ	KCZ
+    KMJ	KOJ
+    KMJ	MYJ
+    KMJ	NGO
+    KMJ	OKA
+    KMJ	TAK
+    KMJ	AKJ
+    MYJ	FUK
+    MYJ	KOJ
+    MYJ	KMJ
+    MYJ	KMI
+    MYJ	OIT
+    MYJ	OKA
+    MYJ	AKJ
+    MYJ	NGS
+    KMI	KCZ
+    KMI	MYJ
+    KMI	OKA
+    KMI	TAK
+    KMI	AKJ
+    NGO	FUK
+    NGO	KOJ
+    NGO	KMJ
+    NGO	OKA
+    OIT	KCZ
+    OIT	MYJ
+    OIT	OKA
+    OIT	TAK
+    OIT	AKJ
+    OKA	KCZ
+    OKA	FUK
+    OKA	KOJ
+    OKA	KMJ
+    OKA	MYJ
+    OKA	KMI
+    OKA	NGO
+    OKA	OIT
+    OKA	TAK
+    OKA	AKJ
+    OKA	NGS
+    TAK	FUK
+    TAK	KOJ
+    TAK	KMJ
+    TAK	KMI
+    TAK	OIT
+    TAK	OKA
+    TAK	AKJ
+    TAK	NGS
+    AKJ	KCZ
+    AKJ	FUK
+    AKJ	KOJ
+    AKJ	KMJ
+    AKJ	MYJ
+    AKJ	KMI
+    AKJ	OIT
+    AKJ	OKA
+    AKJ	TAK
+    AKJ	NGS
+    NGS	KCZ
+    NGS	MYJ
+    NGS	OKA
+    NGS	TAK
+    NGS	AKJ
+
+    KCZ	FUK
+    KCZ	KOJ
+    KCZ	KMJ
+    KCZ	KMI
+    KCZ	OIT
+    KCZ	OKA
+    KCZ	KIX
+    KCZ	CTS
+    KCZ	NRT
+    KCZ	HKO
+    KCZ	AKJ
+    KCZ	NGS
+    FUK	KCZ
+    FUK	MYJ
+    FUK	NGO
+    FUK	OKA
+    FUK	KIX
+    FUK	CTS
+    FUK	TAK
+    FUK	NRT
+    FUK	HKO
+    FUK	EKK
+    FUK	AKJ
+    KOJ	KCZ
+    KOJ	KMJ
+    KOJ	MYJ
+    KOJ	NGO
+    KOJ	OKA
+    KOJ	CTS
+    KOJ	TAK
+    KOJ	NRT
+    KOJ	HKO
+    KOJ	EKK
+    KOJ	AKJ
+    KMJ	KCZ
+    KMJ	KOJ
+    KMJ	MYJ
+    KMJ	NGO
+    KMJ	OKA
+    KMJ	KIX
+    KMJ	CTS
+    KMJ	TAK
+    KMJ	NRT
+    KMJ	HKO
+    KMJ	EKK
+    KMJ	AKJ
+    MYJ	FUK
+    MYJ	KOJ
+    MYJ	KMJ
+    MYJ	KMI
+    MYJ	OIT
+    MYJ	OKA
+    MYJ	CTS
+    MYJ	NRT
+    MYJ	HKO
+    MYJ	AKJ
+    MYJ	NGS
+    KMI	KCZ
+    KMI	MYJ
+    KMI	OKA
+    KMI	KIX
+    KMI	CTS
+    KMI	TAK
+    KMI	NRT
+    KMI	HKO
+    KMI	EKK
+    KMI	AKJ
+    NGO	FUK
+    NGO	KOJ
+    NGO	KMJ
+    NGO	OKA
+    NGO	CTS
+    NGO	HKO
+    OIT	KCZ
+    OIT	MYJ
+    OIT	OKA
+    OIT	KIX
+    OIT	CTS
+    OIT	TAK
+    OIT	NRT
+    OIT	HKO
+    OIT	EKK
+    OIT	AKJ
+    OKA	KCZ
+    OKA	FUK
+    OKA	KOJ
+    OKA	KMJ
+    OKA	MYJ
+    OKA	KMI
+    OKA	NGO
+    OKA	OIT
+    OKA	KIX
+    OKA	CTS
+    OKA	TAK
+    OKA	NRT
+    OKA	HKO
+    OKA	EKK
+    OKA	AKJ
+    OKA	NGS
+    KIX	KCZ
+    KIX	FUK
+    KIX	KMJ
+    KIX	KMI
+    KIX	OIT
+    KIX	OKA
+    KIX	CTS
+    KIX	NRT
+    KIX	HKO
+    KIX	EKK
+    KIX	AKJ
+    KIX	NGS
+    CTS	KCZ
+    CTS	FUK
+    CTS	KOJ
+    CTS	KMJ
+    CTS	MYJ
+    CTS	KMI
+    CTS	NGO
+    CTS	OIT
+    CTS	OKA
+    CTS	KIX
+    CTS	TAK
+    CTS	NRT
+    CTS	EKK
+    CTS	NGS
+    TAK	FUK
+    TAK	KOJ
+    TAK	KMJ
+    TAK	KMI
+    TAK	OIT
+    TAK	OKA
+    TAK	CTS
+    TAK	NRT
+    TAK	HKO
+    TAK	AKJ
+    TAK	NGS
+    NRT	KCZ
+    NRT	FUK
+    NRT	KOJ
+    NRT	KMJ
+    NRT	MYJ
+    NRT	KMI
+    NRT	OIT
+    NRT	OKA
+    NRT	KIX
+    NRT	CTS
+    NRT	TAK
+    NRT	HKO
+    NRT	EKK
+    NRT	AKJ
+    NRT	NGS
+    HKO	KCZ
+    HKO	FUK
+    HKO	KOJ
+    HKO	KMJ
+    HKO	MYJ
+    HKO	KMI
+    HKO	NGO
+    HKO	OIT
+    HKO	OKA
+    HKO	KIX
+    HKO	TAK
+    HKO	NRT
+    HKO	EKK
+    HKO	NGS
+    EKK	FUK
+    EKK	KOJ
+    EKK	KMJ
+    EKK	KMI
+    EKK	OIT
+    EKK	OKA
+    EKK	KIX
+    EKK	CTS
+    EKK	NRT
+    EKK	HKO
+    EKK	AKJ
+    EKK	NGS
+    AKJ	KCZ
+    AKJ	FUK
+    AKJ	KOJ
+    AKJ	KMJ
+    AKJ	MYJ
+    AKJ	KMI
+    AKJ	OIT
+    AKJ	OKA
+    AKJ	KIX
+    AKJ	TAK
+    AKJ	NRT
+    AKJ	EKK
+    AKJ	NGS
+    NGS	KCZ
+    NGS	MYJ
+    NGS	OKA
+    NGS	KIX
+    NGS	CTS
+    NGS	TAK
+    NGS	NRT
+    NGS	HKO
+    NGS	EKK
+    NGS	AKJ
+       """
+
+    db.get_collection(FLIGHTS_WEBSITES_ROUTE_CONF_TAB).delete_many({"source_website": website})  # 清空之前数据
+    temp_list = [i.strip() for i in routes.split("\n") if i.strip()]
+    routes = list(set(temp_list))  # 去重
+    routes.sort(key=temp_list.index)  # 保持原有顺序
+    # print(len(routes))
+    # total_route = {x for route in routes for x in route.split('\t')}
+    # print(f'一共需要 {len(total_route)} 条航线的城市机场对应信息')
+
+    insert_datas = []  # 列表里准备存字典
+
+    count = 0
+    for route in routes:
+        name_code_datas = get_from_to_data(route)
+        # print(route, name_code_datas)
+        from_city_code = name_code_datas.get("from_airport_code")
+        to_city_code = name_code_datas.get("to_airport_code")
+
+        from_airport_code = get_airport_data(from_city_code)
+        to_airport_code = get_airport_data(to_city_code)
+        dict_mode = {
+            "source_website": website,  # 数据来源网站
+            "website_status": 1,  # 网站是否采集状态
+            "flight_route_status": 1,  # 航线是否采集状态
+            "from_city_code": from_city_code,
+            "from_city_name": "",
+            "from_airport_code": from_airport_code,
+            "to_city_code": to_city_code,
+            "to_city_name": "",
+            "to_airport_code": to_airport_code,
+        }
+        insert_datas.append(dict_mode)
+        count += 1
+        if count % 50 == 0:
+            print("add {} ...".format(count))
+    db.get_collection(FLIGHTS_WEBSITES_ROUTE_CONF_TAB).insert_many(insert_datas)  # 一次录入多条数据
+    print("finish...")
+
+
+if __name__ == "__main__":
+    insert_routes()

+ 304 - 0
3.31GK/other_code/city_pair.py

@@ -0,0 +1,304 @@
+routes = """
+KCZ	FUK
+KCZ	KOJ
+KCZ	KMJ
+KCZ	KMI
+KCZ	OIT
+KCZ	OKA
+KCZ	AKJ
+KCZ	NGS
+FUK	KCZ
+FUK	MYJ
+FUK	NGO
+FUK	OKA
+FUK	TAK
+FUK	AKJ
+KOJ	KCZ
+KOJ	KMJ
+KOJ	MYJ
+KOJ	NGO
+KOJ	OKA
+KOJ	TAK
+KOJ	AKJ
+KMJ	KCZ
+KMJ	KOJ
+KMJ	MYJ
+KMJ	NGO
+KMJ	OKA
+KMJ	TAK
+KMJ	AKJ
+MYJ	FUK
+MYJ	KOJ
+MYJ	KMJ
+MYJ	KMI
+MYJ	OIT
+MYJ	OKA
+MYJ	AKJ
+MYJ	NGS
+KMI	KCZ
+KMI	MYJ
+KMI	OKA
+KMI	TAK
+KMI	AKJ
+NGO	FUK
+NGO	KOJ
+NGO	KMJ
+NGO	OKA
+OIT	KCZ
+OIT	MYJ
+OIT	OKA
+OIT	TAK
+OIT	AKJ
+OKA	KCZ
+OKA	FUK
+OKA	KOJ
+OKA	KMJ
+OKA	MYJ
+OKA	KMI
+OKA	NGO
+OKA	OIT
+OKA	TAK
+OKA	AKJ
+OKA	NGS
+TAK	FUK
+TAK	KOJ
+TAK	KMJ
+TAK	KMI
+TAK	OIT
+TAK	OKA
+TAK	AKJ
+TAK	NGS
+AKJ	KCZ
+AKJ	FUK
+AKJ	KOJ
+AKJ	KMJ
+AKJ	MYJ
+AKJ	KMI
+AKJ	OIT
+AKJ	OKA
+AKJ	TAK
+AKJ	NGS
+NGS	KCZ
+NGS	MYJ
+NGS	OKA
+NGS	TAK
+NGS	AKJ
+
+
+KCZ	FUK
+KCZ	KOJ
+KCZ	KMJ
+KCZ	KMI
+KCZ	OIT
+KCZ	OKA
+KCZ	KIX
+KCZ	CTS
+KCZ	NRT
+KCZ	HKO
+KCZ	AKJ
+KCZ	NGS
+FUK	KCZ
+FUK	MYJ
+FUK	NGO
+FUK	OKA
+FUK	KIX
+FUK	CTS
+FUK	TAK
+FUK	NRT
+FUK	HKO
+FUK	EKK
+FUK	AKJ
+KOJ	KCZ
+KOJ	KMJ
+KOJ	MYJ
+KOJ	NGO
+KOJ	OKA
+KOJ	CTS
+KOJ	TAK
+KOJ	NRT
+KOJ	HKO
+KOJ	EKK
+KOJ	AKJ
+KMJ	KCZ
+KMJ	KOJ
+KMJ	MYJ
+KMJ	NGO
+KMJ	OKA
+KMJ	KIX
+KMJ	CTS
+KMJ	TAK
+KMJ	NRT
+KMJ	HKO
+KMJ	EKK
+KMJ	AKJ
+MYJ	FUK
+MYJ	KOJ
+MYJ	KMJ
+MYJ	KMI
+MYJ	OIT
+MYJ	OKA
+MYJ	CTS
+MYJ	NRT
+MYJ	HKO
+MYJ	AKJ
+MYJ	NGS
+KMI	KCZ
+KMI	MYJ
+KMI	OKA
+KMI	KIX
+KMI	CTS
+KMI	TAK
+KMI	NRT
+KMI	HKO
+KMI	EKK
+KMI	AKJ
+NGO	FUK
+NGO	KOJ
+NGO	KMJ
+NGO	OKA
+NGO	CTS
+NGO	HKO
+OIT	KCZ
+OIT	MYJ
+OIT	OKA
+OIT	KIX
+OIT	CTS
+OIT	TAK
+OIT	NRT
+OIT	HKO
+OIT	EKK
+OIT	AKJ
+OKA	KCZ
+OKA	FUK
+OKA	KOJ
+OKA	KMJ
+OKA	MYJ
+OKA	KMI
+OKA	NGO
+OKA	OIT
+OKA	KIX
+OKA	CTS
+OKA	TAK
+OKA	NRT
+OKA	HKO
+OKA	EKK
+OKA	AKJ
+OKA	NGS
+KIX	KCZ
+KIX	FUK
+KIX	KMJ
+KIX	KMI
+KIX	OIT
+KIX	OKA
+KIX	CTS
+KIX	NRT
+KIX	HKO
+KIX	EKK
+KIX	AKJ
+KIX	NGS
+CTS	KCZ
+CTS	FUK
+CTS	KOJ
+CTS	KMJ
+CTS	MYJ
+CTS	KMI
+CTS	NGO
+CTS	OIT
+CTS	OKA
+CTS	KIX
+CTS	TAK
+CTS	NRT
+CTS	EKK
+CTS	NGS
+TAK	FUK
+TAK	KOJ
+TAK	KMJ
+TAK	KMI
+TAK	OIT
+TAK	OKA
+TAK	CTS
+TAK	NRT
+TAK	HKO
+TAK	AKJ
+TAK	NGS
+NRT	KCZ
+NRT	FUK
+NRT	KOJ
+NRT	KMJ
+NRT	MYJ
+NRT	KMI
+NRT	OIT
+NRT	OKA
+NRT	KIX
+NRT	CTS
+NRT	TAK
+NRT	HKO
+NRT	EKK
+NRT	AKJ
+NRT	NGS
+HKO	KCZ
+HKO	FUK
+HKO	KOJ
+HKO	KMJ
+HKO	MYJ
+HKO	KMI
+HKO	NGO
+HKO	OIT
+HKO	OKA
+HKO	KIX
+HKO	TAK
+HKO	NRT
+HKO	EKK
+HKO	NGS
+EKK	FUK
+EKK	KOJ
+EKK	KMJ
+EKK	KMI
+EKK	OIT
+EKK	OKA
+EKK	KIX
+EKK	CTS
+EKK	NRT
+EKK	HKO
+EKK	AKJ
+EKK	NGS
+AKJ	KCZ
+AKJ	FUK
+AKJ	KOJ
+AKJ	KMJ
+AKJ	MYJ
+AKJ	KMI
+AKJ	OIT
+AKJ	OKA
+AKJ	KIX
+AKJ	TAK
+AKJ	NRT
+AKJ	EKK
+AKJ	NGS
+NGS	KCZ
+NGS	MYJ
+NGS	OKA
+NGS	KIX
+NGS	CTS
+NGS	TAK
+NGS	NRT
+NGS	HKO
+NGS	EKK
+NGS	AKJ
+   """
+# 网站没有的城市/机场码: OSA SPK TYO SHI, 删去它们的航段
+temp_list = [i.strip() for i in routes.split("\n") if i.strip()]
+
+routes = list(set(temp_list))  # 去重
+routes.sort(key=temp_list.index)  # 保持原有顺序
+print(f'一共需要采集 {len(routes)} 条航段')
+
+total_route = {x for route in routes for x in route.split('\t')}
+
+print(f'一共需要 {len(total_route)} 条城市机场对应信息')
+
+
+
+print(total_route)
+
+

+ 18 - 12
3.31Gk航司/请求-curl_cffi.py → 3.31GK/other_code/request_curl_cffi.py

@@ -13,6 +13,7 @@ from loguru import logger
 class GK:
 
     def __init__(self):
+        self.akm_url = 'https://www.jetstar.com/c9NCrswc1aL9a_poKlkL/Y5OpJhrfcSzf/MwUVAg/SE0/adRNiWCo'
         self.search_flights_api = "https://booking.jetstar.com/hk/zh/booking/search-flights"
 
         self.headers = {
@@ -32,30 +33,34 @@ class GK:
             "upgrade-insecure-requests": "1",
             "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"
         }
-        with open('./akm逆向/逆向.js', encoding='utf-8') as f:
+        with open('../akm/akm_5.26.js', encoding='utf-8') as f:
             js = f.read()
         self.ctx = execjs.compile(js)
         self.session = requests.Session()
 
     def get_cookie(self):
         # akm js file url
-        akm_url = "https://booking.jetstar.com/MkuYlo/pcp/LD0/PPluEQ/1ik7QcJffXbmL53i/QTcvXmg7/KS5kC3N/VRQcB"
+        akm_url = self.akm_url
+        statusTs = str(int(time.time() * 1000))
 
         data = {
-            'sensor_data': self.ctx.call('encrypt1')
+            'sensor_data': self.ctx.call('encrypt1', statusTs)
         }
         response = self.session.post(akm_url, headers=self.headers, verify=False, data=data,
-                                     impersonate='chrome101',
+                                     impersonate='chrome100',
                                      # 不指定 impersonate 时,TLS 指纹是 curl 原生的,而非浏览器指纹(依旧过不了检测)。需显式设置该参数以绕过 TLS 指纹检测
                                      http_version=2
                                      )
 
-        print(response.text)
+        logger.info(f'第一次请求cookie bmsz 状态吗 {response.status_code}')
+        print('内容 ', response.text)
+        print('响应cookie ', response.cookies.get_dict())
+
         bmsz = response.cookies.get_dict()['bm_sz']
         print('bmsz =>', bmsz)
 
         data2 = {
-            "sensor_data": self.ctx.call('encrypt2', bmsz)
+            "sensor_data": self.ctx.call('encrypt2', statusTs, bmsz)
         }
 
         data2 = json.dumps(data2)
@@ -63,8 +68,8 @@ class GK:
                                       impersonate='chrome101',
                                       http_version=2
                                       )
+        logger.info(f'第2次请求验证 cookie bmsz 状态吗 {response.status_code}')
         print(response2.text)
-        print(response2.status_code)
         print(response2.cookies.get_dict())
 
     @retrying.retry(stop_max_attempt_number=3)
@@ -74,13 +79,14 @@ class GK:
             response = self.session.get(
                 url,
                 headers=self.headers, params=params,
-                timeout=15,
+                timeout=20,
                 verify=False,
                 # proxies=proxies
-                impersonate='chrome101',
+                impersonate='chrome99',
                 http_version=2
             )
             response.raise_for_status()
+            print('请求返回cookie', response.cookies.get_dict())
             return response
         # 捕获超时请求,可能是cookie不行了,更新后报错触发重试
         except Timeout as e:
@@ -148,16 +154,16 @@ class GK:
 
     def run(self, start_date, end_date):
         self.get_cookie()
-        # 获取采集时间
+        # # 获取采集时间
         for num, datetime_str in enumerate(self.gen_datetime(start_date, end_date), start=1):
             # if num % 5 == 0:
             #     self.session = requests.Session()
             #     self.get_cookie()
 
             self.get_data(datetime_str)
-            # time.sleep(1)
+        #     # time.sleep(1)
 
 
 if __name__ == '__main__':
     gk = GK()
-    gk.run(start_date='2025-05-15', end_date='2025-05-27')
+    gk.run(start_date='2025-05-29', end_date='2025-06-29')

+ 1 - 1
3.31Gk航司/请求-httpx.py → 3.31GK/other_code/request_httpx.py

@@ -18,7 +18,7 @@ class GK:
     def __init__(self):
         self.search_flights_api = "https://booking.jetstar.com/hk/zh/booking/search-flights"
 
-        with open('./akm逆向/逆向.js', encoding='utf-8') as f:
+        with open('../akm/逆向.js', encoding='utf-8') as f:
             js = f.read()
         self.ctx = execjs.compile(js)
         ja3 = "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,5-10-11-17613-45-43-0-23-18-65037-27-35-13-51-65281-16-41,4588-29-23-24,0"

+ 289 - 0
3.31GK/other_code/request_pyhttpx.py

@@ -0,0 +1,289 @@
+import requests
+import pyhttpx
+import time
+from datetime import datetime, timedelta
+
+import retrying
+import execjs
+from lxml import etree
+import json
+from loguru import logger
+
+import threading
+from queue import Queue
+
+
+# import pandas as pd
+
+
+class GK:
+
+    def __init__(self):
+        self.search_flights_api = "https://booking.jetstar.com/hk/zh/booking/search-flights"
+
+        self.headers = {
+            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36',
+            # 'user-agent': get_random_user_agent(),
+            'Accept-Encoding': 'gzip, deflate, br',
+            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
+            'Connection': 'keep-alive',
+            'Content-Type': 'application/x-www-form-urlencoded',
+            'accept-language': 'zh-CN,zh;q=0.9',
+            'cache-control': 'no-cache',
+            'pragma': 'no-cache',
+            'priority': 'u=0, i',
+            'referer': 'https://booking.jetstar.com/',
+            'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
+            'sec-ch-ua-mobile': '?0',
+            'sec-ch-ua-platform': '"Windows"',
+            'sec-fetch-dest': 'document',
+            'sec-fetch-mode': 'navigate',
+            'sec-fetch-site': 'same-origin',
+            'sec-fetch-user': '?1',
+            'upgrade-insecure-requests': '1'
+        }
+
+        with open('../akm/逆向1.js', encoding='utf-8') as f:
+            js = f.read()
+        self.ctx = execjs.compile(js)
+        # self.session = pyhttpx
+        # self.ip = 100000000000
+        # self.proxies = {
+        #     'http': f'http://B_3351_HK___5_ss-{self.ip}:ev2pjj@proxy.renlaer.com:7778',
+        #     'https': f'http://B_3351_HK___5_ss-{self.ip}:ev2pjj@proxy.renlaer.com:7778'
+        # }
+
+        self.lock = threading.Lock()
+        # self.cookies_queue = CookieQueue()
+        self.cookies_queue = Queue()
+        self.ja3_queue = Queue()
+        self.task_queue = Queue()
+        self.resp_data_queue = Queue()
+
+    @retrying.retry(stop_max_attempt_number=3, wait_fixed=4000)
+    def get_ja3_str(self):
+        url = "http://8.218.51.130:9003/api/v1/ja3"
+        payload = {}
+        headers = {
+            'cid': '750B5141EDBF7FA6F73A99C768130099'
+        }
+        while True:
+            if self.ja3_queue.qsize() < 5:
+                response = requests.get(url, headers=headers, data=payload)
+                if response.status_code == 200:
+                    res_json = response.json()
+                    if res_json.get("code") == 0:
+                        ja3 = res_json.get("data").get("ja3_str")
+                        ua = res_json.get("data").get("ua")
+                        if "--" not in ja3 and ",," not in ja3:
+                            end_data = (
+                                ua,
+                                ja3
+                            )
+                            self.ja3_queue.put(end_data)
+
+            time.sleep(3)
+
+    @retrying.retry(stop_max_attempt_number=3, wait_fixed=4000)
+    def request_new_cookie(self):
+        logger.debug('正在获取 cookie bm-sz...')
+
+        ua, ja3 = self.ja3_queue.get()
+        # print(ua, ja3)
+        sess = pyhttpx.HttpSession(
+            ja3=ja3,  # 自定义 JA3 字符串
+            http2=True,  # 启用 HTTP/2
+        )
+        # akm js file url
+        akm_url = "https://booking.jetstar.com/MkuYlo/pcp/LD0/PPluEQ/1ik7QcJffXbmL53i/QTcvXmg7/KS5kC3N/VRQcB"
+
+        data = {
+            'sensor_data': self.ctx.call('encrypt1')
+        }
+        response = sess.post(akm_url, headers=self.headers, verify=False, data=data,
+                             # proxies=self.proxies
+                             )
+
+        # print(response.text)
+        bmsz = response.cookies['bm_sz']
+
+        data2 = {
+            "sensor_data": self.ctx.call('encrypt2', bmsz)
+        }
+
+        data2 = json.dumps(data2)
+        response2 = sess.post(akm_url, headers=self.headers, data=data2, verify=False)
+
+        # print(response2.text)
+        # print(response2.status_code)
+        # print(response2.cookies.get_dict())
+        # with self.lock:
+        logger.debug(f'成功获取到 cookie :{bmsz}')
+
+        return response.cookies
+        # return bmsz
+
+    def _refresh_cookie(self):
+        while True:
+            if self.cookies_queue.qsize() < 2:
+                cookie = self.request_new_cookie()
+
+                self.cookies_queue.put(cookie)
+
+            time.sleep(3)
+
+    def gen_task(self, start_date, end_date):
+        """将每个城市对与日期组合生成独立任务, 上传到任务队列"""
+        # 获取采集城市对
+        # for city_code in self.gen_city():
+        # 获取采集时间
+        for datetime_str in self.gen_datetime(start_date, end_date):
+            # self.task_queue.put((city_code, datetime_str))
+            self.task_queue.put((datetime_str))
+
+    @retrying.retry(stop_max_attempt_number=2)
+    def send_get(self, url, params, bmsz_cookie):
+        ua, ja3_str = self.ja3_queue.get()
+        sess = pyhttpx.HttpSession(
+            ja3=ja3_str,  # 自定义 JA3 字符串
+            http2=True,  # 启用 HTTP/2
+        )
+        headers = {
+            # 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36',
+            'user-agent': ua,
+            'Accept-Encoding': 'gzip, deflate, br',
+            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
+            'Connection': 'keep-alive',
+            'Content-Type': 'application/x-www-form-urlencoded',
+            'accept-language': 'zh-CN,zh;q=0.9',
+            'cache-control': 'no-cache',
+            'pragma': 'no-cache',
+            'priority': 'u=0, i',
+            'referer': 'https://booking.jetstar.com/',
+            'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
+            'sec-ch-ua-mobile': '?0',
+            'sec-ch-ua-platform': '"Windows"',
+            'sec-fetch-dest': 'document',
+            'sec-fetch-mode': 'navigate',
+            'sec-fetch-site': 'same-origin',
+            'sec-fetch-user': '?1',
+            'upgrade-insecure-requests': '1'
+        }
+        response = sess.get(
+            url,
+            headers=headers, params=params, cookies=bmsz_cookie,
+            timeout=15,
+            verify=False,
+        )
+        self.ja3_queue.put((ua, ja3_str))  # 回收破烂
+        # print(response.text)
+
+        # logger.info(f'')
+        return response
+
+    def get_data(self):
+        while True:
+            datetime_str = self.task_queue.get()
+            bmsz_cookie = self.cookies_queue.get()
+            params = {
+                "s": "true",
+                "adults": "1",  # 成年人
+                "children": "0",  # 儿童
+                "infants": "0",  # 婴儿
+                "selectedclass1": "economy",  # 选择类型:经济舱
+                "currency": "CNY",  # 货币
+                "mon": "true",
+                "channel": "DESKTOP",
+                "origin1": "PVG",  # 出发地
+                "destination1": "NRT",  # 目的地
+                "departuredate1": datetime_str  # 出发时间
+            }
+            logger.info(f'正在采集 {datetime_str} 航班数据...')
+            try:
+                response = self.send_get(self.search_flights_api, params, bmsz_cookie)
+                self.resp_data_queue.put((datetime_str, response))
+                # 请求成功,归还Cookie
+                self.cookies_queue.put(bmsz_cookie)  # 成功时放回cookie
+
+            except Exception as e:
+                logger.error(f"错误发生: {e}")
+
+                self.task_queue.put(datetime_str)
+
+            finally:
+                self.task_queue.task_done()
+
+    def parse_data(self):
+        while True:
+            datetime_str, response = self.resp_data_queue.get()
+
+            html = etree.HTML(response.text)
+            data = html.xpath("//script[@id='bundle-data-v2']/text()")
+            if data:
+                json_data = json.loads(data[0])
+                logger.info(f'获取数据成功 {datetime_str} => {json_data}')
+            else:
+                logger.warning(f'{datetime_str} 当天暂无数据 / 触发验证码')
+                print(response.text)
+
+            self.resp_data_queue.task_done()
+
+    def gen_city(self):
+        """提取Excel表格的城市对信息, 用set去重"""
+        # 只读取Excel的Sheet1的航段信息, 将读取的数据存储在 df(DataFrame 对象)中。
+        df = pd.read_excel(
+            self.excel_path,
+            sheet_name="Sheet1",
+            usecols=["出发机场", "到达机场"]  # 只读取 "出发机场" 和 "到达机场" 两列。
+        )
+
+        segment_info = set()
+        segment_info.add('YNT,XIY')
+
+        # 遍历 DataFrame 的每一行
+        # for row in df.itertuples(index=True, name='Pandas'):
+        #     # 访问行中的数据
+        #     segment_info.add(row.出发机场 + ',' + row.到达机场)
+        # logger.info(f'去重后的航段长度: {len(segment_info)}, {segment_info}')
+        return segment_info
+
+    @staticmethod
+    def gen_datetime(start_date, end_date):
+        current_date = datetime.strptime(start_date, '%Y-%m-%d')
+        end_date = datetime.strptime(end_date, '%Y-%m-%d')
+        date_list = []
+        while current_date <= end_date:
+            date_list.append(current_date.strftime('%Y-%m-%d'))  # 转换为字符串格式存储
+            current_date += timedelta(days=1)
+        return date_list
+
+    def run(self, start_date, end_date):
+        thread_list = []
+
+        self.gen_task(start_date, end_date)
+
+        for _ in range(2):
+            t_get_cookie = threading.Thread(target=self._refresh_cookie)
+            thread_list.append(t_get_cookie)
+
+        t_get_ja3 = threading.Thread(target=self.get_ja3_str)
+        thread_list.append(t_get_ja3)
+
+        for _ in range(6):
+            t_get_data = threading.Thread(target=self.get_data)
+            thread_list.append(t_get_data)
+
+        t_parse_data = threading.Thread(target=self.parse_data)
+        thread_list.append(t_parse_data)
+
+        for t_obj in thread_list:
+            t_obj.setDaemon(True)
+            t_obj.start()
+
+        for q in [self.task_queue, self.resp_data_queue]:
+            q.join()
+
+
+if __name__ == '__main__':
+    gk = GK()
+    gk.run(start_date='2025-06-01', end_date='2025-06-30')

+ 22 - 20
3.31Gk航司/请求requests 多线程.py → 3.31GK/other_code/requests_multi_thread.py

@@ -3,7 +3,6 @@ from datetime import datetime, timedelta
 
 import requests
 
-from requests.exceptions import Timeout
 import retrying
 import execjs
 from lxml import etree
@@ -48,7 +47,7 @@ class GK:
             'sec-fetch-user': '?1',
             'upgrade-insecure-requests': '1'
         }
-        with open('./akm逆向/逆向.js', encoding='utf-8') as f:
+        with open('../akm/逆向1.js', encoding='utf-8') as f:
             js = f.read()
         self.ctx = execjs.compile(js)
         self.session = requests.Session()
@@ -69,7 +68,7 @@ class GK:
     @retrying.retry(stop_max_attempt_number=3,  wait_fixed=4000)
     def get_cookie(self):
         logger.debug('正在获取 cookie bm-sz...')
-
+        self.session.cookies.clear()
         # akm js file url
         akm_url = "https://booking.jetstar.com/MkuYlo/pcp/LD0/PPluEQ/1ik7QcJffXbmL53i/QTcvXmg7/KS5kC3N/VRQcB"
 
@@ -99,12 +98,10 @@ class GK:
 
     def get_cookie_thread(self):
         while True:
-            if self.cookies_queue.qsize() < 1:
-                new_cookie = self.get_cookie()
-                cookies = {
-                    "bm_sz": new_cookie
-                }
-                self.cookies_queue.put(cookies)
+            if self.cookies_queue.qsize() < 3:
+                bmsz = self.get_cookie()
+
+                self.cookies_queue.put(bmsz)
 
             time.sleep(15)
 
@@ -137,24 +134,24 @@ class GK:
             self.task_queue.put((datetime_str))
 
     @retrying.retry(stop_max_attempt_number=2)
-    def send_get(self, url, params, cookies):
+    def send_get(self, url, params, bmsz):
+        cookies = {
+            "bm_sz": bmsz
+        }
         response = requests.get(
             url,
             headers=self.headers, params=params, cookies=cookies,
             timeout=15,
             verify=False,
         )
-        # print(response)
         # print(response.text)
         response.raise_for_status()
-        self.cookies_queue.put(cookies)
         return response
 
-    @retrying.retry(stop_max_attempt_number=3)
     def get_data(self):
         while True:
             datetime_str = self.task_queue.get()
-            cookies = self.cookies_queue.get()
+            bmsz = self.cookies_queue.get()
             params = {
                 "s": "true",
                 "adults": "1",  # 成年人
@@ -170,15 +167,21 @@ class GK:
             }
             logger.info(f'正在采集 {datetime_str} 航班数据...')
             try:
-                response = self.send_get(self.search_flights_api, params, cookies)
+                response = self.send_get(self.search_flights_api, params, bmsz)
+                ret_bmsz = response.cookies.get_dict()['bm_sz']  # 收集返回的 bmsz,也能用来请求
+                self.cookies_queue.put(ret_bmsz)
                 self.resp_data_queue.put((datetime_str, response))
 
+            except requests.exceptions.Timeout:
+                logger.error(f"请求超时: 更换bmsz ")
+                self.task_queue.put(datetime_str)
+
             except Exception as e:
                 logger.error(e)
                 self.task_queue.put(datetime_str)
-                raise
 
             finally:
+                self.cookies_queue.put(bmsz)
                 self.task_queue.task_done()
                 self.cookies_queue.task_done()
 
@@ -210,9 +213,8 @@ class GK:
 
         self.gen_task(start_date, end_date)
 
-        for _ in range(1):
-            t_get_cookie = threading.Thread(target=self.get_cookie_thread)
-            thread_list.append(t_get_cookie)
+        t_get_cookie = threading.Thread(target=self.get_cookie_thread)
+        thread_list.append(t_get_cookie)
 
         for _ in range(1):
             t_get_data = threading.Thread(target=self.get_data)
@@ -231,4 +233,4 @@ class GK:
 
 if __name__ == '__main__':
     gk = GK()
-    gk.run(start_date='2025-06-15', end_date='2025-06-27')
+    gk.run(start_date='2025-06-01', end_date='2025-06-30')

+ 38 - 26
3.31Gk航司/其他/响应数据分析.py → 3.31GK/other_code/response_data_parse.py

@@ -2,32 +2,34 @@ var = {
     "Trips": [
         {
             "TripIndex": 0,
+            # ---
             "Flights": [
                 {
                     "IsCjFare": false,
                     "JourneySellKey": "GK~  36~ ~~PVG~04/21/2025 02:15~NRT~04/21/2025 06:20~~^GK~ 631~ ~~NRT~04/21/2025 12:40~KMI~04/21/2025 14:45~~",
                     "HighlightProductClass": null,
                     "Lob": "GKINT",
-                    "JourneyStations": "PVG-NRT-KMI",
+                    "JourneyStations": "PVG-NRT-KMI",  # 航班的中转路径
                     "SelectedServiceBundleCode": null,
                     "SelectedProductClass": null,
+                    # 这里面是各种票价
                     "Bundles": [
                         {
                             "ProductClass": null,
-                            "ServiceBundleCode": "S000",
-                            "ServiceBundleCodeType": 0,
-                            "Amount": 0,
-                            "CjAmount": 0,
-                            "RegularInclusiveAmount": "1219.56",
+                            "ServiceBundleCode": "S000",  # 服务套餐的唯一代码,用于系统内部标识,可用来区分不同的票价
+                            "ServiceBundleCodeType": 0,   #  套餐代码类型,可能为枚举值(如 0=基础套餐,1=促销套餐等)
+                            "Amount": 0,  # 当前套餐的销售价格  附加服务包费用,
+                            "CjAmount": 0,  # 可能为“差价金额”(
+                            "RegularInclusiveAmount": "1219.56",  # 常规包含的总金额(可能是原价或基准价
                             "CjInclusiveAmount": 0,
                             "FlightFareKey": "2~E1~~JQ~ELECOE1~7200~~0~1~~X^1~H~~JQ~HLECOH~7000~~0~6~~",
                             "CjFlightFareKey": null,
                             "SavingPercent": 0,
-                            "IsSaleFare": false,
+                            "IsSaleFare": false,  # 是否为促销价格
                             "HasCjFareBundle": false,
-                            "IsBusinessClassBundle": false,
+                            "IsBusinessClassBundle": false,  # 是否为商务舱套餐
                             "BundleLabel": "基本票",
-                            "BundleName": "基本票",
+                            "BundleName": "基本票",  # 套餐正式名称,
                             "BundleSubHeader": "我們的基本票價",
                             "BundleSsrCode": "STRT",
                             "IsStarterBundle": true,
@@ -50,7 +52,7 @@ var = {
                             "IsBusinessClassBundle": false,
                             "BundleLabel": "基本加值套票",
                             "BundleName": "基本加值套票",
-                            "BundleSubHeader": "行李 + 座位 + 餐膳",
+                            "BundleSubHeader": "行李 + 座位 + 餐膳",  # 套餐子标题,描述包含的核心服务内容
                             "BundleSsrCode": "STPL",
                             "IsStarterBundle": false,
                             "BundleProductName": "基本加值套票",
@@ -119,13 +121,14 @@ var = {
                             "Position": "bottom"
                         }
                     ],
+                    # 显示航班信息/ 航班数据在这里面
                     "DisplayFlightInfo": {
-                        "Legs": [
+                        "Legs": [  # 有超过2个元素时,是中转航班
                             {
                                 "Color": "flight-one",
                                 "HasToolTip": false,
-                                "IsConnectingFlight": false,
-                                "IsInternational": true,
+                                "IsConnectingFlight": false,  # 是否转机
+                                "IsInternational": true,  # 国际航班。
                                 "IsDepartingFromInternationalTerminal": false,
                                 "DepartureStation": "PVG",
                                 "ArrivalStation": "NRT",
@@ -135,6 +138,7 @@ var = {
                                     "Type": "32J",
                                     "IsAircraftType": true
                                 },
+                                # 航班号  GK36
                                 "FlightDesignator": {
                                     "FlightNumber": "  36",
                                     "CarrierCode": "GK",
@@ -142,14 +146,14 @@ var = {
                                 },
                                 "DisplayDepartureAirportTerminal": "上海 (浦東) - 2號航站樓",
                                 "DisplayArrivalAirportTerminal": "東京 (成田) - 3號航站樓",
-                                "IsAircraftBusinessCabin": false,
+                                "IsAircraftBusinessCabin": false, # 飞机是商务舱吗?
                                 "DisplayTravelDuration": "3小時 5分鐘",
                                 "DisplayAircraft": "空中巴士 A320-200",
-                                "OperatorName": "NGBE.Global.Carrier.GK",
+                                "OperatorName": "NGBE.Global.Carrier.GK",  # 运营商名称
                                 "IsSubjectToGovtApproval": false,
                                 "TransitAirport": "東京 (成田)",
                                 "TransitDuration": "6小時 20分鐘",
-                                "CabinType": "Y",
+                                "CabinType": "Y",  # 舱位类型
                                 "Lob": "GKINT"
                             },
                             {
@@ -184,16 +188,19 @@ var = {
                                 "Lob": "GKDOM"
                             }
                         ],
+                        # 商务航班信息
                         "BusinessFlightInfo": {
                             "IsPreselected": false,
                             "IsSpecialFare": false,
                             "IsLowOnSeats": false,
                             "HasAlert": false,
-                            "TicketsAvailability": "NotAvailable",
-                            "RemainingSeats": 0,
+                            # ​机票状态
+                            "TicketsAvailability": "NotAvailable",  # 不可用
+                            "RemainingSeats": 0,  # 剩余座位
                             "ShouldShowSeatCountdownLabel": false,
                             "IsFlexSameDayChange": false
                         },
+                        # 经济航班信息
                         "EconomyFlightInfo": {
                             "IsPreselected": false,
                             "IsSpecialFare": true,
@@ -221,8 +228,8 @@ var = {
                         },
                         "OriginAirport": "上海 (浦東)",
                         "DestinationAirport": "宮崎",
-                        "StandardTimeOfDeparture": "2025-04-21T02:15:00",
-                        "StandardTimeOfArrival": "2025-04-21T14:45:00",
+                        "StandardTimeOfDeparture": "2025-04-21T02:15:00",  # ​​计划起飞时间​
+                        "StandardTimeOfArrival": "2025-04-21T14:45:00",    # 计划到达时间​
                         "TravelTime": "11:30:00",
                         "RouteName": "上海 (浦東) 至 宮崎"
                     },
@@ -419,6 +426,8 @@ var = {
                         "JclColorVariant": "bundle-100"
                     }
                 ],
+
+
                 "Disclaimers": {
                     "QFFPointsTC": "NGBE.Bundles.BundleRules.Qantas",
                     "EKPointsTC": "NGBE.Bundles.BundleRules.Emirates",
@@ -447,23 +456,26 @@ var = {
                 ]
             }
         ],
+
+        # 航班包含的服务
         "Inclusions": [
             {
-                "ProductName": "CarryOnBaggage",
+                # 标识行李类型(如手提行李、托运行李)
+                "ProductName": "CarryOnBaggage",  #  随身行李
                 "IsIncluded": true,
-                "DisplayText": "7 公斤",
-                "Title": "手提行李",
+                "DisplayText": "7 公斤",  # 行李额度
+                "Title": "手提行李",    # 行李类型名称
                 "SubTitle": null,
                 "SsrCode": null,
                 "SortOrder": 1,
-                "CabinType": "Economy",
+                "CabinType": "Economy", # 舱位等级
                 "RefId": "PgmDQDA29lNhh1x6eWEP+w==",
                 "IconVariant": "economy-carry-on-baggage"
             },
             {
-                "ProductName": "CheckedBaggage",
+                "ProductName": "CheckedBaggage",  # 托运行李
                 "IsIncluded": false,
-                "DisplayText": "稍後添加",
+                "DisplayText": "稍後添加",          # 行李额度
                 "Title": "託運行李",
                 "SubTitle": null,
                 "SsrCode": null,

+ 0 - 0
3.31Gk航司/其他/控制流平坦化-状态机为变量/ast.js → 3.31GK/other_code/控制流平坦化-状态机为变量/ast.js


+ 0 - 0
3.31Gk航司/其他/控制流平坦化-状态机为变量/encode.js → 3.31GK/other_code/控制流平坦化-状态机为变量/encode.js


+ 0 - 0
3.31Gk航司/其他/控制流平坦化-状态机为变量/test.js → 3.31GK/other_code/控制流平坦化-状态机为变量/test.js


+ 432 - 0
3.31GK/req_tls_client.py

@@ -0,0 +1,432 @@
+import threading
+import time
+from queue import Queue
+
+import requests
+from lxml import etree
+import json
+
+import random
+from datetime import datetime, timedelta
+
+import execjs
+from loguru import logger
+import tls_client
+import retrying
+
+from urllib.parse import urljoin
+
+
+# requests = requests.Session()
+
+
+class GK:
+
+    def __init__(self):
+        self.search_flights_api = "https://booking.jetstar.com/hk/zh/booking/search-flights"
+        self.headers = {
+            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
+            "Accept-Language": "zh-CN,zh;q=0.9",
+            "Connection": "keep-alive",
+            "Referer": "https://www.jetstar.com/",
+            "Sec-Fetch-Dest": "document",
+            "Sec-Fetch-Mode": "navigate",
+            "Sec-Fetch-Site": "same-site",
+            "Sec-Fetch-User": "?1",
+            "Upgrade-Insecure-Requests": "1",
+            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
+            "sec-ch-ua": "\"Google Chrome\";v=\"135\", \"Not-A.Brand\";v=\"8\", \"Chromium\";v=\"135\"",
+            "sec-ch-ua-mobile": "?0",
+            "sec-ch-ua-platform": "\"Windows\""
+        }
+        with open('akm/akm_5.26.js', encoding='utf-8') as f:
+            js = f.read()
+        self.ctx = execjs.compile(js)
+        self.proxies_url = 'http://B_3351_HK___5_ss-{}:ev2pjj@proxy.renlaer.com:7778'
+
+        self.cookies_queue = Queue()
+        self.ja3_queue = Queue()
+        self.task_queue = Queue()
+        self.resp_data_queue = Queue()
+
+        # 使用本地代理软件
+        self.proxies = {
+            "http": "http://127.0.0.1:7897",
+            "https": "http://127.0.0.1:7897"
+        }
+
+    def get_ja3_str(self):
+        url = "http://8.218.51.130:9003/api/v1/ja3"
+        payload = {}
+        headers = {
+            'cid': '750B5141EDBF7FA6F73A99C768130099'
+        }
+        while True:
+            if self.ja3_queue.qsize() < 3:
+                try:
+                    response = requests.get(url, headers=headers, data=payload, timeout=15)
+                    if response.status_code == 200:
+                        # print(response.json())
+                        res_json = response.json()
+                        if res_json.get("code") == 0:
+                            ja3 = res_json.get("data").get("ja3_str")
+                            ua = res_json.get("data").get("ua")
+                            if "--" not in ja3 and ",," not in ja3:
+                                end_data = (
+                                    ua,
+                                    ja3
+                                )
+                                # logger.debug('获取ja3成功...')
+                                self.ja3_queue.put(end_data)
+                except Exception as e:
+                    logger.error(f'ja3接口错误: {e}')
+
+            time.sleep(3)
+
+    @retrying.retry(stop_max_attempt_number=3, wait_fixed=3000)
+    def request_new_cookie(self):
+        statusTs = int(time.time() * 1000)
+        # ua, ja3_string = self.ja3_queue.get()
+        ua, ja3_string = self.ja3_queue.get()
+        # ip = ''.join(random.choices('0123456789', k=12))
+        # proxies = {
+        #     'http': self.proxies_url.format(ip),
+        #     'https': self.proxies_url.format(ip)
+        # }
+        # print(proxies)
+        # browser = random.choice(self.BROWSER)
+        """
+        注意:ja3 和 client_identifier、 random_tls_extension_order不能同时使用
+        否则存在 潜在冲突,可能导致 JA3 指纹不符合预期,
+        具体原因如下:
+            参数优先级冲突
+                ja3_string 是直接定义 JA3 指纹的 完整参数,会覆盖 client_identifier 的默认配置。
+                若同时设置 ja3_string 和 client_identifier,client_identifier 的浏览器预置参数会被忽略,仅 ja3_string 生效。
+            随机扩展顺序干扰
+                random_tls_extension_order=True 会打乱 TLS 扩展的顺序,导致 JA3 指纹动态变化。
+                虽然增强了匿名性,但若目标网站检测 JA3 的稳定性(如固定指纹校验),此配置会触发反爬机制。       
+        """
+        get_ck_session = tls_client.Session(
+            ja3_string=ja3_string,
+        )
+        headers = {
+            # 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36',
+            'user-agent': ua,
+            'Accept-Encoding': 'gzip, deflate, br',
+            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
+            'Connection': 'keep-alive',
+            'Content-Type': 'application/x-www-form-urlencoded',
+            'accept-language': 'zh-CN,zh;q=0.9',
+            'cache-control': 'no-cache',
+            'pragma': 'no-cache',
+            'priority': 'u=0, i',
+            'referer': 'https://booking.jetstar.com/',
+            'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
+            'sec-ch-ua-mobile': '?0',
+            'sec-ch-ua-platform': '"Windows"',
+            'sec-fetch-dest': 'document',
+            'sec-fetch-mode': 'navigate',
+            'sec-fetch-site': 'same-origin',
+            'sec-fetch-user': '?1',
+            'upgrade-insecure-requests': '1'
+        }
+        # akm js file url
+        akm_url = "https://www.jetstar.com/w6N0DejiHPXeE_PZTkeSCCzH/3XiJLNQzXNpfYO/EA1mYRtQBw/LV/Y8ahE0KUo"
+
+        data = {
+            'sensor_data': self.ctx.call('encrypt1', statusTs)
+        }
+        response1 = get_ck_session.post(akm_url, headers=headers, data=data, timeout_seconds=15,
+                                        proxy=self.proxies
+                                        )
+
+        # print(response1.status_code)
+        # print(response1.text)
+        # print(response1.cookies.get_dict())
+        # print('111', response.headers)
+        bmsz = response1.cookies.get_dict()['bm_sz']
+        # print('bmsz => ', bmsz)
+
+        data2 = {
+            "sensor_data": self.ctx.call('encrypt2', statusTs, bmsz)
+        }
+
+        data2 = json.dumps(data2)
+        response2 = get_ck_session.post(akm_url, headers=headers, data=data2, timeout_seconds=15,
+                                        proxy=self.proxies
+                                        )
+        logger.debug('成功获取 cookie bm-sz: {}'.format(bmsz[10:]))
+
+        # print(response2.text)
+        # print(response2.cookies.get_dict())
+        if response2.status_code == 201:
+            # print('响应cookie1', response1.cookies.get_dict())
+            # 返回第一次请求响应的cookie
+            return response1.cookies.get_dict()
+        else:
+            logger.error('状态码错误{}'.format(response2.status_code))
+            print(response2.text)
+
+    def _refresh_cookie(self):
+        while True:
+            if self.cookies_queue.qsize() < 3:
+                cookie = self.request_new_cookie()
+
+                self.cookies_queue.put(cookie)
+
+            time.sleep(3)
+
+    @retrying.retry(stop_max_attempt_number=5, wait_fixed=3000)
+    def request_with_redirect(self, url, params, bmsz_cookie, max_redirects=3):
+        """"""
+        ua, ja3_string = self.ja3_queue.get()
+        # ip = ''.join(random.choices('0123456789', k=12))
+        # proxies = {
+        #     'http': self.proxies_url.format(ip),
+        #     'https': self.proxies_url.format(ip)
+        # }
+
+        req_session = tls_client.Session(
+            ja3_string=ja3_string,  # 直接注入自定义指纹
+        )
+        headers = {
+            'user-agent': ua,
+            'Accept-Encoding': 'gzip, deflate, br',
+            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
+            'Connection': 'keep-alive',
+            'Content-Type': 'application/x-www-form-urlencoded',
+            'accept-language': 'zh-CN,zh;q=0.9',
+            'cache-control': 'no-cache',
+            'pragma': 'no-cache',
+            'priority': 'u=0, i',
+            'referer': 'https://booking.jetstar.com/',
+            'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
+            'sec-ch-ua-mobile': '?0',
+            'sec-ch-ua-platform': '"Windows"',
+            'sec-fetch-dest': 'document',
+            'sec-fetch-mode': 'navigate',
+            'sec-fetch-site': 'same-origin',
+            'sec-fetch-user': '?1',
+            'upgrade-insecure-requests': '1'
+        }
+        redirect_count = 0
+        current_url = url
+
+        while redirect_count < max_redirects:
+            response = req_session.get(current_url, headers=headers, cookies=bmsz_cookie, params=params,
+                                       timeout_seconds=15,  # timeout
+                                       proxy=self.proxies
+                                       )
+
+            print(response.status_code)
+            # print(response.text)
+
+            # 检查是否为重定向状态码
+            if response.status_code in (301, 302, 303, 307, 308):
+                # 获取 Location 头(需处理相对路径)
+                location = response.headers.get("Location")
+                # if not location:
+                #     break
+                current_url = urljoin(current_url, location)
+                redirect_count += 1
+                # print(f"Redirecting to: {current_url}")
+
+                # 可选:继承原始请求的特定 Headers(如 Referer)
+                # headers["Referer"] = response.url
+            else:
+                # 请求成功,归还Cookie
+                # print('请求成功的cookie', req_session.cookies.get_dict())
+                # print('请求响应的cookie', response.cookies.get_dict())
+                self.cookies_queue.put(bmsz_cookie)  # 成功时放回cookie
+                return response  # 返回最终响应
+
+        raise Exception(f" ({max_redirects})")
+
+    def get_data(self):
+        while True:
+            city_code, datetime_str = self.task_queue.get()
+            origin1, destination1 = city_code.split('\t')
+            bmsz_cookie = self.cookies_queue.get()
+
+            params = {
+                "s": "true",
+                "adults": "1",
+                "children": "0",
+                "infants": "0",
+                "selectedclass1": "economy",
+                # "currency": "CNY",
+                "mon": "true",
+                "channel": "DESKTOP",
+                "origin1": origin1,
+                "destination1": destination1,
+                "departuredate1": datetime_str
+            }
+            # # print(params1)
+            # params = {
+            #     "s": "true",
+            #     "adults": "1",
+            #     "children": "0",
+            #     "infants": "0",
+            #     "selectedclass1": "economy",
+            #     "currency": "CNY",
+            #     "mon": "true",
+            #     "channel": "DESKTOP",
+            #     "origin1": "CTS",
+            #     "destination1": "KOJ",
+            #     "departuredate1": "2025-05-30"  # !!!
+            # }
+            # print(params)
+            logger.info(f'正在采集{city_code} {datetime_str} 航班数据...')
+
+            try:
+                response = self.request_with_redirect(self.search_flights_api, params, bmsz_cookie)
+                self.resp_data_queue.put((city_code, datetime_str, response))
+
+            except Exception as e:
+                logger.error(e)
+                # 失败时重新上传任务
+                # self.task_queue.put(datetime_str)
+
+            finally:
+                self.task_queue.task_done()
+
+    def parse_data(self):
+        while True:
+            city_code, datetime_str, response = self.resp_data_queue.get()
+
+            html = etree.HTML(response.text)
+            data = html.xpath("//script[@id='bundle-data-v2']/text()")
+            if data:
+                json_data = json.loads(data[0])
+                print('获取数据成功', city_code, datetime_str, ' => ', json_data)
+                # print(response.text)
+            else:
+                logger.warning(f'{datetime_str} 触发验证码或拒绝访问错误, => {response.text}')
+
+            self.resp_data_queue.task_done()
+
+    @staticmethod
+    def gen_datetime(start_date, end_date):
+        current_date = datetime.strptime(start_date, '%Y-%m-%d')
+        end_date = datetime.strptime(end_date, '%Y-%m-%d')
+        date_list = []
+        while current_date <= end_date:
+            date_list.append(current_date.strftime('%Y-%m-%d'))  # 转换为字符串格式存储
+            current_date += timedelta(days=1)
+        return date_list
+
+    def gen_city(self):
+        routes = """
+          
+          
+           CTS	KOJ
+           """
+
+        temp_list = [i.strip() for i in routes.split("\n") if i.strip()]
+        routes = list(set(temp_list))  # 去重
+        print(routes)
+
+        return routes
+
+    @staticmethod
+    def gen_date_format(date_str):
+        """20250531 => 2025-05-31 """
+        original_date = datetime.strptime(date_str, "%Y%m%d")
+        return original_date.strftime("%Y-%m-%d")
+
+    def gen_task(self, start_date, end_date):
+        """将每个城市对与日期组合生成独立任务, 上传到任务队列"""
+        # 获取采集城市对
+        for city_code in self.gen_city():
+
+            # 获取采集时间
+            flight_date_list = self.search_flight_date(city_code, start_date, end_date)
+            if not flight_date_list:
+                print(city_code, start_date, end_date, '无航班')
+                continue
+            for datetime_str in flight_date_list:
+                # 日期格式转为 20250531 => 2025-05-31
+                self.task_queue.put((city_code, self.gen_date_format(datetime_str)))
+            # self.task_queue.put((datetime_str))
+
+    def search_flight_date(self, city_pair, start_date, end_date):
+        """查询航班日期, 即那天有航班"""
+        departures, arrivals = city_pair.split('\t')
+        url = "https://digitalapi.jetstar.com/v1/farecache/flights/batch/availability-with-fareclasses"
+        params = {
+            "flightCount": "1",
+            "includeSoldOut": "true",
+            "requestType": "StarterOnly",
+            "from": start_date,  # 采集开始时间
+            "end": end_date,  # 采集结束时间,可随意写  后面写完实例属性
+            "departures": departures,
+            "arrivals": arrivals,
+            "direction": "outbound",
+            "paxCount": "1",
+            "includeFees": "false"
+        }
+        headers = {
+            "accept": "application/json, text/plain, */*",
+            "accept-language": "zh-CN,zh;q=0.9",
+            "cache-control": "no-cache",
+            "culture": "zh-HK",
+            "origin": "https://www.jetstar.com",
+            "pragma": "no-cache",
+            "priority": "u=1, i",
+            "referer": "https://www.jetstar.com/",
+            "sec-ch-ua": "\"Google Chrome\";v=\"135\", \"Not-A.Brand\";v=\"8\", \"Chromium\";v=\"135\"",
+            "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/135.0.0.0 Safari/537.36"
+        }
+        response = requests.get(url, headers=headers, params=params, verify=False)
+        response.raise_for_status()
+        # for i in response.json():
+        #     print(i)
+        json_data = response.json()[0]['routes']
+
+        # 只有一个键值对
+        for key, val in json_data.items():
+            flight_dates = list(val.get('flights', {}).keys())
+            print(f'航段: {key} 对应有航班的日期为: {flight_dates}')
+            return flight_dates
+
+    def main(self, start_date, end_date):
+        thread_list = list()
+
+        self.gen_task(start_date, end_date)
+
+        for _ in range(1):
+            t_get_cookie = threading.Thread(target=self._refresh_cookie)
+            thread_list.append(t_get_cookie)
+
+        t_get_ja3 = threading.Thread(target=self.get_ja3_str)
+        thread_list.append(t_get_ja3)
+
+        for _ in range(1):
+            t_get_data = threading.Thread(target=self.get_data)
+            thread_list.append(t_get_data)
+
+        t_parse_data = threading.Thread(target=self.parse_data)
+        thread_list.append(t_parse_data)
+
+        for t_obj in thread_list:
+            t_obj.setDaemon(True)
+            t_obj.start()
+
+        for q in [self.task_queue, self.resp_data_queue]:
+            q.join()
+
+
+if __name__ == '__main__':
+    gk = GK()
+    gk.main(start_date='2025-05-30', end_date='2025-06-05')
+    # gk.gen_city()
+
+# http://B_3351_AU___5_ss-XXXXXXXXXXXX:ev2pjj@proxy.renlaer.com:7778
+# curl -x http://B_3351_SG___5_ss-XXXXXXXXXXXX:ev2pjj@proxy.renlaer.com:7778 cip.cc
+# curl -x http://B_3351_TW___5_ss-XXXXXXXXXXXX:ev2pjj@proxy.renlaer.com:7778 cip.cc
+# curl -x http://B_3351_HK___5_ss-115511111111:ev2pjj@proxy.renlaer.com:7778 cip.cc

+ 255 - 0
3.31GK/request_test.py

@@ -0,0 +1,255 @@
+from urllib.parse import urljoin
+
+import requests
+import json
+
+import execjs
+# from curl_cffi import requests
+import retrying
+# import pyhttpx
+#
+# ja3 = "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-45-43-5-23-35-13-65281-16-65037-18-51-10-11-17513-27,29-23-24,0"  # 自定义指纹字符串
+# sess = pyhttpx.HttpSession(
+#     # ja3=ja3,
+#     http2=True
+# )
+import tls_client
+
+headers = {
+    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
+    "accept-language": "zh-CN,zh;q=0.9",
+    "cache-control": "no-cache",
+    "pragma": "no-cache",
+    "priority": "u=0, i",
+    "referer": "https://booking.jetstar.com/",
+    "sec-ch-ua": "\"Google Chrome\";v=\"135\", \"Not-A.Brand\";v=\"8\", \"Chromium\";v=\"135\"",
+    "sec-ch-ua-mobile": "?0",
+    "sec-ch-ua-platform": "\"Windows\"",
+    "sec-fetch-dest": "document",
+    "sec-fetch-mode": "navigate",
+    "sec-fetch-site": "same-origin",
+    "sec-fetch-user": "?1",
+    "upgrade-insecure-requests": "1",
+    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"
+}
+
+
+def get_cookie():
+    with open('akm/逆向.js', encoding='utf-8') as f:
+        js = f.read()
+    ctx = execjs.compile(js)
+    session = requests.Session()
+
+    # akm js file url
+    akm_url = "https://booking.jetstar.com/Yxz-/5uZW/r/LS/v0HpqZQ/cY1w2bLGSLDp/UEtAAzo/SgIr/ED9jfEw"
+
+    data = {
+        'sensor_data': ctx.call('encrypt1')
+    }
+    response = session.post(akm_url, headers=headers, verify=False, data=data,
+                            # proxies=self.proxies
+                            )
+
+    # print(response.text)
+    bmsz = response.cookies.get_dict()['bm_sz']
+
+    data2 = {
+        "sensor_data": ctx.call('encrypt2', bmsz)
+    }
+
+    data2 = json.dumps(data2)
+    response2 = session.post(akm_url, headers=headers, data=data2, verify=False,
+                             # proxies=self.proxies
+                             )
+    print('bmsz => ', bmsz)
+    print(response2.text)
+    print(response2.status_code)
+
+
+@retrying.retry(stop_max_attempt_number=2)
+def req(bmsz_cookie):
+    params = {
+        "s": "true",
+        "adults": "1",
+        "children": "0",
+        "infants": "0",
+        "selectedclass1": "economy",
+        "currency": "CNY",
+        "mon": "true",
+        "channel": "DESKTOP",
+        "origin1": "CTS",
+        "destination1": "KOJ",
+        "departuredate1": f"2025-05-27"
+    }
+    cookie = {
+        'bm_sz': bmsz_cookie
+    }
+    response = requests.get("https://booking.jetstar.com/hk/zh/booking/search-flights", headers=headers, cookies=bmsz_cookie, params=params,
+                        timeout=15,
+                        verify=False,
+                        # impersonate='chrome99',
+                        # http_version=2
+
+                        proxies=proxies
+                        # allow_redirects=False
+
+                        )
+
+    print(response.text)
+    print(response)
+
+    from lxml import etree
+    import json
+
+    html = etree.HTML(response.text)
+    data = html.xpath("//script[@id='bundle-data-v2']/text()")[0] if html.xpath(
+        "//script[@id='bundle-data-v2']/text()") else '{}'
+    json_data = json.loads(data)
+    print(json_data)
+
+
+@retrying.retry(stop_max_attempt_number=3, wait_fixed=4000)
+def get_ja3_str( ):
+    url = "http://8.218.51.130:9003/api/v1/ja3"
+    payload = {}
+    headers = {
+        'cid': '750B5141EDBF7FA6F73A99C768130099'
+    }
+    response = requests.get(url, headers=headers, data=payload)
+    if response.status_code == 200:
+        res_json = response.json()
+        if res_json.get("code") == 0:
+            ja3 = res_json.get("data").get("ja3_str")
+            ua = res_json.get("data").get("ua")
+            if "--" not in ja3 and ",," not in ja3:
+                end_data = (
+                    ua,
+                    ja3
+                )
+                return end_data
+
+def tls_req(bmsz_cookie):
+    ua, ja3_string = get_ja3_str()
+
+    # current_cookie = cookies
+    # browser = random.choice(self.BROWSER)
+    req_session = tls_client.Session(
+        ja3_string=ja3_string,  # 直接注入自定义指纹
+    )
+    headers = {
+        'user-agent': ua,
+        'Accept-Encoding': 'gzip, deflate, br',
+        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
+        'Connection': 'keep-alive',
+        'Content-Type': 'application/x-www-form-urlencoded',
+        'accept-language': 'zh-CN,zh;q=0.9',
+        'cache-control': 'no-cache',
+        'pragma': 'no-cache',
+        'priority': 'u=0, i',
+        'referer': 'https://booking.jetstar.com/',
+        'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
+        'sec-ch-ua-mobile': '?0',
+        'sec-ch-ua-platform': '"Windows"',
+        'sec-fetch-dest': 'document',
+        'sec-fetch-mode': 'navigate',
+        'sec-fetch-site': 'same-origin',
+        'sec-fetch-user': '?1',
+        'upgrade-insecure-requests': '1'
+    }
+    params = {
+        "s": "true",
+        "adults": "1",
+        "children": "0",
+        "infants": "0",
+        "selectedclass1": "economy",
+        "currency": "CNY",
+        "mon": "true",
+        "channel": "DESKTOP",
+        "origin1": "PVG",
+        "destination1": "SYD",
+        "departuredate1": f"2025-05-31"
+    }
+    redirect_count = 0
+    max_redirects = 2
+    cookie = {
+        'bm_sz': bmsz_cookie
+    }
+    proxies_url = 'http://B_3351_HK___5_ss-{}:ev2pjj@proxy.renlaer.com:7778'
+    ip = 100000000000
+    proxies = {
+        'http': proxies_url.format(ip),
+        'https': proxies_url.format(ip)
+    }
+
+    current_url = "https://booking.jetstar.com/hk/zh/booking/search-flights"
+    while redirect_count < max_redirects:
+        response = req_session.get(current_url, headers=headers, cookies=cookie, params=params,
+                                   proxy=proxies
+                                   )
+
+        print(response.status_code)
+        # print(response.text)
+
+        # 检查是否为重定向状态码
+        if response.status_code in (301, 302, 303, 307, 308):
+            # 获取 Location 头(需处理相对路径)
+            location = response.headers.get("Location")
+            # if not location:
+            #     break
+            current_url = urljoin(current_url, location)
+            redirect_count += 1
+            # print(f"Redirecting to: {current_url}")
+
+            # 可选:继承原始请求的特定 Headers(如 Referer)
+            # headers["Referer"] = response.url
+        else:
+            from lxml import etree
+            import json
+
+            html = etree.HTML(response.text)
+            data = html.xpath("//script[@id='bundle-data-v2']/text()")[0] if html.xpath(
+                "//script[@id='bundle-data-v2']/text()") else '{}'
+            json_data = json.loads(data)
+            print(json_data)
+            return
+
+    raise Exception(f" ({max_redirects})")
+
+# cookies = {
+#     # "bm_sz": "C0B44D1663A1D1DF531263C2737158CA~YAAQuqzbF+g+wsyWAQAAXYayzRvvCtO5B+WPIETQGca8PO//hOzF1VgQ8UWaX5jQZqjBtJddRoQiBEhF8Kt/yAAy1PYYdaau8jE40Cfj3UxUpLerF6Bx7lMVhelxsPpebDhexd9epZ869ZHXU7vr1aD5waP/ryM62ifQhwkZhoZYCUTM+l4o3i6heEfjohv20aoENno39gXuJ62b7Pw/fWIV1iZsg9ZXz6cytoOozhB86c7SYg8S4F2uHmdRJCQwAle44prjdlu+Dr4InbJIQNhYP+vlzTTuJjMBQWidZncw+5SeoYGHGVhzONc4K8ojnfu1RdhhFfv1vWbT6jLa7pKh3sxzSOHYh7c3zXJsEp7bKFRcqWNO0dqt5NvlLXmOgdiQuOk=~4604742~4342593",
+#     "bm_sz": "D0FDE91D248039D3BCB85401C9E89EBC~YAAQEmrRF7aHJueWAQAA7oY75xu9AR2ykLW/ST7t+Z/9dlMdB5y12d+59GyysxUFJhQNz3GORFkJm0LXmIRyzA3UQ1toCGCp7oib9mXRbovqxMUbdHe3FzPkg6P+Qkz523VsaKzS40mf4sPhh33AU7BTBLYYoTeOii1NKDjkX7xXK0UQQTmi3DLjkLHTXNYuvzNpRZLjMXsMqDOp0e7mm8altPSk8GMJPnA0mMcokJ348UHk9vL92QLq9FmvD0Oi6PQwgPlec/qRjN2rQBH/hYe0KETY6RwKtaVbti5MVbR84d2VWVkKZyQwmmcibWMSrwdxp+oZjCJ3kguEctLgrQlOUfFiQwXprYugwZM=~3159352~4407875",
+# }
+# url = "https://booking.jetstar.com/hk/zh/booking/search-flights"
+#
+# # get_cookie()
+# req(30)
+
+bmsz = cookies = {
+    "bm_sz": "92BF676C3DD979E01C44FB2085A5EB17~YAAQHWrRFzRVgemWAQAAVomREBt8eEC//siHZ6ZbSARsn9I5LSlX4gu9JMhr+mKMUqle7mBkR+FaMJRD6bqONlFEMRiSPt47mEXkvqd2XdhB42MWCDbDyBL4Kq5AQAUstK/W5QCqigla+wVukC/J8BCF4uUXQeC8RLQFt7nELruQ95bcwOZ0dcK+DLBJqhl7tbFUBXwJzTg59ijCrpx/3KIPbsVb8fOnX5+3HE1bgrwurqAVOB7ZLwDy2rz0MR4TZegpmu1LroCHjdbOC97Sr8Bm0vwycXsd3P67jSVGKtsjMkBWFXPYAnnZEfVYFWkCvq33qY4VAMwP0+liJr7oV/OtUSxJNKOXMARY6g==~3683381~3421233",
+}
+try:
+    proxies = {
+        "http": "http://127.0.0.1:7897",
+        "https": "http://127.0.0.1:7897"
+    }
+    req(bmsz)
+    tls_req(bmsz_cookie=bmsz)
+
+except Exception as e:
+    #
+    print(e)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 0 - 85
3.31Gk航司/akm逆向/demo.py

@@ -1,85 +0,0 @@
-# from curl_cffi import requests
-#
-# import requests
-# import execjs
-# import json
-#
-# requests = requests.Session()
-#
-# with open('逆向.js', encoding='utf-8') as f:
-#     js = f.read()
-# ctx = execjs.compile(js)
-#
-#
-# headers = {
-#     "accept": "*/*",
-#     "accept-language": "zh-CN,zh;q=0.9",
-#     "cache-control": "no-cache",
-#     "content-type": "text/plain;charset=UTF-8",
-#     "origin": "https://booking.jetstar.com",
-#     "pragma": "no-cache",
-#     "priority": "u=1, i",
-#     "referer": "https://booking.jetstar.com/",
-#     "sec-ch-ua": "\"Google Chrome\";v=\"135\", \"Not-A.Brand\";v=\"8\", \"Chromium\";v=\"135\"",
-#     "sec-ch-ua-mobile": "?0",
-#     "sec-ch-ua-platform": "\"Windows\"",
-#     "sec-fetch-dest": "empty",
-#     "sec-fetch-mode": "cors",
-#     "sec-fetch-site": "same-origin",
-#     "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"
-# }
-#
-#
-# # akm js file url
-# # url = "https://www.jetstar.com/RGa75acATohb/xCwZta/rbnL7W/9J7Vz2pzzSVwGEXE/YxU3A31SAw/chwnU/DkTD0s"
-# url = "https://booking.jetstar.com/MkuYlo/pcp/LD0/PPluEQ/1ik7QcJffXbmL53i/QTcvXmg7/KS5kC3N/VRQcB"
-#
-# data = {
-#     'sensor_data': ctx.call('encrypt1')
-# }
-# data = json.dumps(data, ensure_ascii=False)
-# response = requests.post(url, headers=headers,
-#                          verify=False,
-#                          data=data,
-#                          impersonate='chrome110'  # 不指定 impersonate 时,TLS 指纹是 curl 原生的,而非浏览器指纹(依旧过不了检测)。需显式设置该参数以绕过 TLS 指纹检测
-#                          )
-#
-# print(response.text)
-#
-# bmsz = response.cookies.get_dict()['bm_sz']
-# print('bmsz =>', bmsz)
-#
-#
-# data2 = {
-#     "sensor_data": ctx.call('encrypt2', bmsz)
-# }
-#
-# data2 = json.dumps(data2)
-# # print(data2)
-# response2 = requests.post(url, headers=headers, data=data2, verify=False,
-#                           impersonate='chrome110'
-#                           )
-# print(response2.text)
-# print(response2.status_code)
-# print(response2.cookies.get_dict())
-#
-#
-# import requests
-# # 隧道域名:端口号
-# # tunnel = "l716.kdltps.com:15818"
-# tunnel = "l716.kdltps.com:15818"
-#
-# # 用户名密码方式
-# username = "t14669095435186"
-# password = "cle082qz"
-# proxies = {
-#     "http": "http://%(user)s:%(pwd)s@%(proxy)s/" % {"user": username, "pwd": password, "proxy": tunnel},
-#     "https": "http://%(user)s:%(pwd)s@%(proxy)s/" % {"user": username, "pwd": password, "proxy": tunnel}
-# }
-# print(requests.get('https://myip.ipip.net/', proxies=proxies).text)
-# print(requests.get('https://tls.peet.ws/api/all', proxies=proxies).text)
-
-# 113.14.208.206
-# 0149f47eabf9a20d0893e2a44e5a6323
-# 0149f47eabf9a20d0893e2a44e5a6323
-# 0149f47eabf9a20d0893e2a44e5a6323

+ 0 - 40
3.31Gk航司/tls - ja3 指纹.py

@@ -1,40 +0,0 @@
-from tls_client import Session
-
-# 自定义 JA3 字符串
-ja3 = "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513,29-23-24,0"
-
-session = Session(
-    client_identifier="Chrome_120",
-    random_tls_extension_order=True,
-
-)
-headers = {
-    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
-    "accept-language": "zh-CN,zh;q=0.9",
-    "cache-control": "no-cache",
-    "pragma": "no-cache",
-    "priority": "u=0, i",
-    "referer": "https://booking.jetstar.com/",
-    "sec-ch-ua": "\"Google Chrome\";v=\"135\", \"Not-A.Brand\";v=\"8\", \"Chromium\";v=\"135\"",
-    "sec-ch-ua-mobile": "?0",
-    "sec-ch-ua-platform": "\"Windows\"",
-    "sec-fetch-dest": "document",
-    "sec-fetch-mode": "navigate",
-    "sec-fetch-site": "same-origin",
-    "sec-fetch-user": "?1",
-    "upgrade-insecure-requests": "1",
-    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"
-}
-
-session.headers.update(headers)
-
-response = session.get("https://tls.peet.ws/api/all", headers=headers)
-print(response.text)
-
-
-"""
-2eb0a61fa86253c470b1d53224c0f7ad
-74c901ecc2a908b2f4b458d0fcbbbcd9
-b6d8149144237b3e6a1cf629b4a0abfa
-
-"""

+ 0 - 8
3.31Gk航司/其他/.idea/.gitignore

@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
-# Editor-based HTTP Client requests
-/httpRequests/

+ 0 - 8
3.31Gk航司/其他/.idea/3.31Gk航司.iml

@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="PYTHON_MODULE" version="4">
-  <component name="NewModuleRootManager">
-    <content url="file://$MODULE_DIR$" />
-    <orderEntry type="jdk" jdkName="Python 3.9 (py3.9) (3)" jdkType="Python SDK" />
-    <orderEntry type="sourceFolder" forTests="false" />
-  </component>
-</module>

+ 0 - 38
3.31Gk航司/其他/.idea/inspectionProfiles/Project_Default.xml

@@ -1,38 +0,0 @@
-<component name="InspectionProjectProfileManager">
-  <profile version="1.0">
-    <option name="myName" value="Project Default" />
-    <inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
-      <Languages>
-        <language minSize="125" name="JavaScript" />
-        <language minSize="68" name="Python" />
-      </Languages>
-    </inspection_tool>
-    <inspection_tool class="PyInterpreterInspection" enabled="false" level="WARNING" enabled_by_default="false" />
-    <inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
-      <option name="ignoredPackages">
-        <value>
-          <list size="11">
-            <item index="0" class="java.lang.String" itemvalue="selenium-wire" />
-            <item index="1" class="java.lang.String" itemvalue="pymongo" />
-            <item index="2" class="java.lang.String" itemvalue="pyhttpx" />
-            <item index="3" class="java.lang.String" itemvalue="selenium" />
-            <item index="4" class="java.lang.String" itemvalue="undetected-chromedriver" />
-            <item index="5" class="java.lang.String" itemvalue="seleniumbase" />
-            <item index="6" class="java.lang.String" itemvalue="pyexecjs" />
-            <item index="7" class="java.lang.String" itemvalue="requests" />
-            <item index="8" class="java.lang.String" itemvalue="loguru" />
-            <item index="9" class="java.lang.String" itemvalue="xdeek-logger" />
-            <item index="10" class="java.lang.String" itemvalue="redis" />
-          </list>
-        </value>
-      </option>
-    </inspection_tool>
-    <inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
-      <option name="ignoredErrors">
-        <list>
-          <option value="N806" />
-        </list>
-      </option>
-    </inspection_tool>
-  </profile>
-</component>

+ 0 - 6
3.31Gk航司/其他/.idea/inspectionProfiles/profiles_settings.xml

@@ -1,6 +0,0 @@
-<component name="InspectionProjectProfileManager">
-  <settings>
-    <option name="USE_PROJECT_PROFILE" value="false" />
-    <version value="1.0" />
-  </settings>
-</component>

+ 0 - 7
3.31Gk航司/其他/.idea/misc.xml

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="JavaScriptSettings">
-    <option name="languageLevel" value="ES6" />
-  </component>
-  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (py3.9) (3)" project-jdk-type="Python SDK" />
-</project>

+ 0 - 8
3.31Gk航司/其他/.idea/modules.xml

@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ProjectModuleManager">
-    <modules>
-      <module fileurl="file://$PROJECT_DIR$/.idea/3.31Gk航司.iml" filepath="$PROJECT_DIR$/.idea/3.31Gk航司.iml" />
-    </modules>
-  </component>
-</project>

+ 0 - 6
3.31Gk航司/其他/1.html

@@ -1,6 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
-<HTML><HEAD><TITLE>Bad Request</TITLE>
-<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
-<BODY><h2>Bad Request - Invalid Header</h2>
-<hr><p>HTTP Error 400. The request has an invalid header name.</p>
-<script type="text/javascript"  src="/MkuYlo/pcp/LD0/PPluEQ/1ik7QcJffXbmL53i/QTcvXmg7/KS5kC3N/VRQcB"></script></BODY></HTML>

+ 0 - 197
3.31Gk航司/其他/ast/ast.js

@@ -1,197 +0,0 @@
-const fs = require('fs')
-const parser = require('@babel/parser') // 解析 JavaScript 代码
-const traverse = require('@babel/traverse').default // 遍历 AST
-const generator = require('@babel/generator').default // 生成代码
-const t = require('@babel/types')
-
-
-// 定义文件路径
-const input_js = './encode.js'
-const output_js = './decode.js'
-
-// 读取文件内容并解析成 AST
-const js_code = fs.readFileSync(input_js, {encoding: 'utf-8'})
-
-
-const ast = parser.parse(js_code)  // 解析代码为 AST
-
-// 字面量访问器 -------------------------------
-const varPool = new Map(); // 存储(第一个函数)计算出的变量值
-const varPool2 = new Map(); // 存储(第二个函数)计算出的变量值
-
-const visitor_literal = {
-    // 第一阶段:处理 QxN 函数
-    FunctionDeclaration(path) {
-        let {id} = path.node
-        let bodyPath = path.get('body')
-        if (!t.isIdentifier(id, {name: 'QxN'})) return;
-
-        bodyPath.traverse({
-            AssignmentExpression(path) {
-                const rightPath = path.get('right'); // 获取右侧表达式的路径(左边是变量名)
-                const var_name = path.node.left.name  // 获取左侧的变量名
-                // evaluate() 方法是路径对象(Path)提供的方法,而非节点(Node)本身的方法。你需要通过路径来调用该方法
-                const evaluated = rightPath.evaluate(); // 调用evaluate()
-
-                if (evaluated.confident) {
-                    let value = evaluated.value
-                    varPool.set(var_name, value); // 存储变量值
-                    console.log(rightPath.toString(), '=>', value); // 输出确定的值
-                    rightPath.replaceWith(t.valueToNode(value))  // 替换为字面量
-                } else {
-                    console.log('无法静态求值');
-                }
-
-            }
-        })
-
-    },
-    Program: {
-        exit(path) {
-            // 第二阶段:在所有节点处理完成后处理 ShN 函数
-            path.traverse({
-                FunctionDeclaration(path) {
-                    let {id} = path.node
-                    let bodyPath = path.get('body')
-                    if (!t.isIdentifier(id, {name: 'ShN'})) return;
-
-                    bodyPath.traverse({
-                        AssignmentExpression(path) {
-                            const rightPath = path.get('right');
-                            const var_name = path.node.left.name  // 获取左侧的变量名
-                            // evaluate() 方法是路径对象(Path)提供的方法,而非节点(Node)本身的方法。你需要通过路径来调用该方法
-                            // 继续遍历rightPath下的节点,替换已知变量引用为字面量
-                            rightPath.traverse({
-                                // subPath表示子路径,定位子路径下的标识符
-                                Identifier(subPath) {
-                                    if (varPool.has(subPath.node.name)) {
-                                        subPath.replaceWith(
-                                            t.valueToNode(varPool.get(subPath.node.name))
-                                        )
-                                    }
-                                }
-                            });
-
-                            // 再次尝试计算表达式
-                            const evaluated = rightPath.evaluate();
-                            if (evaluated.confident) {
-                                let value = evaluated.value
-                                varPool2.set(var_name, value)
-                                console.log(rightPath.toString(), '=>', evaluated.value); // 输出确定的值
-
-                                rightPath.replaceWith(t.valueToNode(evaluated.value));
-                            }
-                        }
-
-                    })
-
-                }
-
-            });
-        }
-    }
-};
-
-
-// 定位 return j2.call(this, xL);
-const visitor_ = {
-
-    CallExpression(path) {
-        let {callee} = path.node
-
-        if (!t.isFunctionExpression(callee)) return;
-
-        path.traverse({
-            ReturnStatement(path) {
-                let {argument} = path.node
-                if (!t.isCallExpression(argument)) return;
-
-                let {callee: {property,}, arguments: args} = argument
-
-                if (args.length !== 2 || !t.isIdentifier(property, {name: 'call'})) return;
-                console.log(path.toString())
-
-
-            }
-        })
-
-    },
-
-}
-
-
-// 控制流平坦化访问器 -------------------------------
-function return_num(varStr) {
-    // 根据变量字符串,返回对应变量值
-    if (varPool.has(varStr) || varPool2.has(varStr)) {
-        return varPool[varStr] || varPool2[varStr]
-    }
-    console.warn(`${varStr}未找到`)
-
-}
-
-const visitor_for = {
-    ForStatement(path) {
-        const {test, body} = path.node;     // 解构循环条件和循环体
-
-        // let {} = test                       // 从循环条件取出具体值,在变量值map中查找,方便下面循环处理
-
-        // 初始状态变量值
-        let init_name = 'HO';               // 状态变量名
-        let init_value = 3;                 // 初始状态值
-
-        const switch_body = body.body[0];   // 提取循环体内的switch语句
-
-        // 验证是否为 Switch 语句,否则终止处理
-        if (!t.isSwitchStatement(switch_body)) return;
-
-        const {discriminant, cases} = switch_body;  // 解构 Switch 的条件和分支列表
-
-        // 验证 Switch 条件是否为指定状态变量
-        if (!t.isIdentifier(discriminant, {name: init_name})) return;
-
-        const ret_body = [];               // 存储最终生成的代码块集合
-        let end_flag = false;              // 终止循环处理标志
-
-        while (init_value !== 662) {       // 循环处理所有状态分支
-            if (end_flag) break;           // 检测终止条件
-
-            for (const each_case of cases) {              // 遍历 Switch 的所有 case 分支
-                const {test, consequent} = each_case;     // 从case分支中取出条件和对应代码块
-
-
-                if (init_value !== test.name) continue;  // 跳过非当前状态的 case 分支
-
-
-            }
-
-
-        }
-    }
-}
-
-const visitor_while = {
-    VariableDeclarator(path) {
-        let {id, init} = path.node
-
-        if (!t.isIdentifier(id, {name: 'j2'})) return
-
-        path.traverse(visitor_for)
-        // console.log(id.name)
-    }
-}
-
-
-traverse(ast, visitor_literal); // 还原初始化2个变量赋值函数
-// traverse(ast, visitor_);
-// traverse(ast, visitor_while);
-
-console.log(varPool2)
-
-// 使用 Babel 生成新的代码
-let {code} = generator(ast)
-
-
-// 将生成的代码写入指定的文件
-// fs.writeFile(output_js, code, (err) => {
-// })

File diff suppressed because it is too large
+ 0 - 264
3.31Gk航司/其他/ast/decode.js


File diff suppressed because it is too large
+ 0 - 59
3.31Gk航司/其他/ast/encode.js


File diff suppressed because it is too large
+ 0 - 3191
3.31Gk航司/其他/ast/收集函数加密/ast.js


File diff suppressed because it is too large
+ 0 - 59
3.31Gk航司/其他/ast/收集函数加密/decode.js


File diff suppressed because it is too large
+ 0 - 59
3.31Gk航司/其他/ast/收集函数加密/encode.js


File diff suppressed because it is too large
+ 0 - 3
3.31Gk航司/其他/bm_sz 生成/分析


File diff suppressed because it is too large
+ 0 - 30
3.31Gk航司/其他/bm_sz 生成/第一次请求akm.py


+ 0 - 64
3.31Gk航司/其他/cookie参数测试.py

@@ -1,64 +0,0 @@
-
-
-# 只带 SEFD 和 ASP.NET_SessionId 会报错
-cookies = {
-    # "$date_selected": "0",
-    # "optimizelyEndUserId": "oeu1744595167365r0.8968549342456524",
-    # "bid_JSaU2TcvPguuhpZfmwr34R7R8Wo7moKH": "fbcdc2e7-4124-47b7-bd23-b63061f4e537",
-    # "AMCVS_8D0D1C8B532B54B40A490D4D%40AdobeOrg": "1",
-    # "bx_bucket_number": "42",
-    # "bx_guest_ref": "587456a6-5f66-49a4-80cf-d730c5c1a2ba",
-    # "s_cc": "true",
-    # "htjs_anonymous_id": "18b92168-bd03-4295-9296-1cf56b28cab6",
-    # "_gcl_au": "1.1.259153084.1744595174",
-    # "optimizelySession": "0",
-    # "_fbp": "fb.1.1744613560083.2120932399812202",
-    # "PlatformChannel": "REVTS1RPUA==",
-    # "PlatformAppVersion": "",
-    # "WorkFlow": "MA==",
-    # "s_sq": "%5B%5BB%5D%5D",
-    # "user-location": "country_code=AU,region_code=NSW,city=SYDNEY,lat=-33.88,long=151.22",
-    # "AKA_A2": "A",
-    # "bm_ss": "ab8e18ef4e",
-    # "ab.storage.deviceId.8eb26f80-6f07-43d3-be0e-778c98485224": "g%3Aee8e7ee6-34ae-480d-2a66-99bd0dad803b%7Ce%3Aundefined%7Cc%3A1743408255712%7Cl%3A1744684408023",
-    # "bxIDT": "",
-    # "gpv_mpl": "1",
-
-    # "mcp-pre-selected-currency": "null",
-    # "gpv_pn": "%2Fbooking%2Fselect-flights",
-    # "gpv_v1": "%2Fbooking-flow-ngbe",
-    # "__RequestVerificationToken": "_GsgZMqY1rXYqfQ96sUCXLjYpoBXK7mB8uLeplvbOZo15DEFJ5hzMFsUyH94rigM_AQr6-lDYwzzR7DVDXr6kYVmgOiZV8kq8puFpk18bg1IWGFwKW4tYCeyN6FUbXQtil0RSA2",
-    # "X-Session-Id": "24vpdrcoqoppqnveymu3eltv",
-    # "X-Session-Sig": "c0a2c5116a8bb863133cd0e3eeb8fb7e6a8cbf576210eace5f0fcd27d717d88a",
-
-    # 不带 SEFD 会触发验证码 (每次请求都会变化,请求成功后,响应cookie会返回这个值; 同一个代码中 SEFD只能请求4次 第5次时,就会触发验证码, 更换它就没事了)
-    "SEFD": "eyJPcmlnaW4iOiJQVkciLCJEZXN0aW5hdGlvbiI6IktNSSIsIlJvdW5kVHJpcCI6ZmFsc2UsIkRlcGFydHVyZURhdGUiOiIyMDI1LTA1LTMxVDAwOjAwOjAwIiwiUmV0dXJuRGF0ZSI6IjAwMDEtMDEtMDFUMDA6MDA6MDAiLCJBZHVsdHMiOjEsIkNoaWxkcmVuIjowLCJJbmZhbnRzIjowfQ==",
-
-    # "bm_so": "7698670B499A260BE6A3F4AC213FB146A9A75B95EF674ED595B97F45A8CBB95A~YAAQAgUgF4+8zjKWAQAA4sBoNwPzlPg/g8PzigNKJ31ExpnJxMfQtD1Su5bRRWHD6koSoi9qOmYlXz74OC8wEcVuACq5tGPivwiQ60Sko+bH1LJfFZdmzSaI1iv03FzSYhrq/g3KLR217Bz+iAgEwNiwoHLR1uN0AsOiNOCTPsHEwETT3Y5f1EhJdBtzKllcjNRJAub5W0A+tzCc4Q+ALECFacB3WGsBiZqbVlebdQ1p9XM+egTC0DHDkY9DfIzCMBggR9kmz7hwjLORla8U5wkRFH5l46XpDu84D07fb8G7Qpfds9WrFg0Zv/JgRoCw2ciASKOkVJ0FdWe+YW2nJyVNHVR2MQZ9PA5o0AEgWCABDGGgiWxcqApsCdRcMQrja7+vZHJA+0oDm+CiYlVMl2IfCcMt958/54vutMalTjWdSrbyoSGez66K4AnU/n5wsPKs6lmp9kemr3yrxjarTQ==",
-    # "MT": "1744686338958",
-    # "ab.storage.sessionId.8eb26f80-6f07-43d3-be0e-778c98485224": "g%3Ae5689bcb-fc11-ff83-81a1-4f31bf107f85%7Ce%3A1744688139890%7Cc%3A1744684408021%7Cl%3A1744686339890",
-
-
-    # "s_nbs": "1744686342",
-    # "htjs_sesh": "{%22id%22:1744684429277%2C%22expiresAt%22:1744688144291%2C%22timeout%22:1800000%2C%22sessionStart%22:false%2C%22autoTrack%22:true}",
-    # "RT": "\"z=1&dm=jetstar.com&si=e684950f-3a6d-4647-9fe3-27df785970eb&ss=m9hw1mh9&sl=e&tt=7j7r&bcn=%2F%2F684d0d45.akstat.io%2F&obo=5&ld=15vtt\"",
-
-    # "flightIndex": "0",
-    # "bm_sv": "6A3EC4D0406D1A497A8C3FD65F715C94~YAAQJAUgF7fJ7h6WAQAAStFpNxtXE33mIKEHjS2pkJAKeXCnaFA9hsmQdlRonaOnxFRx5x4IkdB2YcIFgW0imoKXf9T0+0rYOa6i15SuC77zcuXcHN32TUA6Cy9LSM2eEC8UOkYVYBZGvAGxn35yoI6OI/eldQma6Uv8fHdCitt7l708KZi4/ox0yGA1A2ISo3YmveNg47x6pX/O4goi9u5+FaXsM/jMXDKGdFywWg/p513Is0eNv7OObAoC6UAH9Q==~1",
-
-    # 这个必须带,(同一个会话中 ASP.NET_SessionId 是不变的 待验证!!)
-    "ASP.NET_SessionId": "wf30ys1zm1y5zi3ius1vkbut",
-
-    # "dotrez": "\\u00219cFnD/LGKhSbWaTKjWHgUrSHoe1obMAGG8p4/HmpcTLZGKlG6ONGvIX5E/2f4TmQMoapbwu1IvZIdpI=",
-    # "_abck": "930E26A3CD6C8D10C55BDD4E4EE13B50~-1~YAAQHAUgF9H2BDWWAQAAxFhrNw0FT7RyViSSrpUtP3vZ0qAaoF037BWwFzO7OIoTvJtndrO304YZeE/dsGtt46swTSTlz8OhInpEstk1b4MZhMVUgArmxQSbUyumMBl9qXAjIsCe5goLmT8u5I1AndVLT7ESrGz1NACO8cBRkO4GESR6/ljHH/PZYXV5HjacZIy9oGlNWaXUXGRDqSesn5mylmB+xOkg5kiI302j4QKhTqOs1lr/lJibDerRpIxorsVlhRGJAyfbbzRQVlCQ3bDRgIXraQoJXvrKQOohBzvJ/I0aFZ3+Jp4iWKbhosOJydf80t4rDlxaoNEEYtk9NYOxc86iuPyVXWcBATloD6vPJTjWquFcpawn4I+DL/92se/bAKieFxciUm+kDgDIzIioDabit+UYU5nHe9KCHOUmetCKwel4OxoPcpBmdsCsNz/5f2krCjb16fxqxUDF0dZuXentP8Z5PSPB2bXAwxwMbB21/FhA8odoyWPvIbOIpTFAGEPvPP7MF4Ii8czDNQTMg0WG5BIq5oXWR3xGcDu1d2TgzaUzKuZ6YPFThItfAisNqqeJy6UmcC1Ia3NUjMlyeYF7TZYISLSGiQ6rYyfas3dKxTm+IsBm+0ol/M4lGpa+tjkIWO5FJVUn96xuRPdzy7QF7ZrxNAID8Cbpk+29fQIr9AYq0QZB3Mi9ByAbScGGcyhk09wpul+1ZJly~-1~-1~-1",
-    # "bm_s": "YAAQHAUgF9L2BDWWAQAAxFhrNwODr3pxx2fke2m/JKT6P2irIYpOHcTjOc4vL0Pt6uGWQt1lmMew5jdCwvRLrM5VAvNouDNBvtKOewwEZ8jmBDkT0VdZoXZprj6eEa6dS1lhlXC3kfaB7IFo/4qXsD735xtuKbUWNbaF34XcQPldBr+yJAQQbJdJaAOw9MYNG08HVPaGpacIW4EfcBHU6SMcugUHmyhepFoUQI7H4RDicVJmGheAKkG7D+aSxiOufTs5b9HhI8f0QU9czhZs1xFAs7T+AkIm1Nf35T3Ynr9vd0pq/JAm83/OP32qQjZwmE4L6oHMo6RnH+V/7pyK84EAq23sr19kd+8tonu+ii+dfJyNh0ULmJ8zI59lHbqPWoB+bhAaYLzeb4hVZMUwur6hvM1f8vVePAtUstr2SdxJoy7ASVqfJaCiGcixadLe0WzY64SUg/ZmT+xO",
-
-    # 只带 SEFD 和 ASP.NET_SessionId 会报错, 再带个 bm_sz 就可以
-    "bm_sz": "240D392558B96D94D296BEF81A894105~YAAQHAUgF9P2BDWWAQAAxFhrNxsOcABuBbRjbd+k1j02geHY6EEHSzBfigP7IJ7wKnbCuTcz+3pnnbljDPPVkkr/eenq4V0QfiTD5yBx81YoAGq47fmRw5QMThY3nkRz81gwwHgUPTlIWEE3qkiB6CtB/Ih/h+H9XKkPj79ynRIDSX8KVmEE8Uuv5QeaRNiaX0gdeqUHKionhtE02U9TdvOnGa6yh7gGBZyiME5N5eTHJziblAF4iY/IMU8Gw9aQYwF9S7lu5Ejm7LzjS8tpN0g64GiUEviC5f+To7aRTt7NTcHx4pgbOctg/nigwbgLSAxY2uOz0s1vVO3xr0GSLCq7nXliTfJ4KamL7yHfC/CqXROZy8dzFzqI4wOiM2BbfcLiHWhmhY9IGnBEOia3bvl7Vl1lxfRqpl92m+kWRmMpoyVNqWutvD8JlmF0bqLx6YusdVfsDYXhxuTASgUR3wDWZ4yBd8jsBG8dYvAwy2DmmIxOOqainI2xCO5PAzTnv3NiQojLNloYPzDzXMFo4g1cbwqv06OuP1IVAXx3PXiRC/VenlAw4D+LIORDXR7W~4601670~3617843",
-
-    # "_dd_s": "rum=2&id=c451fcb4-3547-4e95-937e-04435aae9853&created=1744684407029&expire=1744687421491",
-    # "s_getNewRepeat": "1744686521497-Repeat"
-    # "bm_lso":
-    # ak_bmsc
-    # AMCV_8D0D1C8B532B54B40A490D4D
-}

+ 0 - 71
3.31Gk航司/其他/demo2.py

@@ -1,71 +0,0 @@
-import requests
-
-
-headers = {
-    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
-    "accept-language": "zh-CN,zh;q=0.9",
-    "cache-control": "no-cache",
-    "pragma": "no-cache",
-    "priority": "u=0, i",
-    "referer": "https://booking.jetstar.com/",
-    "sec-ch-ua": "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"",
-    "sec-ch-ua-mobile": "?0",
-    "sec-ch-ua-platform": "\"Windows\"",
-    "sec-fetch-dest": "document",
-    "sec-fetch-mode": "navigate",
-    "sec-fetch-site": "same-origin",
-    "sec-fetch-user": "?1",
-    "upgrade-insecure-requests": "1",
-    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
-}
-
-url = "https://booking.jetstar.com/hk/zh/booking/search-flights"
-params = {
-    "s": "true",
-    "adults": "1",
-    "children": "0",
-    "infants": "0",
-    "selectedclass1": "economy",
-    "currency": "CNY",
-    "mon": "true",
-    "channel": "DESKTOP",
-    "origin1": "PVG",
-    "destination1": "KMJ",
-    "departuredate1": "2025-05-12"
-}
-
-ip = '000000000024'
-proxies = {
-    'http': f'http://B_3351_HK___5_ss-{ip}:ev2pjj@proxy.renlaer.com:7778',
-    'https': f'http://B_3351_HK___5_ss-{ip}:ev2pjj@proxy.renlaer.com:7778'
-}
-cookies = {
-    # "ASP.NET_SessionId": "fs0akgjdzhdbwjdlk1345egb",
-
-    # "SEFD": "eyJPcmlnaW4iOiJQVkciLCJEZXN0aW5hdGlvbiI6IlFTVSIsIlJvdW5kVHJpcCI6ZmFsc2UsIkRlcGFydHVyZURhdGUiOiIyMDI1LTA2LTEyVDAwOjAwOjAwIiwiUmV0dXJuRGF0ZSI6IjAwMDEtMDEtMDFUMDA6MDA6MDAiLCJBZHVsdHMiOjEsIkNoaWxkcmVuIjowLCJJbmZhbnRzIjowfQ==",
-
-    # "bm_sz": "1AF44A3B342C0D65F7FE487CEE4B582B~YAAQuqzbFxUlkUqWAQAA0aJOehsVzB0waQURNtQG+ozage9BslR5TVlORc0702ZswDMt5mhWFgT5YZcpMATNFJuEtK4l2IEjzc6A5qCfBaZHiYSbw/2wDEopU/xGH2mKKOyAArvP/Ui9bk4tpjBbOKE6KvMwzsmAs/0dO5Q40Py1YrDeJpFJlsQ+OTAEbdm1hl28uuzi118b02DSCtc9tG1pPFcs/x9BXVid1nILwcsg1XZf3s3basCdvkjUImUxxp71atqcVRr1Ho8s2NFzEFOj2hqhkNV4j4+Gumrgiyru7TQvn37BeRLqb3W8RIMhnQiC6FrUBlKLkdpdfVvBuhCTxX164Efg8PNLJudApfmrSW4t+3dZmng=~4277552~4277555",
-    "bm_sz": "1AF44A3B342C0D65F7FE487CEE4B582B~YAAQuqzbFxUlkUqWAQAA0aJOehsVzB0waQURNtQG+ozage9BslR5TVlORc0702ZswDMt5mhWFgT5YZcpMATNFJuEtK4l2IEjzc6A5qCfBaZHiYSbw/2wDEopU/xGH2mKKOyAArvP/Ui9bk4tpjBbOKE6KvMwzsmAs/0dO5Q40Py1YrDeJpFJlsQ+OTAEbdm1hl28uuzi118b02DSCtc9tG1pPFcs/x9BXVid1nILwcsg1XZf3s3basCdvkjUImUxxp71atqcVRr1Ho8s2NFzEFOj2hqhkNV4j4+Gumrgiyru7TQvn37BeRLqb3W8RIMhnQiC6FrUBlKLkdpdfVvBuhCTxX164Efg8PNLJudApfmrSW4t+3dZmng=~4277552~4277555",
-
-}
-response = requests.get(url, headers=headers, cookies=cookies, params=params,
-                        # proxies=proxies,
-                        timeout=15)
-
-
-print(response.text)
-print(response.cookies.get_dict().get('SEFD'))
-print(response)
-
-
-from lxml import etree
-import json
-
-html = etree.HTML(response.text)
-data = html.xpath("//script[@id='bundle-data-v2']/text()")[0]
-json_data = json.loads(data)
-print(json_data)
-
-
-
-# akm文件名称 2hOd3M

File diff suppressed because it is too large
+ 0 - 120
3.31Gk航司/其他/html解析.py


+ 0 - 3
3.31Gk航司/其他/test.js

@@ -1,3 +0,0 @@
-
-
-''['concat']('bJuuHvFXAI5wXS6lfXoa/bPz62/VEoOV5bodHyJ9lxU=' )

+ 0 - 71
3.31Gk航司/其他/verify.py

@@ -1,71 +0,0 @@
-import requests
-
-
-headers = {
-    "accept": "*/*",
-    "accept-language": "zh-CN,zh;q=0.9",
-    "cache-control": "no-cache",
-    "pragma": "no-cache",
-    "priority": "u=1, i",
-    "referer": "https://booking.jetstar.com/hk/zh/booking/select-flights",
-    "sec-ch-ua": "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"",
-    "sec-ch-ua-mobile": "?0",
-    "sec-ch-ua-platform": "\"Windows\"",
-    "sec-fetch-dest": "empty",
-    "sec-fetch-mode": "cors",
-    "sec-fetch-site": "same-origin",
-    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
-}
-cookies = {
-    "$optimizelyEndUserId": "oeu1744595167365r0.8968549342456524",
-    "bid_JSaU2TcvPguuhpZfmwr34R7R8Wo7moKH": "fbcdc2e7-4124-47b7-bd23-b63061f4e537",
-    "AMCVS_8D0D1C8B532B54B40A490D4D%40AdobeOrg": "1",
-    "bx_bucket_number": "42",
-    "bx_guest_ref": "587456a6-5f66-49a4-80cf-d730c5c1a2ba",
-    "s_cc": "true",
-    "htjs_anonymous_id": "18b92168-bd03-4295-9296-1cf56b28cab6",
-    "_gcl_au": "1.1.259153084.1744595174",
-    "optimizelySession": "0",
-    "user-location": "country_code=AU,region_code=NSW,city=SYDNEY,lat=-33.88,long=151.22",
-    "AKA_A2": "A",
-    "bm_ss": "ab8e18ef4e",
-    "ab.storage.deviceId.8eb26f80-6f07-43d3-be0e-778c98485224": "g%3Aee8e7ee6-34ae-480d-2a66-99bd0dad803b%7Ce%3Aundefined%7Cc%3A1743408255712%7Cl%3A1744613552266",
-    "ak_bmsc": "0C44E7FAA04DABAF0E911B33938AFB91~000000000000000000000000000000~YAAQPJw+F3CAmAWWAQAAGDISMxvLvAESCoKHTt1O08nNiA/HnQ4AFKBRQ7NfQ5z0Q3uffqgevW6oQtndWSYM0L/P1aqtHc9dSvi9LI43CMebVI4bcNsxJ9ZECzg3K0DUcR4qO/34pAG0eMoLGr03Eg6DPqefuSwlyevi8qKbX9txtairrYtNRZnd+CESJf3RCC/OAz+ltYzB9U9U9cQ0r/n1mQJBq7pCGp/YpXxAiZftVkMR6oOydo+Vo/pED3rSp7n6SGf5m40cM0Hpoo5e6UPnKLvUJJS9NiZHV/Lu7NP4VNAaO8SrRHxvUe2VPMxs3dhhITF776iq5VFYgBT48QFfPyaw0wFsPXkfKnCZViyNzdSd+htF6TkcYZ0O80GjiBN2AgMrK/BX6jIfelQLgBTuFNOU5s1v/TgiC0gdUXqYnf/N8/kAzlhwXm2x8jMtAW8Yx+Ci1MhW7+8olRW2",
-    "AMCV_8D0D1C8B532B54B40A490D4D%40AdobeOrg": "179643557%7CMCIDTS%7C20193%7CMCMID%7C36684697300333487793028373615178378568%7CMCAAMLH-1745218358%7C8%7CMCAAMB-1745218358%7CRKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y%7CMCOPTOUT-1744620758s%7CNONE%7CMCAID%7CNONE%7CvVersion%7C5.5.0",
-    "bxIDT": "",
-    "_fbp": "fb.1.1744613560083.2120932399812202",
-    "ASP.NET_SessionId": "f3dsc2stgnsfm35jm03erg1j",
-    "PlatformChannel": "REVTS1RPUA==",
-    "PlatformAppVersion": "",
-    "dotrez": "\\u0021moNy7WDrGPklsbbsNjR940Pn0OOujCv8dGPDL5PJDU70lLXZqJ1m4f4iRSglGB7jJCaANH7uqPY/PzU=",
-    "WorkFlow": "MA==",
-    "__RequestVerificationToken": "hvo_OXbN34o-NTEYGkBEeX0PJWTbdCXMhGIi-ch1wYib1fJZh1ujCrCCoEy2DUr_J5XL0xpsVAKew0bpcq2d7ZbdzuZa9fw0xL1-ILfq4Oo6Wb9OruX3Ky34UBFV5yi86N6B5A2",
-    "mcp-pre-selected-currency": "null",
-    "X-Session-Id": "f3dsc2stgnsfm35jm03erg1j",
-    "X-Session-Sig": "eb0dd2484b86005277b0571b451792e19391adb75db620b5c607a0c04c44c306",
-    "gpv_pn": "%2Fbooking%2Fselect-flights",
-    "gpv_mpl": "1",
-    "gpv_v1": "%2Fbooking-flow-ngbe",
-    "SEFD": "eyJPcmlnaW4iOiJQVkciLCJEZXN0aW5hdGlvbiI6IktNSSIsIlJvdW5kVHJpcCI6ZmFsc2UsIkRlcGFydHVyZURhdGUiOiIyMDI1LTA1LTE1VDAwOjAwOjAwIiwiUmV0dXJuRGF0ZSI6IjAwMDEtMDEtMDFUMDA6MDA6MDAiLCJBZHVsdHMiOjEsIkNoaWxkcmVuIjowLCJJbmZhbnRzIjowfQ==",
-    "bm_s": "YAAQUpw+FxXUtguWAQAAuVY3MwOqdib805oHFgMgglmkEF+c8Qf0hhRH9RSyvPKRKv4tFF+ibmCM40T1Cu/AlLCGLX8GvRiIzoCM5ONwiF2suBymLV1QR0P2l0GIh0sSIQ0UXvaTidz7D2O0BWRyKZUJpnM3Ois7hVJW0tWDVvQTIkK8NrYgdMJr0SLV9U/sqXS7U1Jdqg3yLzip6OLDY1IplbMJofy16dwGIRuy5NYbwlMpkq2BTKW8RhjDxSGZHZThLnLkIRGX7SlpybXhDMwSkFf9+UHCKMA2C5tSOAoum82aMI/ae6rRMHH32QOib6GFjXLyEvXRkgAVfWWpATmzS/AnQQIDTqGYJ7tkIUQYzGibg73OG63IfwunTnfiq673iUEhEliH49WwbUDCSj1a4mipChaEujPG7sWhpr51Rj8a7uvgKXsRPWNNbxXGp4rmmrTHaUHozuZV",
-    "bm_so": "506C3F1F429C03D7A6F354D59077C3132920801FCF4C82226135EAE8C27168A8~YAAQUpw+FxbUtguWAQAAulY3MwNxdhuBBkxMC+wofVTMg0gto9A0DdMNCIFq0NSf16LSlnwuHY8+G4MGBLfiBP4U9ros5JWYEa1LM4Bv9D1rxVxY3ni9IP30+YAs4KIbEVq/I1Ki4gbUo8afEMlWcVs0ii3zmDOMmfiyMq54k0Lvb6aoj1GgMh8D97lgtjDAjf5vY69yDjRHlhk40lIco6OWcNngh6vCr4AfSTf2iGaG38I+mpNrnCYPFUrhwpjqyp+4+75I8Rl7/9ntMKcRivyH/aO5xR1lrSUgBP9GB0l8+fvd9fZBu/ZjI7HFAb9rzLrfWQTMts+QepkR8yscHWshCKATuVkjEIe2JULM53kRQ9r8m77kqwuT03XS/8rgTUl9DSbu18kfqQtn+4loxxGBGZAUgNOvqR86SfXN/9VFQUDq7/3WR0gQ+5bNveVsMFD4dM4FMTvxsu7RlufcWQ==",
-    "MT": "1744615989411",
-    "ab.storage.sessionId.8eb26f80-6f07-43d3-be0e-778c98485224": "g%3A4c55aa01-21bc-c3c3-fbc4-252c2e5e71e8%7Ce%3A1744617790072%7Cc%3A1744613552264%7Cl%3A1744615990072",
-    "s_nbs": "1744615991",
-    "htjs_sesh": "{%22id%22:1744613626301%2C%22expiresAt%22:1744617792678%2C%22timeout%22:1800000%2C%22sessionStart%22:false%2C%22autoTrack%22:true}",
-    "bm_lso": "506C3F1F429C03D7A6F354D59077C3132920801FCF4C82226135EAE8C27168A8~YAAQUpw+FxbUtguWAQAAulY3MwNxdhuBBkxMC+wofVTMg0gto9A0DdMNCIFq0NSf16LSlnwuHY8+G4MGBLfiBP4U9ros5JWYEa1LM4Bv9D1rxVxY3ni9IP30+YAs4KIbEVq/I1Ki4gbUo8afEMlWcVs0ii3zmDOMmfiyMq54k0Lvb6aoj1GgMh8D97lgtjDAjf5vY69yDjRHlhk40lIco6OWcNngh6vCr4AfSTf2iGaG38I+mpNrnCYPFUrhwpjqyp+4+75I8Rl7/9ntMKcRivyH/aO5xR1lrSUgBP9GB0l8+fvd9fZBu/ZjI7HFAb9rzLrfWQTMts+QepkR8yscHWshCKATuVkjEIe2JULM53kRQ9r8m77kqwuT03XS/8rgTUl9DSbu18kfqQtn+4loxxGBGZAUgNOvqR86SfXN/9VFQUDq7/3WR0gQ+5bNveVsMFD4dM4FMTvxsu7RlufcWQ==^1744615996823",
-    "s_getNewRepeat": "1744616779146-Repeat",
-    "flightIndex": "0",
-    "bm_sv": "7207D8F841AF8E9BDA9D23034FADD6F8~YAAQJpw+FzzQIgSWAQAAk25DMxta9j5xv3jdwoJxDOITY+Wflqq2eFKYyqtfAuHvdw9eQ8UII/cXnBWOlcvbBye+bEarlRmHMLqVDFbOGOSlRA2j3PlmDst9mb10FDbpOPRyhUdTMl0v1vpGO+TwWds2JACGZMtiINRiE3kvVNR6x7zp3Q2n9Ac0MGlTMlIC8XpuMHLAWc/xghpX/vnGYtcAzfTQN7r0th8jd6HPzE+RrHZoPuMdv6gTUaVzEVC71Po=~1",
-    "_dd_s": "rum=1&id=c9cc81e9-3a29-4228-b957-dee6664e16d9&created=1744613551560&expire=1744617679229",
-    "bm_sz": "5EC9B527A352F347DA0063D7B71B3D08~YAAQLpw+F7XoYQuWAQAAX4FDMxvMs0Itx40egwDMd0XvSr1l/MsRFCtrIdzETkM0qc4aWXx9AbRnyrkPl+KlHR8MpwPfgBsEaplHDj3p3Mfzbnx8UvTfhRC/cnEOSEq3lEbspvqO6TpQqKYW3u41kCNBTPivAVDe9sx3MyRUfE7/k4PJOJSWVX+LNvXcis2aW4LzfACzo1LQDt4prs6TUfBCel37yo2T3g8Ek0uiRf/QoPGDzt2UNtGEvtxDgFZCdJErrkGzRj/P+LDm14JXqAXJXc0h720RvlO184xFlqSMJf9a/qLXZMwqJqzAUVbKjE65m7MInl/P4vSkC4FA+KbR9FBBgh+gVE/ivYpINz4jLZf7OcnWYPaGAEmqYSD5B/Q6pYUkETZOH7sJapqbxjN4ZHulFk7LlOmPNoIr7xRK8bzUe7R8Z9HDgv8mgWzsnhAcAY+Rf5XsewcTKXEa1fiXFVr5PaiZQPCyY+w3CbY/HHdpQwMlWlpNwMB9vCq0Vsj9w2kwbcQ0+TfkZ7XaHKuXwRErpscmjHavkhfu~4470852~4337713",
-    "RT": "\"z=1&dm=jetstar.com&si=e684950f-3a6d-4647-9fe3-27df785970eb&ss=m9gpv0pf&sl=g&tt=50nd&bcn=%2F%2F684d0d4c.akstat.io%2F&ld=1xeu2\"",
-    "_abck": "38D48222CFE7D244DC0476D5FD72BF23~0~YAAQLpw+F23qYQuWAQAA+5hDMw014xnfg6TDltur/ldhtpsCZO8HLjOH1lmPD7NSFPzqNwjZbyx0AQRMWWtSXV5letmclPNoGkrgxewo6RNE1/z1XBoT1FMxLAEDmIZdsnBy0ChHbwz2evSDSQmSMA/CvsKRAs13H7Yu35Al4Ks5nnXHWe27hXR4pDrcz4jveKfuPADWfTp4jNuQVzqexiXfB9u7iIrw1jt5uHH6PB8u9278aOu2DFq8CJts0lqjxyWRO4x1EGPu877yx+w1skLVE7CqVwzRIZnLQLJxI1ZOGOOnPX1GJOBr33oySZ342bh9jorYYLzNNo6FYPFKyomEel4LNerooclb747iEX4Li4LQLRadGkosssWXL6bdAkGOFdI4WYOjvHnRNWZcgjghJa5OfMq7/9BOIVqr8CSHFS7yWd6QEllSy84AuopZfELQtxETO+Ko1I3FKABC3CPPzgBMXLdGGxdKQU2QLIYPHuYJ47SpVeMcaA7/DN0EjLGe+PVQjw/LGSAlygUKdGmbyZR5DmnCqfHaE9nMik5JWTC1EGA+MJk7Zg+L0KFTqY4X2dKr+XpP+DjbI5pbUfGTR2YZYqFiQ4v5wVRefDxHqWzDPhQnvaj3+4ubiRVTDQsOjgoW2T1maLu76nhf/KAFjIVLc//82FB/8YhUItBw9n+8RNdNVhjVYszdeXf3B9gWMxNvwKdJBkPsCVsybpB9ZPfmlunsX9DEQ7eiwlSeWglC0y8NkvOMx8ACaWVY20yywYRdddVvz94ZEtQUodcll/Tp6mEIreSLfnyTKz6d0gOYDlycGj0Js1yYxJ2gOwfKGivyDB99qHSmjNsHVAE/+zhHQeWbUYufaQIKWTd0ptsN/gwKXq+BoGVB5PuXJJ9QGF8wUql1Cx+Aw+0EDyZpzxBylqGSbArqZhqI93KHiWKNRPFSl6F0vv+QjCrOob3u~-1~||0||~-1",
-    "sec_cpt": "A4CCF25250832ED2213B78C549F3367C~2~YAAQLpw+F27qYQuWAQAA+5hDMwwkgbOzQnx9/8SYdI7oPat24X5uht70NNJjmGxruTzynKkerbIJA8uQynenJ/P2ZVbNJTp91nNd8LCi1c6j59Swmi5p3U8QYs/6K7CekfqIDtBraWn6OT9dnD9dQ0+ng0ol2QK4k4kNIQ4ipVcHKf1fkbKaPlgNpPzRofS/33PKfQIOr8rt9DBfK+ohnkdC9SNaJtQJjN6/F/h318TCBxc3BeMxazFWYO0+zdcHfMaKaQZ0nXem5hj984NcAWgG4aEe+s+97VaIbCsnABrFxFtI71cXXfWfQNPGIAzGVGYHdvHnyVnqIhFwI8XZCo/+0AljqwIvWRwLkEZ31W9nnMozQswpe7EHjmDWCbbUg0fKzuz2l6iEtoCLsmjsE4b5YALcDlA3jV2VEUGKlZ0r5U2Lqqets2ZT6jSSBmBE4eeXNTxGlI5Hlzod7hzynq7xu9yY90aJ75UyidTiQ30EXCo8xk3RU5zfLAvMbmdGeGMGjIT4cFj/5M2DaUonlinlZxYIprz/YW7hDxXlAKEdMPziapqKjhtMEg7KPowknHcyaGvR7BVrKmZPMT9zwm4WWBN9xCBpQC5MjaQYRYTBOfK02lsxvya5JJfPYoxrqvgOnSk7mJNxLrSFvbovyqMKL8HeBZILYfsV3oUzenkto0ymGJdMbtlYRWuRQdN/rUkd5Yc4E7OOqYs8GaRdVHjTyZmIzkTgKuyX8SG9IOkiC2C6sjennQRFa2bjfZaH0LzbCB36cgXGM9+7ealO2ivpd/FKy7MF4qK1zazPU4/uRPG4jRRgFOpHIy2bH0wkq1jE4onpQqMkXCVCSsTuHf9CqX0mKKKJucQEq5IhAESmGK+vkGvJf1Q3NRuLyJvPdRX66ncAgri60TinzwQHDZRnaGBlbBl+bKywUpW5cXCK4rJ7oRwuyA8/6MI3ZA=="
-}
-url = "https://booking.jetstar.com/_sec/cp_challenge/verify"
-response = requests.get(url, headers=headers, cookies=cookies)
-
-print(response.text)
-print(response.cookies.get_dict())
-print(response)

+ 0 - 94
3.31Gk航司/其他/分析.txt

@@ -1,94 +0,0 @@
-
-可能是
- 0.请求 https://www.jetstar.com/IN8wyRJtH_OQqV-jNF2LfziXtCg/DJE5SpEuNO1J/BD9HAQ/KksEJgAX/I3M
-    携带cookie
-        _dd_s=  空值
-    获取cookie
-        ak_bmsc
-        user-location
- 1.先请求主页https://www.jetstar.com/hk/zh/home?tab=1,
-   携带cookie
-        _dd_s
-        ak_bmsc
-        ak_bmsc
-   获取cookie
-        AKA_A2
-        _abck
-        bm_mi
-        bm_s
-        bm_so
-        bm_ss
-        bm_sv
-        bm_sz
-
- 2.再请求https://auth.jetstar.com/authorize这个接口验证 获取cookies bm_sv值
-
-
-
- 请求航班信息中的这几个 cookie 是变化的
-    SEFD
-    bm_s
-    bm_so
-    bm_sz
-    bm_lso
-    MT
-    ab.storage.sessionId.8eb26f80-6f07-43d3-be0e-778c98485224
-    optimizelySession
-    bm_sv
-    s_nbs
-    htjs_sesh
-    _abck
-    RT
-    _dd_s
-    s_getNewRepeat
-
-
-
-
-
-
-澳大利亚的网站,代理用 AU
-
-
-cookie
-    备注: 要带  有时效性, 不带也可以请求,但是没有价格等数据
-    主要带以下 3 个值
-        SEFD: 不带它会触发验证码
-            来源: 请求成功后,响应cookie会返回这个值; 第一次生成位置待确定 ?
-            注意: 每次请求该值都会变化, 测试在同一个代码中, SEFD不变的情况下,最多请求4次, 第5次请求时,会触发验证码, 更换它就没事了)
-
-        ASP.NET_SessionId:
-            这个必须带,有时候不带也可以请求 待观察 (同一个会话中 ASP.NET_SessionId 是不变的 待验证!!)
-
-        bm_sz:
-            有时候只带这 1 个也可以请求
-            只带 SEFD 和 ASP.NET_SessionId 这2个,请求会报错, 测试了再带个 bm_sz 就可以正常请求
-            这个值不对, 也会触发验证码
-            来源: 有2个
-                1.请求主页来的
-                    请求主页响应的 https://www.jetstar.com/hk/zh/home, 请求接口后也会响应一个新的这个值
-                    请求主页响应的cookie值, 要再请求1次阿卡麦文件,, 响应 abck 为 -1 可以用
-
-                2.从网页akm接口获取
-                    Akamai文件分析
-                        第一次请求
-                            携带cookie: MT _dd_s  ak_bmsc
-                            返回响应{"success": false}
-                            响应cookie:_abck  bm_sz
-                            用这个响应cookie bm_sz 直接请求是不会请求成功的
-                        第二次请求
-                             响应cookie abck为 -1 也可以使用
-
-
-
-
-新ip请求 要过验证码  !!! 可能是加密参数没带全 或 没带对 所以出现验证码
-    验证api https://booking.jetstar.com/_sec/cp_challenge/verify
-     响应 cookie sec_cpt  应该是用这个cookie作为验证值, 验证时会请求几次 /0dVo  (阿卡麦验证接口),如果响应 abck 为 0的话 直接携带请求验证api接口
-     sec_cpt 里面也有关于它的状态值  注意观察!!
-
-
-
-
-响应数据在 html的   <script type="application/json" id="bundle-data-v2"  文件中
-

+ 0 - 20
3.31Gk航司/其他/获取加密cookie.py

@@ -1,20 +0,0 @@
-import requests
-
-
-headers = {
-    "accept": "*/*",
-    "accept-language": "zh-CN,zh;q=0.9",
-    "cache-control": "no-cache",
-    "content-type": "text/plain;charset=UTF-8",
-    "origin": "https://www.jetstar.com",
-    "pragma": "no-cache",
-    "priority": "u=1, i",
-    "referer": "https://www.jetstar.com/hk/zh/home?adults=1&children=0&flexible=1&flight-type=2&infants=0&origin=PVG&tab=1",
-    "sec-ch-ua": "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"",
-    "sec-ch-ua-mobile": "?0",
-    "sec-ch-ua-platform": "\"Windows\"",
-    "sec-fetch-dest": "empty",
-    "sec-fetch-mode": "cors",
-    "sec-fetch-site": "same-origin",
-    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
-}

+ 0 - 176
3.31Gk航司/请求-requests版.py

@@ -1,176 +0,0 @@
-from datetime import datetime, timedelta
-
-import requests
-
-from requests.exceptions import Timeout
-import retrying
-import execjs
-from lxml import etree
-import json
-from loguru import logger
-
-import threading
-from queue import Queue
-
-#
-
-# 禁用SSL相关警告 (推荐)
-from requests.packages.urllib3.exceptions import InsecureRequestWarning
-import warnings
-
-requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
-warnings.filterwarnings("ignore", category=DeprecationWarning)  # 可选:过滤其他警告
-
-
-class GK:
-
-    def __init__(self):
-        self.search_flights_api = "https://booking.jetstar.com/hk/zh/booking/search-flights"
-
-        self.headers = {
-            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36',
-            'Accept-Encoding': 'gzip, deflate, br',
-            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
-            'Connection': 'keep-alive',
-            'Content-Type': 'application/x-www-form-urlencoded',
-            'accept-language': 'zh-CN,zh;q=0.9',
-            'cache-control': 'no-cache',
-            'pragma': 'no-cache',
-            'priority': 'u=0, i',
-            'referer': 'https://booking.jetstar.com/',
-            'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
-            'sec-ch-ua-mobile': '?0',
-            'sec-ch-ua-platform': '"Windows"',
-            'sec-fetch-dest': 'document',
-            'sec-fetch-mode': 'navigate',
-            'sec-fetch-site': 'same-origin',
-            'sec-fetch-user': '?1',
-            'upgrade-insecure-requests': '1'
-        }
-        with open('./akm逆向/逆向.js', encoding='utf-8') as f:
-            js = f.read()
-        self.ctx = execjs.compile(js)
-        self.session = requests.Session()
-        # self.ip = 100000000000
-        # self.proxies = {
-        #     'http': f'http://B_3351_HK___5_ss-{self.ip}:ev2pjj@proxy.renlaer.com:7778',
-        #     'https': f'http://B_3351_HK___5_ss-{self.ip}:ev2pjj@proxy.renlaer.com:7778'
-        # }
-        # self.proxies = {
-        #     'http': f'127.0.0.1:8888',
-        #     'https': f'127.0.0.1:8888'
-        # }
-        self.cookies_queue = Queue()
-
-    def get_cookie(self):
-        logger.debug('正在获取 cookie bm-sz...')
-
-        # akm js file url
-        akm_url = "https://booking.jetstar.com/MkuYlo/pcp/LD0/PPluEQ/1ik7QcJffXbmL53i/QTcvXmg7/KS5kC3N/VRQcB"
-
-        data = {
-            'sensor_data': self.ctx.call('encrypt1')
-        }
-        response = self.session.post(akm_url, headers=self.headers, verify=False, data=data,
-                                     # proxies=self.proxies
-                                     )
-
-        # print(response.text)
-        bmsz = response.cookies.get_dict()['bm_sz']
-
-        data2 = {
-            "sensor_data": self.ctx.call('encrypt2', bmsz)
-        }
-
-        data2 = json.dumps(data2)
-        response2 = self.session.post(akm_url, headers=self.headers, data=data2, verify=False,
-                                      # proxies=self.proxies
-                                      )
-        # print(response2.text)
-        # print(response2.status_code)
-        logger.debug(f'成功获取到 bm-sz :{bmsz}')
-
-    @retrying.retry(stop_max_attempt_number=2)
-    def send_get(self, url, params):
-        response = self.session.get(
-            url,
-            headers=self.headers, params=params,
-            timeout=15,
-            verify=False,
-        )
-        response.raise_for_status()
-        return response
-
-    @retrying.retry(stop_max_attempt_number=3)
-    def get_data(self, datetime_str):
-        params = {
-            "s": "true",
-            "adults": "1",  # 成年人
-            "children": "0",  # 儿童
-            "infants": "0",  # 婴儿
-            "selectedclass1": "economy",  # 选择类型:经济舱
-            "currency": "CNY",  # 货币
-            "mon": "true",
-            "channel": "DESKTOP",
-            "origin1": "PVG",  # 出发地
-            "destination1": "NRT",  # 目的地
-            "departuredate1": datetime_str  # 出发时间
-        }
-        logger.info(f'正在采集 {datetime_str} 航班数据...')
-        try:
-            response = self.send_get(self.search_flights_api, params)
-
-            if not response:
-                return
-
-            return datetime_str, response
-            # print(response.text)
-
-        except Exception as e:
-            logger.error(e)
-            self.session = requests.Session()
-            # self.ip += 1
-            self.get_cookie()
-            raise
-            # return datetime_str, None
-
-    def parse_data(self, datetime_str, response):
-        if not response:
-            return
-
-        html = etree.HTML(response.text)
-        data = html.xpath("//script[@id='bundle-data-v2']/text()")
-        if data:
-            json_data = json.loads(data[0])
-            print(datetime_str, ' => ', json_data)
-        else:
-            logger.warning(f'{datetime_str} 当天暂无数据 / 触发验证码')
-            print(response.text)
-
-    @staticmethod
-    def gen_datetime(start_date, end_date):
-        current_date = datetime.strptime(start_date, '%Y-%m-%d')
-        end_date = datetime.strptime(end_date, '%Y-%m-%d')
-        date_list = []
-        while current_date <= end_date:
-            date_list.append(current_date.strftime('%Y-%m-%d'))  # 转换为字符串格式存储
-            current_date += timedelta(days=1)
-        return date_list
-
-    def run(self, start_date, end_date):
-        self.get_cookie()
-        # 获取采集时间
-        for num, datetime_str in enumerate(self.gen_datetime(start_date, end_date)):
-            # if num % 4 == 0:
-            #     self.session = requests.Session()
-            #     self.get_cookie()
-
-            datetime_str, response = self.get_data(datetime_str)
-            self.parse_data(datetime_str, response)
-            # time.sleep(2)
-
-
-if __name__ == '__main__':
-    gk = GK()
-    gk.run(start_date='2025-05-15', end_date='2025-05-27')
-

+ 0 - 168
3.31Gk航司/请求-tls_client.py

@@ -1,168 +0,0 @@
-import time
-from datetime import datetime, timedelta
-
-from tls_client import Session
-
-from requests.exceptions import Timeout
-import retrying
-import execjs
-from lxml import etree
-import json
-from loguru import logger
-
-import threading
-from queue import Queue
-import requests
-
-class GK:
-
-    def __init__(self):
-        self.search_flights_api = "https://booking.jetstar.com/hk/zh/booking/search-flights"
-
-        with open('./akm逆向/逆向.js', encoding='utf-8') as f:
-            js = f.read()
-        self.ctx = execjs.compile(js)
-        ja3 = "771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,5-10-11-17613-45-43-0-23-18-65037-27-35-13-51-65281-16-41,4588-29-23-24,0"
-
-        # 基础配置(指定浏览器指纹)
-        self.session = Session(
-            client_identifier="Chrome_120",  # 预设浏览器指纹
-            random_tls_extension_order=True,  # 随机tls指纹
-        )
-        self.session.http2 = True
-
-
-        # self.session = requests.Session()
-        self.headers = {
-            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
-            "accept-language": "zh-CN,zh;q=0.9",
-            "cache-control": "no-cache",
-            "pragma": "no-cache",
-            "priority": "u=0, i",
-            "referer": "https://booking.jetstar.com/",
-            "sec-ch-ua": "\"Google Chrome\";v=\"135\", \"Not-A.Brand\";v=\"8\", \"Chromium\";v=\"135\"",
-            "sec-ch-ua-mobile": "?0",
-            "sec-ch-ua-platform": "\"Windows\"",
-            "sec-fetch-dest": "document",
-            "sec-fetch-mode": "navigate",
-            "sec-fetch-site": "same-origin",
-            "sec-fetch-user": "?1",
-            "upgrade-insecure-requests": "1",
-            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
-        }
-
-    def get_cookie(self):
-        logger.debug('正在获取 cookie bm-sz...')
-
-        # akm js file url
-        akm_url = "https://booking.jetstar.com/MkuYlo/pcp/LD0/PPluEQ/1ik7QcJffXbmL53i/QTcvXmg7/KS5kC3N/VRQcB"
-
-        data = {
-            'sensor_data': self.ctx.call('encrypt1')
-        }
-        response = self.session.post(akm_url, headers=self.headers, data=data,
-                                     # proxies=self.proxies
-                                     )
-        # print(response.http_version)  # 应该显示 "HTTP/2"
-
-        # print(response.text)
-        bmsz = response.cookies.get_dict()['bm_sz']
-
-        data2 = {
-            "sensor_data": self.ctx.call('encrypt2', bmsz)
-        }
-
-        data2 = json.dumps(data2)
-        response2 = self.session.post(akm_url, headers=self.headers, data=data2,
-                                      # proxies=self.proxies
-                                      )
-        # print(response2.text)
-        # print(response2.status_code)
-        logger.debug(f'成功获取到 bm-sz :{bmsz}')
-
-    @retrying.retry(stop_max_attempt_number=2)
-    def send_get(self, url, params):
-
-        response = self.session.get(
-            url,
-            headers=self.headers,
-            params=params,
-        )
-        if response.status_code == 302:
-            url = 'https://booking.jetstar.com/hk/zh/booking/select-flights'
-            response = self.session.get(url, headers=self.headers)
-        print(response.status_code)
-        print(response.text)
-        return response
-
-    @retrying.retry(stop_max_attempt_number=3)
-    def get_data(self, datetime_str):
-        params = {
-            "s": "true",
-            "adults": "1",  # 成年人
-            "children": "0",  # 儿童
-            "infants": "0",  # 婴儿
-            "selectedclass1": "economy",  # 选择类型:经济舱
-            "currency": "CNY",  # 货币
-            "mon": "true",
-            "channel": "DESKTOP",
-            "origin1": "PVG",  # 出发地
-            "destination1": "NRT",  # 目的地
-            "departuredate1": datetime_str  # 出发时间
-        }
-        logger.info(f'正在采集 {datetime_str} 航班数据...')
-        try:
-            response = self.send_get(self.search_flights_api, params)
-
-            if not response:
-                return
-
-            return datetime_str, response
-            # print(response.text)
-
-        except Exception as e:
-            logger.error(e)
-            # self.ip += 1
-            self.get_cookie()
-            raise
-            # return datetime_str, None
-
-    def parse_data(self, datetime_str, response):
-        if not response:
-            return
-
-        html = etree.HTML(response.text)
-        data = html.xpath("//script[@id='bundle-data-v2']/text()")
-        if data:
-            json_data = json.loads(data[0])
-            print(datetime_str, ' => ', json_data)
-        else:
-            logger.warning(f'{datetime_str} 当天暂无数据 / 触发验证码')
-            print(response.text)
-
-    @staticmethod
-    def gen_datetime(start_date, end_date):
-        current_date = datetime.strptime(start_date, '%Y-%m-%d')
-        end_date = datetime.strptime(end_date, '%Y-%m-%d')
-        date_list = []
-        while current_date <= end_date:
-            date_list.append(current_date.strftime('%Y-%m-%d'))  # 转换为字符串格式存储
-            current_date += timedelta(days=1)
-        return date_list
-
-    def run(self, start_date, end_date):
-        self.get_cookie()
-        # 获取采集时间
-        for num, datetime_str in enumerate(self.gen_datetime(start_date, end_date)):
-            # if num % 4 == 0:
-            #     self.session = requests.Session()
-            #     self.get_cookie()
-
-            datetime_str, response = self.get_data(datetime_str)
-            self.parse_data(datetime_str, response)
-            time.sleep(2)
-
-
-if __name__ == '__main__':
-    gk = GK()
-    gk.run(start_date='2025-05-15', end_date='2025-05-27')

+ 0 - 72
3.31Gk航司/请求测试.py

@@ -1,72 +0,0 @@
-# import requests
-from curl_cffi import requests
-import retrying
-
-
-headers = {
-    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
-    "accept-language": "zh-CN,zh;q=0.9",
-    "cache-control": "no-cache",
-    "pragma": "no-cache",
-    "priority": "u=0, i",
-    "referer": "https://booking.jetstar.com/",
-    "sec-ch-ua": "\"Google Chrome\";v=\"135\", \"Not-A.Brand\";v=\"8\", \"Chromium\";v=\"135\"",
-    "sec-ch-ua-mobile": "?0",
-    "sec-ch-ua-platform": "\"Windows\"",
-    "sec-fetch-dest": "document",
-    "sec-fetch-mode": "navigate",
-    "sec-fetch-site": "same-origin",
-    "sec-fetch-user": "?1",
-    "upgrade-insecure-requests": "1",
-    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"
-}
-cookies = {
-
-    "bm_sz": "80764634952076F4EC0668CAE470DF02~YAAQh6InF+vHy7OWAQAAPBkxtBvjipCr2+Be8lQpPuukMutGdZhmvPLcnZxIE0H2SW8teLqWp1Pvw21yJC+5YdaIKtxfxi0OuJ8v+NYVJhYGUTIhe0PpH/U5LLuwLSHz3U/e4AhvEklMvEWDUPGyGsBVUktXU8G4WhSk0rur3qSc/ytEzR8U/oP3quyUwtlFgX8liYL6uhvWEY+4yRjnhaJykTIt7Fw+BhWNVvF8jKtn7usSkqm6oi+S3zSEZD8iBZolfvNCsmuZ3lD+PNlG8zH3hSiQAvC5vCPcskk6AONlJP2URQVkirgZzORWdM0+Uit7lyqEmossKcSdxITkS4amRpXnUN97PSG1Lji0j0JrytJAC2PP0VUlqtSgn0k/iTLz2+L498HNB0VpoSrW8lTry8jtixmFJ+c/iUiFWW6jvqZWAG6p01J+v95zmkX3vmkN2aR5p74UHxyBxm/Y4ZRlbgSj34TS+Z6erY/ezT0Xp9coSt7+mf2LntSVpSlxj4ZA54Pn5pN9oaPqtm1/Xz6kkYH43DIKXhoUghwV/YcKUeeF2bowXCWCbGVGkg==~3425331~3687985",
-
-}
-url = "https://booking.jetstar.com/hk/zh/booking/search-flights"
-
-
-
-
-@retrying.retry(stop_max_attempt_number=1)
-def req(i):
-    params = {
-        "s": "true",
-        "adults": "1",
-        "children": "0",
-        "infants": "0",
-        "selectedclass1": "economy",
-        "currency": "CNY",
-        "mon": "true",
-        "channel": "DESKTOP",
-        "origin1": "PVG",
-        "destination1": "NRT",
-        "departuredate1": f"2025-05-{i}"
-    }
-    response = requests.get(url, headers=headers, cookies=cookies, params=params,
-                            timeout=15,
-                            verify=False,
-                            # proxies=proxies
-                            # allow_redirects=False
-                            http_version=2
-
-                            )
-
-    # print(response.text)
-    print(response)
-
-
-    from lxml import etree
-    import json
-
-    html = etree.HTML(response.text)
-    data = html.xpath("//script[@id='bundle-data-v2']/text()")[0] if html.xpath(
-        "//script[@id='bundle-data-v2']/text()") else '{}'
-    json_data = json.loads(data)
-    print(json_data)
-
-
-for i in range(9, 31):
-    req(i)

Some files were not shown because too many files changed in this diff