繁体   English   中英

Google Apps 脚本在后端工作,但不在工作表上

[英]Google Apps Script Working on backend but not on sheets

我正在尝试创建一个从硬币市值 API 中提取并显示当前价格的脚本。 当我为变量赋值时,脚本在后端运行良好。 但是,当我尝试在工作表上运行 function 时,返回的值为 null。

function marketview(ticker) {
  var url = "https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest?CMC_PRO_API_KEY=XXX&symbol=" + ticker;
  var data = UrlFetchApp.fetch(url);
  const jsondata = JSON.parse(data);

  Logger.log(jsondata.data[ticker].quote['USD'].price)
  
}

我的执行日志显示脚本正在运行,但是当我使用 function 并尝试引用 ETH 时,脚本正在为 BTC 运行。

当我在后端执行此操作并分配 ETH 时,脚本可以正常工作并返回正确的报价。 关于我所缺少的任何想法?

我对 coingecko API 做了同样的事情,并添加了一个问题,即我的所有请求都因配额超出错误而被拒绝。

我知道 Google 表格服务器的 IP 地址已经在向 coingecko 服务器发送垃圾邮件。 (我显然不是唯一一个尝试这个的人)。

这就是为什么我使用像 apify.com 这样的外部服务来提取数据并在其 API 上重新公开数据。

这是我的 AppScripts coingecko.gs

/**
 * get latest coingecko market prices dataset
 */
async function GET_COINGECKO_PRICES(key, actor) {
  const coinGeckoUrl = `https://api.apify.com/v2/acts/${actor}/runs/last/dataset/items?token=${key}&status=SUCCEEDED`
  return ImportJSON(coinGeckoUrl);
}

您需要ImportJSON function,可在此处获得: https://github.com/bradjasper/ImportJSON/blob/master/ImportJSON.gs

然后在我写的单元格中: =GET_COINGECKO_PRICES(APIFY_API_KEY,APIFY_COINGECKO_MARKET_PRICES) ,您必须创建两个名为APIFY_API_KEYAPIFY_COINGECKO_MARKET_PRICES的字段才能使其正常工作。

然后在 apify.com 上注册,然后你必须通过 fork apify-webscraper actor 创建一个 actor。

我将StartURLs设置为https://api.coingecko.com/api/v3/coins/list ,这将为我提供现有加密的总数(截至今天约为 11000)和页数,以便我可以运行并发请求(在 coingecko 上的速率限制是 10 个并发请求),然后我只需将/list替换为/market并设置适当的限制以获取我需要的所有页面。

我对任务页面 function 使用以下内容:

async function pageFunction(context) {
    let marketPrices = [];
    const ENABLE_CONCURRENCY_BATCH = true;
    const PRICE_CHANGE_PERCENTAGE = ['1h', '24h', '7d'];
    const MAX_PAGE_TO_SCRAP = 10;
    const MAX_PER_PAGE = 250;
    const MAX_CONCURRENCY_BATCH_LIMIT = 10;
    await context.WaitFor(5000);
    const cryptoList = readJson();
    const totalPage = Math.ceil(cryptoList.length / MAX_PER_PAGE);

    context.log.info(`[Coingecko total cryptos count: ${cryptoList.length} (${totalPage} pages)]`)
    
    function readJson() {
        try {
            const preEl = document.querySelector('body > pre');
            return JSON.parse(preEl.innerText);
        } catch (error) {
            throw Error(`Failed to read JSON: ${error.message}`)
        }
    }


    async function loadPage($page) {
        try {
            const params = {
                vs_currency: 'usd',
                page: $page,
                per_page: MAX_PER_PAGE,
                price_change_percentage: PRICE_CHANGE_PERCENTAGE.join(','),
                sparkline: true,
            }
            
            let pageUrl = `${context.request.url.replace(/\/list$/, '/markets')}?`;
            pageUrl += [
                `vs_currency=${params.vs_currency}`,
                `page=${params.page}`,
                `per_page=${params.per_page}`,
                `price_change_percentage=${params.price_change_percentage}`,
            ].join('&');
                        
            context.log.info(`GET page ${params.page} URL: ${pageUrl}`);
            const page = await fetch(pageUrl).then((response) => response.json());
            context.log.info(`Done GET page ${params.page} size ${page.length}`);
            marketPrices = [...marketPrices, ...page];
            return page
        } catch (error) {
            throw Error(`Fail to load page ${$page}: ${error.message}`)
        }
    }

    try {
        if (ENABLE_CONCURRENCY_BATCH) {
            const fetchers = Array.from({ length: totalPage }).map((_, i) => {
                const pageIndex = i + 1;
                if (pageIndex > MAX_PAGE_TO_SCRAP) {
                    return null;
                }
                return () => loadPage(pageIndex);
            }).filter(Boolean);
            while (fetchers.length) {   
                await Promise.all(
                    fetchers.splice(0, MAX_CONCURRENCY_BATCH_LIMIT).map((f) => f())
                );
            }
        } else {
            let pageIndex = 1
            let page = await loadPage(pageIndex)
            while (page.length !== 0 && page <= MAX_PAGE_TO_SCRAP) {
                pageIndex += 1
                page = await loadPage(pageIndex)
            }
        }
    } catch (error) {
        context.log.info(`Fetchers failed: ${error.message}`);
    }

    context.log.info(`End: Updated ${marketPrices.length} prices for ${cryptoList.length} cryptos`);
    const data = marketPrices.sort((a, b) => a.id.toLowerCase() > b.id.toLowerCase() ? 1 : -1);
    context.log.info(JSON.stringify(data.find((item) => item.id.toLowerCase() === 'bitcoin')));

    function sanitizer(item) {
        item.symbol = item.symbol.toUpperCase()
        return item;
    }
    return data.map(sanitizer)
}

我认为您遇到了与 coinmarketcap 相同的问题,并且您可以对它做同样的事情。

您不会将任何内容return到工作表,而只是将其记录下来。 把它返还:

return jsondata.data[ticker].quote['USD'].price

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM