西班牙华人网 西华论坛

 找回密码
 立即注册
搜索
查看: 48|回复: 2
收起左侧

用脚本自动刷新抢CITA

[复制链接]
发表于 9 小时前 | 显示全部楼层 |阅读模式
  1. // ==UserScript==
  2. // @name         Auto Cita Barcelona NIE (With Audio Alert)
  3. // @namespace    http://tampermonkey.net/
  4. // @version      1.4
  5. // @description  自动预约NIE指纹 CITA (Barcelona),修复误报并加入蜂鸣声音提醒
  6. // @match        https://icp.administracionelectronica.gob.es/icpplustieb/*
  7. // @match        https://icp.administracionelectronica.gob.es/icpplus/*
  8. // @grant        none
  9. // ==/UserScript==

  10. (function() {
  11.     'use strict';

  12.     // 个人信息配置
  13.     const NIE = "X0000000X";
  14.     const FULLNAME = "MINGZI XING";
  15.     const NATIONALITY = "CHINA";

  16.     // 简单日志
  17.     function log(msg) {
  18.         console.log("[CITA] " + msg);
  19.     }

  20.     // ???? 核心功能:播放警报蜂鸣声
  21.     function playAlertSound() {
  22.         try {
  23.             const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
  24.             const oscillator = audioCtx.createOscillator();
  25.             const gainNode = audioCtx.createGain();

  26.             oscillator.type = 'sine'; // 声音类型:正弦波(哔哔声)
  27.             oscillator.frequency.setValueAtTime(880, audioCtx.currentTime); // 音高:880Hz(比较清脆刺耳的高音)
  28.             gainNode.gain.setValueAtTime(0.5, audioCtx.currentTime); // 音量:0.5

  29.             oscillator.connect(gainNode);
  30.             gainNode.connect(audioCtx.destination);

  31.             oscillator.start();
  32.             // 响铃 0.8 秒后自动停止,配合外层的 setInterval 形成“哔-- 哔--”的间歇警报效果
  33.             setTimeout(() => {
  34.                 oscillator.stop();
  35.                 audioCtx.close();
  36.             }, 800);
  37.         } catch (e) {
  38.             log("播放声音失败(可能是浏览器权限限制): " + e);
  39.         }
  40.     }

  41.     // 首页:选择省份 Barcelona
  42.     if (location.pathname.endsWith("/index.html") || location.pathname.endsWith("/index")) {
  43.         log("首页:选择省份 Barcelona");
  44.         const sel = document.querySelector("select[name='form']");
  45.         if (sel) {
  46.             for (let opt of sel.options) {
  47.                 if (opt.text.toUpperCase().includes("BARCELONA")) {
  48.                     sel.value = opt.value;
  49.                     break;
  50.                 }
  51.             }
  52.             const btn = document.querySelector("input[type='submit'], button[type='submit']");
  53.             if (btn) setTimeout(() => btn.click(), 800);
  54.         }
  55.     }

  56.     // 业务选择页:选择 TOMA DE HUELLA
  57.     else if (location.pathname.includes("/citar")) {
  58.         log("业务选择页:选择 TOMA DE HUELLA");
  59.         const sel = document.querySelector("select[name='tramiteGrupo[0]']");
  60.         if (sel) {
  61.             sel.value = "4010"; // TOMA DE HUELLA
  62.             const btn = document.querySelector("input[type='submit'], button[type='submit']");
  63.             if (btn) setTimeout(() => btn.click(), 500);
  64.         }
  65.     }

  66.     // 填写个人资料页
  67.     else if (location.pathname.includes("/acEntrada")) {
  68.         log("填写个人资料(手动点击 Aceptar)");
  69.         const inputNie = document.querySelector("input[name='txtIdCitado']");
  70.         const inputName = document.querySelector("input[name='txtDesCitado']");

  71.         if (inputNie) inputNie.value = NIE;
  72.         if (inputName) inputName.value = FULLNAME;

  73.         // 自动选择国籍 CHINA
  74.         const sel = document.querySelector("select[name='txtPaisNac']");
  75.         if (sel) {
  76.             for (let opt of sel.options) {
  77.                 if (opt.text.trim().toUpperCase() === NATIONALITY.toUpperCase()) {
  78.                     sel.value = opt.value;
  79.                     break;
  80.                 }
  81.             }
  82.         }
  83.         log("【提示】个人信息已自动填好,请手动点击 Aceptar");
  84.     }

  85.     // 进入验证页:点击 SOLICITAR CITA
  86.     else if (location.pathname.includes("/acValidarEntrada")) {
  87.         log("点击 SOLICITAR CITA");
  88.         const btn = [...document.querySelectorAll("input[type='submit']")]
  89.             .find(b => b.value.toUpperCase().includes("SOLICITAR"));
  90.         if (btn) setTimeout(() => btn.click(), 500);
  91.     }

  92.     // Cita 结果页:精确检测是否有号
  93.     else if (location.pathname.includes("/acCitar")) {
  94.         const bodyText = document.body.innerText.toUpperCase();

  95.         // 1. 优先排除被防火墙拒绝或者系统崩溃的情况(防止误报有号)
  96.         if (bodyText.includes("REQUESTED URL WAS REJECTED") || bodyText.includes("FORBIDDEN") || bodyText.includes("ERROR")) {
  97.             log("❌ 糟糕,IP可能被封锁!停止自动刷新。");
  98.             alert("⚠️ 访问被防火墙拒绝(Rejected)!请切换网络(手机热点)再试。");
  99.             return;
  100.         }

  101.         // 2. 定义官方经典的几种“无号”核心提示语
  102.         const noCitaKeywords = [
  103.             "EN ESTE MOMENTO NO HAY CITAS DISPONIBLES",
  104.             "NO HAY CITAS DISPONIBLES",
  105.             "NO ENCONTRADO CITAS",
  106.             "En este momento no hay citas disponibles."
  107.         ];

  108.         // 检查页面是否包含任意一个无号关键词
  109.         const hasNoCita = noCitaKeywords.some(keyword => bodyText.includes(keyword));

  110.         if (hasNoCita) {
  111.             log("当前无号,45秒后自动刷新重试...");
  112.             setTimeout(() => location.reload(), 45000);
  113.         } else {
  114.             // 排除无号,排除报错 —— 确定有位置了!
  115.             log("???? 发现可用 CITA !!!");

  116.             // 每隔 1.5 秒鸣叫一次警报声,直到你处理页面
  117.             playAlertSound(); // 先响第一声
  118.             const soundInterval = setInterval(playAlertSound, 1500);

  119.             // 弹出提示框(点击确定后会关闭声音)
  120.             alert("???? 发现可用 CITA !!!请立刻手动选择办公室并确认!");
  121.             clearInterval(soundInterval); // 你点了弹窗的确定后,关闭警报声音
  122.         }
  123.     }

  124. })();
复制代码
以上是电脑版本。以下是手机版本。
  1. // ==UserScript==
  2. // @name         Auto Cita Barcelona NIE (Mobile Ultimate Edition)
  3. // @namespace    http://tampermonkey.net/
  4. // @version      2.0
  5. // @description  自动预约NIE指纹(手机深度优化 + 人类行为仿真 + 彻底解决Not Found)
  6. // @match        https://icp.administracionelectronica.gob.es/icpplustieb/*
  7. // @match        https://icp.administracionelectronica.gob.es/icpplus/*
  8. // @grant        none
  9. // ==/UserScript==

  10. (function() {
  11.     'use strict';

  12.     // =================================================================
  13.     // 个人信息配置(已为你保持原样)
  14.     // =================================================================
  15.     const NIE = "居留号";
  16.     const FULLNAME = "名-姓";
  17.     const NATIONALITY = "CHINA";

  18.     // 简单日志输出
  19.     function log(msg) {
  20.         console.log("[CITA] " + msg);
  21.     }

  22.     // ???? 核心功能:播放警报蜂鸣声(高频清脆哔哔声)
  23.     function playAlertSound() {
  24.         try {
  25.             const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
  26.             const oscillator = audioCtx.createOscillator();
  27.             const gainNode = audioCtx.createGain();

  28.             oscillator.type = 'sine';
  29.             oscillator.frequency.setValueAtTime(880, audioCtx.currentTime); // 880Hz 刺耳高音
  30.             gainNode.gain.setValueAtTime(0.5, audioCtx.currentTime); // 音量

  31.             oscillator.connect(gainNode);
  32.             gainNode.connect(audioCtx.destination);

  33.             oscillator.start();
  34.             // 响铃 0.8 秒后自动停止,配合外层的 setInterval 形成间歇警报
  35.             setTimeout(() => {
  36.                 oscillator.stop();
  37.                 audioCtx.close();
  38.             }, 800);
  39.         } catch (e) {
  40.             log("播放声音失败(可能是浏览器权限限制): " + e);
  41.         }
  42.     }

  43.     // ????️ 移动端核心防卡:仿真人输入,并强制触发下拉菜单的系统更换事件
  44.     function simulateHumanInput(element, value) {
  45.         element.value = value;
  46.         element.dispatchEvent(new Event('input', { bubbles: true }));
  47.         element.dispatchEvent(new Event('change', { bubbles: true }));
  48.         element.dispatchEvent(new KeyboardEvent('keydown', { bubbles: true, key: 'Enter' }));
  49.         element.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true, key: 'Enter' }));
  50.     }

  51.     // 生成随机延迟时间(让每次操作间隔都不同,完美迷惑防火墙行为审计)
  52.     function getRandomDelay(min, max) {
  53.         return Math.floor(Math.random() * (max - min + 1) + min);
  54.     }

  55.     // 1. 首页:自动选择省份 Barcelona
  56.     if (location.pathname.endsWith("/index.html") || location.pathname.endsWith("/index") || location.pathname === "/icpplustieb/" || location.pathname === "/icpplus/") {
  57.         log("首页:正在自动探测省份下拉框...");
  58.         const checkSelect = setInterval(() => {
  59.             const sel = document.querySelector("select[name='form']") || document.getElementById('provincia');
  60.             if (sel && sel.options.length > 1) {
  61.                 clearInterval(checkSelect); // 抓取成功,清除定时器
  62.                
  63.                 // 模拟人类:进页面发呆 1.2 - 2 秒再选择
  64.                 setTimeout(() => {
  65.                     for (let opt of sel.options) {
  66.                         if (opt.text.toUpperCase().includes("BARCELONA")) {
  67.                             simulateHumanInput(sel, opt.value);
  68.                             log("成功选择省份: BARCELONA");
  69.                             break;
  70.                         }
  71.                     }
  72.                     // 选完再等 1 秒多才点提交
  73.                     setTimeout(() => {
  74.                         const btn = document.querySelector("input[type='submit'], button[type='submit']");
  75.                         if (btn) { btn.click(); log("首页已成功提交"); }
  76.                     }, getRandomDelay(1000, 1500));
  77.                 }, getRandomDelay(1200, 2000));
  78.             }
  79.         }, 200);
  80.     }

  81.     // 2. 业务选择页:自动选择 TOMA DE HUELLA
  82.     else if (location.pathname.includes("/citar")) {
  83.         log("业务选择页:正在自动选择项目...");
  84.         const checkTramite = setInterval(() => {
  85.             const sel = document.querySelector("select[name='tramiteGrupo[0]']") || document.querySelector("select[id*='tramite']");
  86.             if (sel && sel.options.length > 1) {
  87.                 clearInterval(checkTramite);
  88.                
  89.                 // 模拟人类:等 1.5 到 2.5 秒再选项目
  90.                 setTimeout(() => {
  91.                     let found = false;
  92.                     for (let opt of sel.options) {
  93.                         if (opt.value === "4010" || opt.text.toUpperCase().includes("TOMA DE HUELLAS")) {
  94.                             simulateHumanInput(sel, opt.value);
  95.                             log("成功选择业务: TOMA DE HUELLAS (4010)");
  96.                             found = true;
  97.                             break;
  98.                         }
  99.                     }
  100.                     if(found) {
  101.                         // 选完再等 1.2 秒提交
  102.                         setTimeout(() => {
  103.                             const btn = document.querySelector("input[type='submit'], button[type='submit']");
  104.                             if (btn) { btn.click(); log("业务页已成功提交"); }
  105.                         }, getRandomDelay(1200, 1800));
  106.                     }
  107.                 }, getRandomDelay(1500, 2500));
  108.             }
  109.         }, 200);
  110.     }

  111.     // 3. 填写个人资料页:自动秒填数据
  112.     else if (location.pathname.includes("/acEntrada")) {
  113.         log("资料页:正在快速填写个人隐私数据...");
  114.         setTimeout(() => {
  115.             const inputNie = document.querySelector("input[name='txtIdCitado']");
  116.             const inputName = document.querySelector("input[name='txtDesCitado']");
  117.             const sel = document.querySelector("select[name='txtPaisNac']");

  118.             if (inputNie) simulateHumanInput(inputNie, NIE);
  119.             
  120.             // 故意延迟 500 毫秒填名字和国籍,模仿手速
  121.             setTimeout(() => {
  122.                 if (inputName) simulateHumanInput(inputName, FULLNAME);
  123.                 if (sel) {
  124.                     for (let opt of sel.options) {
  125.                         if (opt.text.trim().toUpperCase() === NATIONALITY.toUpperCase()) {
  126.                             simulateHumanInput(sel, opt.value);
  127.                             break;
  128.                         }
  129.                     }
  130.                 }
  131.                 log("【安全提示】所有资料已瞬间填好,请您【手动】点击大红按钮 Aceptar 提交!");
  132.             }, 500);
  133.         }, 1000);
  134.     }

  135.     // 4. 验证确认页:自动点击 SOLICITAR
  136.     else if (location.pathname.includes("/acValidarEntrada")) {
  137.         log("确认页:模拟人类阅读 1.2 秒后自动进入最后一步...");
  138.         setTimeout(() => {
  139.             const btn = [...document.querySelectorAll("input[type='submit']")]
  140.                 .find(b => b.value.toUpperCase().includes("SOLICITAR"));
  141.             if (btn) { btn.click(); log("已成功点击 SOLICITAR CITA"); }
  142.         }, getRandomDelay(1200, 1800));
  143.     }

  144.     // 5. Cita 结果页:智能判定有无号,利用后退流完美替代刷新
  145.     else if (location.pathname.includes("/acCitar")) {
  146.         const bodyText = document.body.innerText.toUpperCase();

  147.         // 优先拦截系统异常、封IP、或彻底断线的极端情况
  148.         if (bodyText.includes("NOT FOUND") || bodyText.includes("REQUESTED URL WAS REJECTED") || bodyText.includes("FORBIDDEN") || bodyText.includes("CADUCADA") || bodyText.includes("EXPIRADO")) {
  149.             log("❌ 页面异常或登录会话失效!5秒后自动强制跳回最开始的首页彻底重来...");
  150.             setTimeout(() => {
  151.                 location.href = "https://icp.administracionelectronica.gob.es/icpplustieb/index.html";
  152.             }, 5000);
  153.             return;
  154.         }

  155.         // 定义官方标准的无号关键词
  156.         const noCitaKeywords = ["EN ESTE MOMENTO NO HAY CITAS DISPONIBLES", "NO HAY CITAS DISPONIBLES", "NO ENCONTRADO CITAS", "En este momento no hay citas disponibles"];
  157.         const hasNoCita = noCitaKeywords.some(keyword => bodyText.includes(keyword));

  158.         if (hasNoCita) {
  159.             // 设置一个安全的查号等待期(35-45秒随机),防止高频刷新被系统拉黑
  160.             const reloadDelay = getRandomDelay(35000, 45000);
  161.             log(`当前暂无可用卡位。为了防止 Not Found 错误,系统将在 ${(reloadDelay/1000).toFixed(1)} 秒后自动后退并重新点进查询...`);
  162.             
  163.             setTimeout(() => {
  164.                 const btnVolver = document.querySelector("input[value='Volver'], input[value='Aceptar']");
  165.                 if (btnVolver) {
  166.                     btnVolver.click(); // 优先点击网页自带的红按钮退回第4步
  167.                     log("已模拟点击 Volver 按钮退回。");
  168.                 } else {
  169.                     history.back(); // 备用方案:通过浏览器历史记录强行后退
  170.                     log("未找到按钮,执行浏览器底层后退。");
  171.                 }
  172.             }, reloadDelay);
  173.         } else {
  174.             // 恭喜!排除所有异常和无号词,代表放号了!
  175.             log("???? 火力全开!发现可用指纹卡位 CITA !!!");

  176.             // 启动疯狂鸣叫警报机制
  177.             playAlertSound();
  178.             const soundInterval = setInterval(playAlertSound, 1500);

  179.             // 弹出强力锁屏弹窗,等你来处理
  180.             alert("???? 恭喜!系统发现可用 CITA !!!请立刻点击确定,然后以最快速度手动选择办公室并锁定你的号!");
  181.             clearInterval(soundInterval); // 一旦你手点了弹窗的确定,警报声才会关闭
  182.         }
  183.     }

  184. })();
复制代码
游客,如果您要查看本帖隐藏内容请回复





评分

参与人数 1银子 +999 收起 理由
yotranquilo + 999 给力!

查看全部评分

发表于 9 小时前 该贴发自手机用户 | 显示全部楼层
谢谢分享????辛苦啦(^????^)
回复 支持 反对

使用道具 举报

发表于 6 小时前 | 显示全部楼层
少数内容设置回复可见,避免帖子沉底
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们|广告服务|免责声明|小黑屋|友情链接|Archiver|联系我们|手机版|西班牙华人网 西华论坛 ( 蜀ICP备05006459号 )

GMT+2, 2026-7-15 22:25 , Processed in 0.009123 second(s), 12 queries , Gzip On, Redis On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表
手机版