您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
新球体育网(球探)手机端网页,在赛程页面加入“统计”按钮,点击后统计当前页面有完场比分的比赛。在分析页面右上角加入“表格”按钮,点击后生成各公司的统计表格。误差越低的公司越准确,预测出来的只是一个相对方向。
// ==UserScript== // @name 新球体育网亚盘统计 // @namespace http://dol.freevar.com/ // @version 0.91 // @description 新球体育网(球探)手机端网页,在赛程页面加入“统计”按钮,点击后统计当前页面有完场比分的比赛。在分析页面右上角加入“表格”按钮,点击后生成各公司的统计表格。误差越低的公司越准确,预测出来的只是一个相对方向。 // @author Dolphin // @match https://m.titan007.com/info/* // @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'; // 检查当前URL并执行相应操作 const currentUrl = window.location.href; if (currentUrl.match(/https:\/\/m\.titan007\.com\/info\//)) { handleInfoPage(); } else if (currentUrl.match(/https:\/\/m\.titan007\.com\/analy\/Analysis\//i)) { handleAnalysisPage(); } /** * 处理info页面:添加统计和清除按钮 */ function handleInfoPage() { // 在.matchname中添加按钮 const matchnameDiv = document.querySelector('.matchname'); if (matchnameDiv) { // 创建统计按钮 const statsBtn = document.createElement('button'); statsBtn.textContent = '统计'; statsBtn.style.margin = '0 5px'; statsBtn.style.padding = '3px 8px'; statsBtn.style.cursor = 'pointer'; statsBtn.style.background = '#bfb'; statsBtn.addEventListener('click', analyzeMatches); // 创建清除按钮 const clearBtn = document.createElement('button'); clearBtn.textContent = '清除'; clearBtn.style.margin = '0 5px'; clearBtn.style.padding = '3px 8px'; clearBtn.style.cursor = 'pointer'; clearBtn.style.background = '#fbb'; clearBtn.addEventListener('click', clearStatistics); matchnameDiv.appendChild(clearBtn); matchnameDiv.appendChild(statsBtn); } } /** * 处理Analysis页面:添加表格按钮 */ function handleAnalysisPage() { // 在.btns中添加表格按钮 const btnsDiv = document.querySelector('.btns'); if (btnsDiv) { const tableBtn = document.createElement('div'); tableBtn.className = 'btn'; tableBtn.textContent = '表格'; tableBtn.style.background = '#4c8'; tableBtn.addEventListener('click', showStatisticsTable); btnsDiv.appendChild(tableBtn); } } /** * 分析所有比赛数据 */ async function analyzeMatches() { // 找到所有包含红色比分的<tr>元素 const matchRows = document.querySelectorAll('tr:has(span.red, span[style*="color:red"])'); if (matchRows.length === 0) { alert('未找到符合条件的比赛数据'); return; } let processedCount = 0; for (const row of matchRows) { try { // 获取比赛ID const onclickAttr = row.getAttribute('onclick'); const matchIdMatch = onclickAttr.match(/ToAnaly\((\d+)\s*,\s*-1\)/); if (!matchIdMatch) continue; const matchId = matchIdMatch[1]; // 获取实际比分并计算比分差 const scoreSpan = row.querySelector('span.red, span[style*="color:red"]'); if (!scoreSpan) continue; const scoreText = scoreSpan.textContent.trim(); const scoreParts = scoreText.split(':').map(Number); if (scoreParts.length !== 2) continue; const [homeScore, awayScore] = scoreParts; const actualDiff = homeScore - awayScore; // 获取赔率数据 const oddsData = await fetchOddsData(matchId); if (!oddsData) continue; // 处理赔率数据并计算误差 processOddsData(oddsData, actualDiff, matchId); processedCount++; } catch (error) { console.error('处理比赛数据时出错:', error); } } alert(`已统计 ${processedCount} 场比赛`); } /** * 获取赔率数据 */ async function fetchOddsData(scheduleId) { try { const response = await fetch(`/HandicapDataInterface.ashx?scheid=${scheduleId}&type=1&oddskind=0&isHalf=0`); if (!response.ok) return null; const data = await response.json(); return data; } catch (error) { console.error('获取赔率数据失败:', error); return null; } } /** * 处理赔率数据并计算误差 */ function processOddsData(oddsData, actualDiff, matchId) { if (!oddsData.companies || !oddsData.companies.length) return; // 收集所有预期比分差用于找到标准值 const allExpectedDiffs = []; // 先遍历所有公司收集数据 oddsData.companies.forEach(company => { // 只取num为1的数据 const detail = company.details.find(d => d.num === 1); if (!detail) return; // 计算初盘预期比分差 const firstDrawOdds = detail.firstDrawOdds !== undefined ? detail.firstDrawOdds : 0; const firstExpectedDiff = firstDrawOdds + (detail.firstAwayOdds - detail.firstHomeOdds) / 2; allExpectedDiffs.push(firstExpectedDiff); // 计算即时盘预期比分差(如果有数据) if (detail.homeOdds !== undefined && detail.awayOdds !== undefined) { const drawOdds = detail.drawOdds !== undefined ? detail.drawOdds : 0; const liveExpectedDiff = drawOdds + (detail.awayOdds - detail.homeOdds) / 2; allExpectedDiffs.push(liveExpectedDiff); } }); if (allExpectedDiffs.length === 0) return; // 找到最接近实际比分差的预期比分差作为标准 const standardDiff = findClosestValue(allExpectedDiffs, actualDiff); // 再次遍历公司计算误差并保存 oddsData.companies.forEach(company => { const companyName = company.nameCn; const detail = company.details.find(d => d.num === 1); if (!detail) return; // 处理初盘数据 const firstDrawOdds = detail.firstDrawOdds !== undefined ? detail.firstDrawOdds : 0; const firstExpectedDiff = firstDrawOdds + (detail.firstAwayOdds - detail.firstHomeOdds) / 2; const firstError = firstExpectedDiff - standardDiff; // 处理即时盘数据(如果有) let liveError = null; if (detail.homeOdds !== undefined && detail.awayOdds !== undefined) { const drawOdds = detail.drawOdds !== undefined ? detail.drawOdds : 0; const liveExpectedDiff = drawOdds + (detail.awayOdds - detail.homeOdds) / 2; liveError = liveExpectedDiff - standardDiff; } // 保存到localStorage saveToLocalStorage(companyName, '初盘', matchId, firstError); if (liveError !== null) { saveToLocalStorage(companyName, '即时盘', matchId, liveError); } }); } /** * 找到数组中最接近目标值的元素 */ function findClosestValue(arr, target) { return arr.reduce((prev, curr) => { return (Math.abs(curr - target) < Math.abs(prev - target) ? curr : prev); }); } /** * 保存数据到localStorage */ function saveToLocalStorage(companyName, oddsType, matchId, error) { let stats = JSON.parse(localStorage.getItem('footballOddsStats') || '{}'); // 初始化公司数据 if (!stats[companyName]) { stats[companyName] = { '初盘': {}, '即时盘': {} }; } // 保存误差数据(如果该比赛ID尚未记录) if (!stats[companyName][oddsType][matchId]) { stats[companyName][oddsType][matchId] = error; } // 保存回localStorage localStorage.setItem('footballOddsStats', JSON.stringify(stats)); } /** * 清除所有统计数据 */ function clearStatistics() { if (confirm('确定要清除所有统计数据吗?')) { localStorage.removeItem('footballOddsStats'); } } /** * 在Analysis页面显示统计表格 */ async function showStatisticsTable() { // 获取当前比赛ID(假设页面已定义scheduleId变量) if (!scheduleId) { alert('无法获取比赛ID'); return; } // 获取赔率数据 const oddsData = await fetchOddsData(scheduleId); if (!oddsData || !oddsData.companies || !oddsData.companies.length) { alert('无法获取赔率数据'); return; } // 获取本地存储的统计数据 const stats = JSON.parse(localStorage.getItem('footballOddsStats') || '{}'); // 计算当前比赛各公司的预期比分差 const currentMatchOdds = {}; oddsData.companies.forEach(company => { const companyName = company.nameCn; const detail = company.details.find(d => d.num === 1); if (!detail) return; currentMatchOdds[companyName] = {}; // 初盘 const firstDrawOdds = detail.firstDrawOdds !== undefined ? detail.firstDrawOdds : 0; currentMatchOdds[companyName]['初盘'] = firstDrawOdds + (detail.firstAwayOdds - detail.firstHomeOdds) / 2; // 即时盘(如果有) if (detail.homeOdds !== undefined && detail.awayOdds !== undefined) { const drawOdds = detail.drawOdds !== undefined ? detail.drawOdds : 0; currentMatchOdds[companyName]['即时盘'] = drawOdds + (detail.awayOdds - detail.homeOdds) / 2; } }); // 清除已存在的表格(如果有) const existingTables = document.querySelectorAll('.odds-stats-table'); existingTables.forEach(table => table.remove()); // 生成初盘和即时盘的统计表格 generateTable('即时盘', stats, currentMatchOdds); generateTable('初盘', stats, currentMatchOdds); } /** * 生成统计表格 */ function generateTable(oddsType, stats, currentOdds) { // 创建表格容器 const tableContainer = document.createElement('div'); tableContainer.className = 'odds-stats-table'; tableContainer.style.border = '1px solid #ccc'; tableContainer.style.borderRadius = '10px'; // 创建标题 const title = document.createElement('h3'); title.textContent = `${oddsType}统计`; title.style.padding = '5px'; title.style.background = '#bdf'; tableContainer.appendChild(title); // 创建表格 const table = document.createElement('table'); table.style.borderCollapse = 'collapse'; table.style.textAlign = 'center'; table.style.margin = '0 auto'; table.style.fontSize = '16px'; // 创建表头 const thead = document.createElement('thead'); const headerRow = document.createElement('tr'); headerRow.style.backgroundColor = '#eee'; ['公司', '开盘', '平均误差', '预期比分差'].forEach(text => { const th = document.createElement('th'); th.textContent = text; th.style.border = '1px solid #ccc'; headerRow.appendChild(th); }); thead.appendChild(headerRow); table.appendChild(thead); // 创建表格内容 const tbody = document.createElement('tbody'); // 收集并处理数据 const tableData = []; for (const companyName in stats) { const companyData = stats[companyName]; if (!companyData[oddsType]) continue; const matchIds = Object.keys(companyData[oddsType]); const count = matchIds.length; // 计算平均误差(绝对值的平均值) const totalError = matchIds.reduce((sum, matchId) => { return sum + Math.abs(companyData[oddsType][matchId]); }, 0); const avgError = totalError / count; // 获取当前比赛的预期比分差 const currentExpectedDiff = currentOdds[companyName] && currentOdds[companyName][oddsType] ? currentOdds[companyName][oddsType] : '无数据'; tableData.push({ company: companyName, count: count, avgError: avgError, currentDiff: currentExpectedDiff }); } // 按平均误差排序 tableData.sort((a, b) => a.avgError - b.avgError); // 填充表格 tableData.forEach((item, index) => { const row = document.createElement('tr'); row.style.backgroundColor = index % 2 === 0 ? '#fff' : '#eeeeee'; const companyCell = document.createElement('td'); companyCell.textContent = item.company; companyCell.style.border = '1px solid #ccc'; row.appendChild(companyCell); const countCell = document.createElement('td'); countCell.textContent = item.count; countCell.style.border = '1px solid #ccc'; row.appendChild(countCell); const avgErrorCell = document.createElement('td'); avgErrorCell.textContent = item.avgError.toFixed(4); avgErrorCell.style.border = '1px solid #ccc'; row.appendChild(avgErrorCell); const diffCell = document.createElement('td'); diffCell.textContent = typeof item.currentDiff === 'number' ? item.currentDiff.toFixed(3) : item.currentDiff; diffCell.style.border = '1px solid #ccc'; row.appendChild(diffCell); tbody.appendChild(row); }); table.appendChild(tbody); tableContainer.appendChild(table); // 插入到页面中 const contentDiv = document.querySelector('#content'); if (contentDiv && contentDiv.firstChild) { contentDiv.insertBefore(tableContainer, contentDiv.firstChild); } } })();