Would you like to clone this notebook?

When you clone a notebook you are able to make changes without affecting the original notebook.

Cancel

mf

node v14.20.1
version: 5.0.0
endpointsharetweet
const express = require("@runkit/runkit/express-endpoint/1.0.0"); const got = require('got'); const app = express(exports); const LruCache = require("lru-cache"); const isPromise = require('is-promise'); const humanizeMs = require('humanize-ms'); const assert = require('assert'); const cheerio = require('cheerio'); /* Declare Cache module */ class Cache { constructor({ maxAge }) { this.lruCache = new LruCache({ maxAge, }); } wrap(key, cb) { const cache = this.lruCache; if(cache.has(key)) { /* do nothing */ } else { const result = cb(key); cache.set(key, result); if(isPromise(result)) { result .then(resolvedValue => cache.set(key, resolvedValue)) .catch(() => cache.del(key)); } } return cache.get(key); } } /* Constants */ const ValueResearchHost = 'https://www.valueresearchonline.com/'; const OneHourMs = humanizeMs('12 hour'); const BlankValue = '--'; const NotFound = 'NA'; const Error = 'ERR'; const Fields = { returns: 'Return Since Launch:', launchDate: 'Launch Date:', aum: 'Assets:', expenseRatio: 'Expense:', minLumpSumInv: 'Minimum Investment (₹)', minSIPInv: 'Minimum SIP Investment (₹)', alpha: 'Alpha', beta: 'Beta', sharpe: 'Sharpe', }; /** css attributes */ const InvestmentDetailsTable = '#basic-investment-table1'; const BasicDetailsTable = '#basic-investment-table'; const RiskMeasuresTable = '#risk-measures-table'; const FundSlug = '#fund_slug'; const FundId = '#fund_id'; const HoldingDate = '#holding_date'; /** Date formats */ const AppDateFormat = 'DD-MMM-YYYY'; const HoldingDateFormat = 'YYYY-MM-DD'; const cache = new Cache({ maxAge: OneHourMs, }); /* fetch and parse html page */ const fetchHtmlPage = (url) => cache.wrap(url, async key => { const body = await got(key, { prefixUrl: ValueResearchHost, resolveBodyOnly: true, }); const $ = cheerio.load(body); /* assertions */ assert($(FundSlug), 'Fund slug missing'); assert($(FundId), 'Fund id missing'); assert($(InvestmentDetailsTable), 'Investment table missing'); assert($(BasicDetailsTable), 'Basic details table missing'); assert($(RiskMeasuresTable), 'Risk measure table missing'); return $; }); /* fetch details service methods */ const trim = str => ( str .trim() .replace(/\s/g, ' ') ); const compare = (a, b) => trim(a) === trim(b); const fetchDetailsValue = async ({ id, slug, field }) => { try { const $ = await fetchHtmlPage(`funds/${id}/${slug}`); const tableDataList = $(`${InvestmentDetailsTable} td, ${BasicDetailsTable} td`); const textList = [...tableDataList] .map(data => trim($(data).text())); const index = textList .findIndex(text => compare(text, field)); return index === -1 ? NotFound : textList[index + 1]; } catch(ex) { console.log(ex); return Error; } }; const fetchRiskMeasure = async ({ id, slug, field }) => { try { const $ = await fetchHtmlPage(`funds/${id}/${slug}`); const [tableHeader, ...tableRows] = $(`${RiskMeasuresTable} tr`); const headerIndex = [...$('th', tableHeader)] .map(header => trim($(header).text())) .findIndex(innerText => compare(innerText, field)) const rowIndex = tableRows .map(row => trim($('td:eq(0)', row).text())) .findIndex(f => compare(f, 'Fund')); if(headerIndex === -1 || rowIndex === -1) return NotFound; const riskMeasure = trim( $(`td:eq(${headerIndex})`, tableRows[rowIndex]).text() ); return riskMeasure === BlankValue ? NotFound : riskMeasure; } catch(ex) { return Error; } }; const fetchAsOnDate = async ({ id, slug }) => { try { const $ = await fetchHtmlPage(`funds/${id}/${slug}`); const holdingDate = $(HoldingDate); return dayjs(holdingDate, HoldingDateFormat).format(AppDateFormat); } catch(ex) { console.log(ex); return Error } }; /* * End points */ app.get("/alpha/:id/:slug", async (req, res) => { const { id, slug } = req.params; console.log(id, slug); const result = await fetchDetailsValue({ id, slug, field: Fields.launchDate, }); res.send(result); });
Loading…

no comments

    sign in to comment