【问题标题】:Google Apps Script Working on backend but not on sheetsGoogle Apps 脚本在后端工作,但不在工作表上
【发布时间】:2021-11-28 15:05:59
【问题描述】:

我正在尝试创建一个从硬币市值 API 中提取并显示当前价格的脚本。当我为变量赋值时,脚本在后端运行良好。但是,当我尝试在工作表上运行该函数时,返回值为 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)
  
}

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

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

【问题讨论】:

    标签: javascript google-apps-script custom-function coinmarketcap


    【解决方案1】:

    我对 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 功能,可在此处获得: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)和页数,以便我可以同时运行请求(速率限制为 10 个并发请求在 coingecko 上),然后我只需将 /list 替换为 /market 并设置适当的限制以获取我需要的所有页面。

    我将以下内容用于任务页面功能:

    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 相同的问题,并且您可以对它做同样的事情。

    【讨论】:

    • 这很完美,起初我使用 coin gecko 编写脚本,但在 API 请求中遇到了这个问题,所以我切换到 coin base,但现在在 Coin Base 上遇到了这个问题。我会在 Coin Gecko 上试一试。谢谢!
    • 我可以分享动作和任务,可以在apify上分享。如果它回答了问题,您可以接受它作为答案。
    【解决方案2】:

    你不是return 向工作表添加任何内容,而只是记录它。归还:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-10
      • 1970-01-01
      • 1970-01-01
      • 2020-12-15
      • 2021-06-13
      • 2015-05-13
      • 1970-01-01
      相关资源
      最近更新 更多