灵猴市集Linghou Market

36氪文章搜索

36氪36kr-search-news

36氪文章搜索结果提取 用途 读取 36氪文章搜索结果页中已经渲染出的文章,返回排名、标题、页面附近日期和文章地址。 执行前提 先打开 https://www.36kr.com/search/articles/<keyword> 对应的搜索结果页,再用同一个 keyword 参数执行。页面公开可访问,但结果依赖客户端渲染,若页面显示验证、空结果或加载失败,…

新闻创投搜索
版本1.0.0
扫描passed
更新2026-06-28
超时30000ms

匹配范围

*://*.36kr.com/search/articles/*

排除范围

未声明

能力声明

dom.read

代码

源码已展开
1const rawParams = params && typeof params === "object" ? params : {};2 3function integerParam(name, fallback, min, max) {4  const raw = rawParams[name];5  const value = raw === undefined || raw === null || raw === "" ? fallback : Number(raw);6  if (!Number.isInteger(value) || value < min || value > max) {7    throw new Error(`${name} must be an integer between ${min} and ${max}`);8  }9  return value;10}11 12function requiredKeyword() {13  const raw = rawParams.keyword ?? rawParams.query;14  const keyword = raw === undefined || raw === null ? "" : String(raw).trim();15  if (!keyword) throw new Error("keyword is required");16  return keyword;17}18 19function sleep(ms) {20  return new Promise(resolve => setTimeout(resolve, ms));21}22 23function normalizeText(value) {24  return (value || "").replace(/\s+/g, " ").trim();25}26 27function normalizeArticleUrl(href) {28  if (!href) return "";29  try {30    const url = new URL(href, "https://36kr.com");31    if (!/(\.|^)36kr\.com$/.test(url.hostname)) return "";32    if (!/\/p\/\d+/.test(url.pathname)) return "";33    return url.toString();34  } catch {35    return "";36  }37}38 39function extractDate(text) {40  const normalized = normalizeText(text);41  const match =42    normalized.match(/\d{4}[-/.]\d{1,2}[-/.]\d{1,2}(?:\s+\d{1,2}:\d{2})?/) ||43    normalized.match(/\d{1,2}月\d{1,2}日(?:\s+\d{1,2}:\d{2})?/) ||44    normalized.match(/\d{1,2}:\d{2}/);45  return match ? match[0] : "";46}47 48function extractItems(doc) {49  const seen = new Set();50  const results = [];51  const preferredLinks = doc.querySelectorAll(52    ".article-item-title a[href*='/p/'], .article-item-title[href*='/p/'], .article-item-title a[href*=\"/p/\"], .article-item-title[href*=\"/p/\"]",53  );54  const links = preferredLinks.length > 055    ? preferredLinks56    : doc.querySelectorAll("a[href*='/p/'], a[href*=\"/p/\"]");57 58  for (const link of links) {59    const title = normalizeText(link.getAttribute("title") || link.textContent);60    const url = normalizeArticleUrl(link.getAttribute("href") || link.href || "");61    if (!title || title.length < 5 || !url) continue;62    const key = `${title}\n${url}`;63    if (seen.has(key) || seen.has(url) || seen.has(title)) continue;64    seen.add(key);65    seen.add(url);66    seen.add(title);67 68    const item = link.closest("[class*='article-item'], article, li, section") || link.parentElement;69    const dateNode = item?.querySelector("[class*='time'], [class*='date'], time");70    const date = normalizeText(dateNode?.textContent || "") || extractDate(item?.textContent || "");71    results.push({ title, date, url });72  }73 74  return results;75}76 77async function waitForItems(doc, timeoutMs) {78  const deadline = Date.now() + timeoutMs;79  let items = extractItems(doc);80  while (Date.now() < deadline && items.length === 0) {81    await sleep(250);82    items = extractItems(doc);83  }84  return items;85}86 87function assertCurrentPage(targetUrl) {88  const current = new URL(location.href);89  const target = new URL(targetUrl);90  if (current.origin !== target.origin || current.pathname !== target.pathname) {91    throw new Error(`Open ${targetUrl} first, then run this script`);92  }93}94 95const keyword = requiredKeyword();96const limit = integerParam("limit", 20, 1, 50);97const timeoutMs = integerParam("timeoutMs", 8000, 1000, 30000);98const targetUrl = `https://www.36kr.com/search/articles/${encodeURIComponent(keyword)}`;99assertCurrentPage(targetUrl);100 101const items = await waitForItems(document, timeoutMs);102 103if (items.length === 0) {104  throw new Error(`No search results found on ${targetUrl}`);105}106 107return items.slice(0, limit).map((item, index) => ({108  rank: index + 1,109  title: item.title,110  date: item.date,111  url: item.url,112}));