您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
新球体育网(球探)手机端网页,比赛的分析页面右上角添加了一个按钮,点击后生成关键时间点的欧盘变化。
当前为
// ==UserScript== // @name 新球体育网欧盘分析 // @namespace http://dol.freevar.com/ // @version 0.5 // @description 新球体育网(球探)手机端网页,比赛的分析页面右上角添加了一个按钮,点击后生成关键时间点的欧盘变化。 // @author Dolphin // @match https://m.titan007.com/analy/Analysis/* // @match https://m.titan007.com/Analy/Analysis/* // @run-at document-idle // @grant GM_xmlhttpRequest // @license MIT // ==/UserScript== (function() { 'use strict'; // 添加欧盘按钮 const btnsDiv = document.querySelector('div.btns'); const oddsBtn = document.createElement('div'); oddsBtn.className = 'btn'; oddsBtn.textContent = '欧盘'; oddsBtn.style.backgroundColor = '#4c8'; btnsDiv.appendChild(oddsBtn); // 按钮点击事件处理 oddsBtn.addEventListener('click', function() { // 清除已存在的表格 const existingTable = document.querySelector('#oddsTable'); if (existingTable) { existingTable.remove(); } // 请求赔率数据 GM_xmlhttpRequest({ method: 'GET', url: `https://txt.titan007.com/1x2/${scheduleId}.js`, onload: function(response) { // 解析赔率数据 const data = parseOddsData(response.responseText); if (!data) return; // 获取需要分析的时间点 const timePoints = getTimePoints(data); // 计算每个时间点的平均赔率 const oddsData = calculateAverageOdds(data, timePoints); // 创建并插入表格 const table = createOddsTable(oddsData); const contentDiv = document.querySelector('div#content'); contentDiv.insertBefore(table, contentDiv.firstChild); } }); }); // 解析赔率数据 function parseOddsData(responseText) { try { // 创建临时变量存储解析结果 const data = {}; // 提取公司信息 const gameMatch = responseText.match(/var game=Array\((.*?)\);/); if (gameMatch && gameMatch[1]) { data.companies = {}; const companyEntries = gameMatch[1].split('","'); companyEntries.forEach(entry => { const parts = entry.replace(/^"|"$/g, '').split('|'); if (parts.length >= 3) { data.companies[parts[1]] = { id: parts[1], name: parts[2] }; } }); } // 提取赔率详情 const gameDetailMatch = responseText.match(/var gameDetail=Array\((.*?)\);/); if (gameDetailMatch && gameDetailMatch[1]) { data.details = {}; const detailEntries = gameDetailMatch[1].split('","'); detailEntries.forEach(entry => { const cleanEntry = entry.replace(/^"|"$/g, ''); const [companyId, oddsStr] = cleanEntry.split('^'); if (companyId && oddsStr) { data.details[companyId] = []; const oddsEntries = oddsStr.split(';'); oddsEntries.forEach(oddEntry => { if (oddEntry.trim() === '') return; const parts = oddEntry.split('|'); if (parts.length >= 4) { // 解析时间 const dateParts = parts[3].split(' '); const timeParts = dateParts[1].split(':'); const monthDay = dateParts[0].split('-'); const year = parts[7] || new Date().getFullYear(); const date = new Date( parseInt(year), parseInt(monthDay[0]) - 1, parseInt(monthDay[1]), parseInt(timeParts[0]), parseInt(timeParts[1]) ); data.details[companyId].push({ win: parseFloat(parts[0]), draw: parseFloat(parts[1]), lose: parseFloat(parts[2]), timestamp: date.getTime() }); } }); // 按时间排序 data.details[companyId].sort((a, b) => a.timestamp - b.timestamp); } }); } return data; } catch (e) { console.error('解析赔率数据出错:', e); return null; } } // 获取需要分析的时间点 function getTimePoints(data) { // 收集网页自带的4个时间戳 const baseTimes = [ parseInt(jsonData.nearMatches.homeMatches.matches[0].matchTime) * 1000, parseInt(jsonData.nearMatches.homeMatches.matches[1].matchTime) * 1000, parseInt(jsonData.nearMatches.awayMatches.matches[0].matchTime) * 1000, parseInt(jsonData.nearMatches.awayMatches.matches[1].matchTime) * 1000 ]; // 添加这4个时间点的3小时后 const threeHoursLater = baseTimes.map(time => time + 3 * 60 * 60 * 1000); // 找到所有公司最早有赔率数据的时间点 let earliestOddsTime = Infinity; Object.values(data.details).forEach(companyOdds => { if (companyOdds.length > 0 && companyOdds[0].timestamp < earliestOddsTime) { earliestOddsTime = companyOdds[0].timestamp; } }); // 添加最早时间点和24小时后 const earliestTimes = [ earliestOddsTime + 3600000, earliestOddsTime + 24 * 60 * 60 * 1000 ]; // 合并所有时间点并去重,然后按降序排列 const allTimes = [...baseTimes, ...threeHoursLater, ...earliestTimes]; const uniqueTimes = [...new Set(allTimes)]; uniqueTimes.sort((a, b) => b - a); return uniqueTimes; } // 计算每个时间点的平均赔率 function calculateAverageOdds(data, timePoints) { const result = []; timePoints.forEach(timestamp => { let totalWin = 0; let totalDraw = 0; let totalLose = 0; let companyCount = 0; // 计算每个公司在该时间点前的最新赔率 Object.values(data.details).forEach(companyOdds => { // 找到时间点前的最后一个赔率记录 for (let i = companyOdds.length - 1; i >= 0; i--) { if (companyOdds[i].timestamp <= timestamp) { totalWin += companyOdds[i].win; totalDraw += companyOdds[i].draw; totalLose += companyOdds[i].lose; companyCount++; break; } } }); // 计算平均值 result.push({ timestamp: timestamp, companyCount: companyCount, avgWin: companyCount > 0 ? (totalWin / companyCount).toFixed(4) : '-', avgDraw: companyCount > 0 ? (totalDraw / companyCount).toFixed(4) : '-', avgLose: companyCount > 0 ? (totalLose / companyCount).toFixed(4) : '-' }); }); return result; } // 创建赔率表格 function createOddsTable(oddsData) { const table = document.createElement('table'); table.id = 'oddsTable'; table.style.borderCollapse = 'collapse'; table.style.margin = '0 auto'; table.style.textAlign = 'center'; table.style.fontSize = '16px'; // 创建表头 const thead = document.createElement('thead'); const headerRow = document.createElement('tr'); headerRow.style.backgroundColor = '#ddd'; const headers = ['公司数量', '平均胜赔', '平均平赔', '平均负赔', '时间']; headers.forEach(text => { const th = document.createElement('th'); th.textContent = text; th.style.border = '1px solid #888'; headerRow.appendChild(th); }); thead.appendChild(headerRow); table.appendChild(thead); // 创建表体 const tbody = document.createElement('tbody'); oddsData.forEach((data, index) => { const row = document.createElement('tr'); row.style.backgroundColor = index % 2 === 0 ? '#fff' : '#eee'; // 公司数量 const countCell = document.createElement('td'); countCell.textContent = data.companyCount; countCell.style.border = '1px solid #888'; row.appendChild(countCell); // 平均胜赔(带颜色变化) const winCell = document.createElement('td'); winCell.textContent = data.avgWin; winCell.style.border = '1px solid #888'; if (index < oddsData.length - 1 && data.avgWin !== '-' && oddsData[index + 1].avgWin !== '-') { const current = data.avgWin; const next = oddsData[index + 1].avgWin; if (current > next) { winCell.style.backgroundColor = '#fbb'; // 上涨(较下一行更高) } else if (current < next) { winCell.style.backgroundColor = '#bfb'; // 下跌(较下一行更低) } } row.appendChild(winCell); // 平均平赔(带颜色变化) const drawCell = document.createElement('td'); drawCell.textContent = data.avgDraw; drawCell.style.border = '1px solid #888'; if (index < oddsData.length - 1 && data.avgDraw !== '-' && oddsData[index + 1].avgDraw !== '-') { const current = data.avgDraw; const next = oddsData[index + 1].avgDraw; if (current > next) { drawCell.style.backgroundColor = '#fbb'; // 上涨 } else if (current < next) { drawCell.style.backgroundColor = '#bfb'; // 下跌 } } row.appendChild(drawCell); // 平均负赔(带颜色变化) const loseCell = document.createElement('td'); loseCell.textContent = data.avgLose; loseCell.style.border = '1px solid #888'; if (index < oddsData.length - 1 && data.avgLose !== '-' && oddsData[index + 1].avgLose !== '-') { const current = data.avgLose; const next = oddsData[index + 1].avgLose; if (current > next) { loseCell.style.backgroundColor = '#fbb'; // 上涨 } else if (current < next) { loseCell.style.backgroundColor = '#bfb'; // 下跌 } } row.appendChild(loseCell); // 时间 const timeCell = document.createElement('td'); const date = new Date(data.timestamp); timeCell.textContent = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`; timeCell.style.border = '1px solid #888'; row.appendChild(timeCell); tbody.appendChild(row); }); table.appendChild(tbody); return table; } })();