UNPKG

rsshub

Version:
106 lines (105 loc) 4.75 kB
import { t as rofetch } from "./ofetch-U0CdpE2g.mjs"; import { t as cache_default } from "./cache-C1Y-9qDV.mjs"; import { a as ridershipItem, i as parsePct, n as parseCount, r as parseFiscalYear, t as cellText } from "./utils-D861Zsp_.mjs"; import { load } from "cheerio"; //#region lib/routes/tokyu/ridership.ts const BASE = "https://www.tokyu.co.jp/railway/company/business/passengers/"; const OPERATOR = "東急電鉄"; /** * 駅別乗降人員・輸送人員 — the index lists one page per fiscal year (`2014/` … `2025/`). * A year page has one `table.table` per line, preceded by `.portal-heading h2` (line name): * 駅名\種別 | 定期(人) | 定期外(人) | 計(人) | 前年比(%) | <previous year>年度 * Columns are located by header text. 世田谷線 only has a 全線 row (no per-station figures), which is skipped. */ const parsePage = (html, link) => { const $ = load(html); const fiscalYear = parseFiscalYear($("title").text()); if (fiscalYear === null) throw new Error("tokyu: fiscal year not found in the page title"); return { fiscalYear, items: $("table.table").toArray().flatMap((table) => { const line = cellText($(table).closest(".portal-table").prevAll(".portal-heading").first().find("h2").text()) || null; const headers = $(table).find("thead th").toArray().map((th) => cellText($(th).text())); const col = (re) => headers.findIndex((h) => re.test(h)); const [iCommuter, iOther, iTotal, iYoy, iPrev] = [ /^定期\(/, /^定期外/, /^計/, /^前年比/, /年度$/ ].map(col); if (iTotal < 0) return []; return $(table).find("tbody tr").toArray().map((tr) => { const station = cellText($(tr).find("th").first().text()); const tds = $(tr).find("td").toArray().map((td) => cellText($(td).text())); const at = (i) => i > 0 ? tds[i - 1] ?? "" : ""; if (station === "" || station === "全線") return null; const raw = { station, commuter_pass: at(iCommuter), non_commuter: at(iOther), total: at(iTotal), yoy: at(iYoy), [headers[iPrev] ?? "previous_year"]: at(iPrev) }; const extra = { source: "tokyu", operator: OPERATOR, station, line, fiscal_year: fiscalYear, daily_average: parseCount(raw.total), unit: "人/日", rank: null, yoy_pct: parsePct(raw.yoy), raw }; return ridershipItem(extra, link); }).filter((item) => item !== null); }) }; }; /** Latest year = the largest `passengers/<year>/` link on the index page. */ const latestYear = async () => { const html = await rofetch(BASE); const $ = load(html); const years = $("a[href*=\"/passengers/\"]").toArray().map((a) => Number(($(a).attr("href") ?? "").match(/\/passengers\/(\d{4})\/?$/)?.[1])).filter((y) => Number.isSafeInteger(y)); if (years.length === 0) throw new Error("tokyu: no fiscal-year pages linked from the index"); return Math.max(...years); }; const handler = async (ctx) => { const year = ctx.req.param("year"); const fy = year === void 0 ? await cache_default.tryGet("tokyu/ridership:latest", latestYear) : Number(year); if (!Number.isSafeInteger(fy)) throw new TypeError(`tokyu: invalid year "${year}"`); const link = `${BASE}${fy}/`; const page = await cache_default.tryGet(link, async () => parsePage(await rofetch(link), link)); return { title: `東急電鉄 ${page.fiscalYear}年度 駅別乗降人員`, link, language: "ja", item: page.items }; }; const route = { path: "/ridership/:year?", name: "駅別乗降人員", url: "www.tokyu.co.jp", maintainers: ["pseudoyu"], handler, example: "/tokyu/ridership", parameters: { year: { description: "Fiscal year (`2014` … latest); omit for the latest year" } }, description: `Annual 駅別乗降人員 (one-day average) for every Tokyu station, from [駅別乗降人員・輸送人員](${BASE}). One item per station, line and fiscal year (渋谷, 日吉, 蒲田 … appear once per line, as on the page); \`_extra\` carries \`operator\`, \`station\`, \`line\`, \`fiscal_year\`, \`daily_average\` (計, 人/日), \`yoy_pct\` and the page's cell text in \`raw\` (定期 / 定期外 / 計 / 前年比 / previous-year figure). \`rank\` is \`null\` because the operator publishes no ranking. 世田谷線 is published as a single 全線 figure and is not included. The operator does not publish a release date, so items have no \`pubDate\`.`, categories: ["other"], features: { requireConfig: false, requirePuppeteer: false, antiCrawler: false, supportRadar: true }, radar: [{ source: ["www.tokyu.co.jp/railway/company/business/passengers/:year", "www.tokyu.co.jp/railway/company/business/passengers/"], target: "/ridership/:year" }] }; //#endregion export { handler, route };