1

我正在尝试创建一个从硬币市值 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 时,脚本可以正常工作并返回正确的报价。关于我所缺少的任何想法?

4

2 回答 2

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_KEYandAPIFY_COINGECKO_MARKET_PRICES的字段才能使其正常工作。

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

我设置了StartURLswith https://api.coingecko.com/api/v3/coins/list,这将给我现有加密的总数(截至今天大约 11000 个)和页数,以便我可以同时运行请求(速率限制是 coingecko 上的 10 个并发请求),然后我只需替换/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 相同的问题,并且您可以对它做同样的事情。

于 2021-11-28T15:11:37.450 回答
0

您没有return在工作表中添加任何内容,而只是将其记录下来。把它返还:

return jsondata.data[ticker].quote['USD'].price
于 2021-11-28T15:48:50.130 回答