您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
爬取体彩大乐透历史开奖信息并导出Excel
// ==UserScript== // @name 体彩大乐透历史开奖信息下载 // @namespace http://tampermonkey.net/ // @version 1.0 // @license MIT // @description 爬取体彩大乐透历史开奖信息并导出Excel // @author 白虎万岁 // @match https://www.lottery.gov.cn/kj/kjlb.html?dlt // @grant GM_addStyle // @grant GM_xmlhttpRequest // @connect www.lottery.gov.cn // @require https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js // ==/UserScript== (function () { 'use strict'; // 添加样式 GM_addStyle(` .lottery-btn { position: fixed; right: 160px; top: 290px; width: 40px; height: 32px; background: linear-gradient(145deg, #e74c3c, #c0392b); border-radius: 4px; color: white; font-size: 16px; font-weight: bold; display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 9999; font-family: "Microsoft YaHei", sans-serif; box-shadow: 0 2px 5px rgba(0,0,0,0.2); transition: all 0.3s; text-shadow: 1px 1px 2px rgba(0,0,0,0.2); } .lottery-btn:hover { transform: scale(1.1); box-shadow: 0 4px 10px rgba(0,0,0,0.3); } .date-picker { position: fixed; right: 70px; top: 50%; transform: translateY(-50%); background: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px 20px rgba(0,0,0,0.1); display: none; z-index: 9999; font-family: "Microsoft YaHei", sans-serif; } .date-picker .title { font-size: 14px; color: #333; margin-bottom: 10px; text-align: center; } .date-picker input { margin: 5px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; width: calc(100% - 26px); font-size: 14px; } .date-picker input:focus { border-color: #3498db; outline: none; } .date-picker button { margin: 5px; padding: 8px 15px; background: linear-gradient(145deg, #3498db, #2980b9); color: white; border: none; border-radius: 4px; cursor: pointer; width: calc(100% - 10px); font-size: 14px; transition: all 0.3s; } .date-picker button:hover { background: linear-gradient(145deg, #2980b9, #2471a3); transform: translateY(-1px); } .status-message { position: fixed; bottom: 20px; right: 20px; padding: 10px 20px; background: rgba(0,0,0,0.8); color: white; border-radius: 4px; display: none; z-index: 10000; font-family: "Microsoft YaHei", sans-serif; } `); // 创建DOM元素 function createElements () { // 创建按钮 const btn = document.createElement('div'); btn.className = 'lottery-btn'; btn.innerHTML = '奖'; document.body.appendChild(btn); // 创建日期选择器 const datePicker = document.createElement('div'); datePicker.className = 'date-picker'; datePicker.innerHTML = ` <div class="title">选择日期范围</div> <input type="date" id="startDate" placeholder="开始日期"> <input type="date" id="endDate" placeholder="结束日期"> <button id="fetchBtn">获取数据</button> <button id="fetch30Btn">获取近30期</button> `; document.body.appendChild(datePicker); // 创建状态消息 const statusMsg = document.createElement('div'); statusMsg.className = 'status-message'; document.body.appendChild(statusMsg); return { btn, datePicker, statusMsg }; } // 显示状态消息 function showStatus (message, duration = 3000) { const statusMsg = document.querySelector('.status-message'); statusMsg.textContent = message; statusMsg.style.display = 'block'; setTimeout(() => { statusMsg.style.display = 'none'; }, duration); } // 数据处理函数 async function fetchLotteryData (startDate, endDate) { try { showStatus('正在获取数据...'); // 获取表格数据 const table = document.querySelector('.result_table'); if (!table) { throw new Error('未找到数据表格'); } const rows = Array.from(table.querySelectorAll('tr')).slice(1); // 跳过表头 const data = []; let count = 0; for (const row of rows) { const cells = row.querySelectorAll('td'); if (cells.length > 0) { const rowDate = cells[1].textContent.trim(); // 日期筛选 if ((!startDate || !endDate || (rowDate >= startDate && rowDate <= endDate)) && count < 30) { // 获取开奖号码 const frontNumbers = Array.from(cells[2].querySelectorAll('.blue_ball')).map(num => num.textContent.trim()); const backNumbers = Array.from(cells[2].querySelectorAll('.red_ball')).map(num => num.textContent.trim()); data.push({ '期号': cells[0].textContent.trim(), '开奖日期': rowDate, '前区号码': frontNumbers.join(' '), '后区号码': backNumbers.join(' '), '一等奖基本注数': cells[3].textContent.trim() || '0', '一等奖基本奖金(元)': cells[4].textContent.trim() || '0', '一等奖追加注数': cells[5].textContent.trim() || '0', '一等奖追加奖金(元)': cells[6].textContent.trim() || '0', '二等奖基本注数': cells[7].textContent.trim() || '0', '二等奖基本奖金(元)': cells[8].textContent.trim() || '0', '二等奖追加注数': cells[9].textContent.trim() || '0', '二等奖追加奖金(元)': cells[10].textContent.trim() || '0', '销售额(元)': cells[11].textContent.trim() || '0', '奖池奖金(元)': cells[12].textContent.trim() || '0' }); count++; } } } if (data.length === 0) { showStatus('未找到符合条件的数据'); return; } showStatus('正在生成Excel文件...'); // 导出Excel const ws = XLSX.utils.json_to_sheet(data); const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "大乐透开奖数据"); // 设置列宽 const colWidths = [10, 12, 15, 15, 12, 15, 12, 15, 12, 15, 12, 15, 15, 15]; ws['!cols'] = colWidths.map(w => ({ wch: w })); // 下载文件 const fileName = `大乐透开奖数据_${new Date().toISOString().split('T')[0]}.xlsx`; XLSX.writeFile(wb, fileName); showStatus('数据导出成功!'); } catch (error) { console.error('获取数据失败:', error); showStatus('获取数据失败: ' + error.message); } } // 添加等待表格加载的函数 function waitForTable () { return new Promise((resolve, reject) => { let attempts = 0; const maxAttempts = 20; const interval = setInterval(() => { const table = document.querySelector('.result_table'); if (table) { clearInterval(interval); resolve(); } else if (attempts >= maxAttempts) { clearInterval(interval); reject(new Error('加载超时,未找到数据表格')); } attempts++; }, 500); }); } // 初始化函数 function init () { const { btn, datePicker } = createElements(); // 事件监听 btn.addEventListener('click', () => { datePicker.style.display = datePicker.style.display === 'none' ? 'block' : 'none'; }); document.getElementById('fetchBtn').addEventListener('click', async () => { const startDate = document.getElementById('startDate').value; const endDate = document.getElementById('endDate').value; if (!startDate || !endDate) { showStatus('请选择开始和结束日期'); return; } if (startDate > endDate) { showStatus('开始日期不能大于结束日期'); return; } try { await waitForTable(); await fetchLotteryData(startDate, endDate); datePicker.style.display = 'none'; } catch (error) { showStatus(error.message); } }); document.getElementById('fetch30Btn').addEventListener('click', async () => { try { await waitForTable(); await fetchLotteryData(); datePicker.style.display = 'none'; } catch (error) { showStatus(error.message); } }); // 点击其他区域关闭日期选择器 document.addEventListener('click', (e) => { if (!btn.contains(e.target) && !datePicker.contains(e.target)) { datePicker.style.display = 'none'; } }); } // 启动脚本 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();