如何用AppScript带Cookie从动态接口取数据到Google Sheets并持久化
解决Google Script循环获取分页交易数据并写入Sheet的问题
问题背景
作为新手开发者,我用Google Script从网站接口获取交易数据,但现有代码只能单次请求。接口URL末尾的数字串(如示例中的63549969)每次请求都会变化——它是上一次请求返回数据最后一条的id,网站前端通过循环调用loadMoreTrades加载全部数据,现在需要实现自动获取完整交易数据并持久化到Google Sheets指定工作表。
现有单次请求代码:
function testFunction() { var url = 'https://trader.xxx.app/api/data/trade/20058760/63549969'; var map = { "cookie": ".AspNetCore.Antiforgery.DvnwCO4RNgs=CfDJ8Lq5zSRi6AVFv2yxRTgHigNGdKZPKdG-c7U33EUIYc-90Mb0y3YYAH7ntiRp9hRygngVce88wIsQq3XSCgA7DYPWxVPKSHZLxKx6Q6R3Q826ulDmwvsoX_N7pESn3TFRWe2_u0Krl0c74_Z4UIeiOWc; .AspNetCore.Cookies=CfDJ8Lq5zSRi6AVFv2yxRTgHigNoZOuFxznxPef2Z2wMA5vKVkuq3rGG6mcmbvh77X3As3at5-Piq3tl79DuzF78LOfEaROXbojr_QJ0n3781h9ohTC_dvVMxfUupSmIAuJCVGP5g56ix_1U1PaWNn7Tj2GYZuVuQ6__xbfIsC58y0aJ8DqLYU9EU62bOVGGIts6Cic-pEfnaNLomkPj-J3qsAvZHliSXt3f2n5JLr4CoYS1FYg9vGYpw7upXyY9FgBC6bXdtjEqIISnirLa3ird1OXeAK7fO9Onk8r2EonGXK1FgDcHMkb0bE4ZtAWzkKvMQGZq07y0iVZL4VFCHuLEAPZ0-ccndGZVvvneUsejS-iT" } var options = { "method": "get", "muteHttpExceptions": false, "headers": map }; var response = UrlFetchApp.fetch(url, options); Logger.log(response); var json = JSON.parse(response.getContentText()); //Logger.log(json); // Use Spreadsheet var ss = SpreadsheetApp.getActiveSpreadsheet(); var balancesSheet = ss.getSheetByName("test"); var values = json.map(({ id, ticket, side, openTime, closeTime, symbol, lots, profit }) => [id, ticket, side, openTime, closeTime, symbol, lots, profit]); Logger.log(values) balancesSheet.getRange(balancesSheet.getLastRow(), 1, values.length, values[0].length).setValues(values); }
网站前端加载数据的核心逻辑:
function loadMoreTrades() { $.get("/api/data/trade/20058760/"+tradeId, function(data, status){ if(data.length==0){ $('#btnMore').css('display','none'); } else { for(i=0; i<data.length;i++){ tradeId = data[i].id; $('#tradeList > tbody:last-child').append(`<tr> <td>${data[i].ticket}</td> <td>${data[i].side}</td> <td>${data[i].openTime}</td> <td>${data[i].closeTime}</td> <td>${data[i].symbol}</td> <td>${data[i].lots}</td> <td>${data[i].profit}</td> </tr>`); } numLoadedTrades += data.length; if (numLoadedTrades == 248) { $('#btnMore').css('display', 'none'); } } }); }
解决方案代码
function fetchAllTrades() { // 基础URL,替换固定用户ID(20058760)为你的实际ID const baseUrl = 'https://trader.xxx.app/api/data/trade/20058760/'; // 初始请求的ID,第一次请求用你当前的起始ID let currentTradeId = '63549969'; // 请求头,保持你的Cookie const headers = { "cookie": ".AspNetCore.Antiforgery.DvnwCO4RNgs=CfDJ8Lq5zSRi6AVFv2yxRTgHigNGdKZPKdG-c7U33EUIYc-90Mb0y3YYAH7ntiRp9hRygngVce88wIsQq3XSCgA7DYPWxVPKSHZLxKx6Q6R3Q826ulDmwvsoX_N7pESn3TFRWe2_u0Krl0c74_Z4UIeiOWc; .AspNetCore.Cookies=CfDJ8Lq5zSRi6AVFv2yxRTgHigNoZOuFxznxPef2Z2wMA5vKVkuq3rGG6mcmbvh77X3As3at5-Piq3tl79DuzF78LOfEaROXbojr_QJ0n3781h9ohTC_dvVMxfUupSmIAuJCVGP5g56ix_1U1PaWNn7Tj2GYZuVuQ6__xbfIsC58y0aJ8DqLYU9EU62bOVGGIts6Cic-pEfnaNLomkPj-J3qsAvZHliSXt3f2n5JLr4CoYS1FYg9vGYpw7upXyY9FgBC6bXdtjEqIISnirLa3ird1OXeAK7fO9Onk8r2EonGXK1FgDcHMkb0bE4ZtAWzkKvMQGZq07y0iVZL4VFCHuLEAPZ0-ccndGZVvvneUsejS-iT" }; const options = { method: "get", muteHttpExceptions: true, // 开启后避免请求失败直接中断脚本 headers: headers }; let allTrades = []; let hasMoreData = true; while (hasMoreData) { try { const url = baseUrl + currentTradeId; const response = UrlFetchApp.fetch(url, options); const json = JSON.parse(response.getContentText()); if (json.length === 0) { hasMoreData = false; break; } // 合并本次请求的交易数据到总列表 allTrades = allTrades.concat(json); // 更新下一次请求的ID为本次最后一条数据的id currentTradeId = json[json.length - 1].id; // 添加1秒延迟,避免请求过于频繁被网站限流 Utilities.sleep(1000); } catch (error) { Logger.log(`请求出错: ${error.message}`); hasMoreData = false; } } // 写入Google Sheet const ss = SpreadsheetApp.getActiveSpreadsheet(); const balancesSheet = ss.getSheetByName("test"); if (!balancesSheet) { Logger.log("找不到名为'test'的工作表"); return; } // 清空原有数据(如需保留历史数据可注释此行) balancesSheet.clearContents(); // 添加表头 const sheetHeaders = ["ID", "Ticket", "Side", "Open Time", "Close Time", "Symbol", "Lots", "Profit"]; balancesSheet.getRange(1, 1, 1, sheetHeaders.length).setValues([sheetHeaders]); // 转换数据格式为Sheet可接受的二维数组 const values = allTrades.map(({ id, ticket, side, openTime, closeTime, symbol, lots, profit }) => [id, ticket, side, openTime, closeTime, symbol, lots, profit] ); // 批量写入数据 if (values.length > 0) { balancesSheet.getRange(2, 1, values.length, values[0].length).setValues(values); Logger.log(`共写入 ${values.length} 条交易数据`); } else { Logger.log("未获取到任何交易数据"); } }
核心优化点说明
- 循环分页请求:通过
while循环持续请求,直到接口返回空数组,确保获取完整数据 - 动态参数更新:每次请求后自动提取返回数据最后一条的
id,作为下一次请求的URL参数,完全复刻前端逻辑 - 错误防护:开启
muteHttpExceptions并添加try-catch,避免单次请求失败导致脚本终止 - Sheet写入优化:
- 支持清空旧数据后写入完整数据集,或注释清空代码实现增量添加
- 添加表头提升表格可读性
- 批量写入数据,比逐条写入效率更高
- 限流处理:添加1秒延迟,降低被网站拦截的风险
注意事项
- Cookie存在有效期,过期后需要从浏览器重新获取
- 如果交易数据量极大,需注意Google Script最长执行时间限制(6分钟),可考虑拆分请求或分批写入
- 如需增量更新而非全量覆盖,可比对Sheet中已有数据的ID,只写入未存在的记录
内容的提问来源于stack exchange,提问作者Minh Chiến Hoà
相关产品推荐
相关产品推荐

