灵猴市集Linghou Market

百度学术论文搜索

百度学术baidu-scholar-search

百度学术搜索结果提取 用途 读取百度学术搜索结果页中已经渲染出的论文条目,返回标题、作者、期刊、年份、被引次数和结果地址。 执行前提 先打开 https://xueshu.baidu.com/s?wd=<query>&pn=0&tn=SEbaiduxueshuc1gjeupa 对应的搜索结果页;页面可能自动跳转到新版 https://xueshu.baid…

搜索论文内容提取
版本1.0.0
扫描passed
更新2026-06-28
超时30000ms

匹配范围

*://xueshu.baidu.com/*

排除范围

未声明

能力声明

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 requiredQuery() {13  const value = rawParams.query === undefined || rawParams.query === null ? "" : String(rawParams.query).trim();14  if (!value) throw new Error("query is required");15  return value;16}17 18function sleep(ms) {19  return new Promise(resolve => setTimeout(resolve, ms));20}21 22function normalizeText(value) {23  return (value || "").replace(/\s+/g, " ").trim();24}25 26function expectedSearchUrl(query) {27  return `https://xueshu.baidu.com/s?wd=${encodeURIComponent(query)}&pn=0&tn=SE_baiduxueshu_c1gjeupa`;28}29 30function sameQuery(left, right) {31  return normalizeText(left).toLowerCase() === normalizeText(right).toLowerCase();32}33 34function assertCurrentSearchPage(query) {35  const current = new URL(location.href);36  const target = expectedSearchUrl(query);37  const allowedPaths = new Set(["/s", "/ndscholar/browse/search"]);38  if (current.hostname !== "xueshu.baidu.com" || !allowedPaths.has(current.pathname)) {39    throw new Error(`Open ${target} first, then run this script`);40  }41  const pageQuery = current.searchParams.get("wd") || "";42  if (!pageQuery || !sameQuery(pageQuery, query)) {43    throw new Error(`Open ${target} first, then run this script`);44  }45}46 47function detectBlockedPage(doc) {48  const text = normalizeText(`${doc.title || ""} ${doc.body ? doc.body.innerText : ""}`).slice(0, 5000);49  if (/百度安全验证|安全验证|验证码|人机验证|访问异常|页面加载失败|请输入验证码/.test(text)) {50    return "The page is showing a verification or risk-control challenge";51  }52  return "";53}54 55function trustedUrl(raw) {56  if (!raw) return "";57  try {58    const url = new URL(raw, "https://xueshu.baidu.com");59    if (url.protocol !== "http:" && url.protocol !== "https:") return "";60    return url.toString();61  } catch {62    return "";63  }64}65 66function parseScholarRow(el, rank) {67  const titleEl =68    el.querySelector("a.atomic-line-clamp-3[href]") ||69    el.querySelector("a[href*='/paper/show']") ||70    el.querySelector("h3 a") ||71    el.querySelector(".paper-title a") ||72    el.querySelector(".t a") ||73    el.querySelector("a[href]");74  const title = normalizeText(titleEl ? titleEl.textContent : "");75  if (!title) return null;76 77  const infoEl =78    el.querySelector(".paper-info") ||79    el.querySelector(".sc_info") ||80    el.querySelector(".res_info") ||81    el.querySelector(".info");82  const infoText = normalizeText(infoEl ? infoEl.textContent : el.textContent);83  const spans = infoEl ? Array.from(infoEl.querySelectorAll("span")) : [];84  const authorParts = [];85  const authorSeen = new Set();86  let journal = "";87  let year = "";88  let cited = null;89 90  function pushAuthorToken(value) {91    const text = normalizeText(value).replace(/[,,、]+$/g, "").trim();92    if (!text || text.length < 2) return;93    if (/^(期刊|会议|学位|图书|专利|来源|百度文库|万方|维普|掌桥科研|收藏|引用|免费下载|论文图谱|AI问答)$/.test(text)) return;94    if (/出版社$/.test(text)) return;95    if (/(\.\.\.|…)/.test(text)) return;96    if (/^[·,,。\-—…\s]+$/.test(text)) return;97    if (authorSeen.has(text)) return;98    authorSeen.add(text);99    authorParts.push(text);100  }101 102  for (const span of spans) {103    const text = normalizeText(span.textContent);104    if (!text || text === "," || text === "," || text === "-" || text === "期刊" || text === "会议" || text === "学位") continue;105    if (!journal && /^[《〈].+[》〉]$/.test(text)) {106      journal = text.replace(/[《》〈〉]/g, "");107      continue;108    }109    if (/被引/.test(text)) {110      const match = text.match(/(\d+)/);111      cited = match ? Number(match[1]) : cited;112      continue;113    }114    if (/(19|20)\d{2}/.test(text)) {115      const match = text.match(/(19|20)\d{2}/);116      year = match ? match[0] : year;117      continue;118    }119    if (!/^[-–—]/.test(text) && !/摘要|关键词|来源/.test(text)) {120      pushAuthorToken(text);121    }122  }123 124  if (!journal) {125    const journalMatch = infoText.match(/[《〈]([^《》〈〉]{2,80})[》〉]/);126    journal = journalMatch ? normalizeText(journalMatch[1]) : "";127  }128  if (!year) {129    const yearMatch = infoText.match(/(19|20)\d{2}/);130    year = yearMatch ? yearMatch[0] : "";131  }132  if (cited === null) {133    const citedMatch = infoText.match(/被引(?:量)?[::\s]*(\d+)/);134    cited = citedMatch ? Number(citedMatch[1]) : null;135  }136 137  return {138    rank,139    title,140    authors: authorParts.join(", ").slice(0, 120),141    journal,142    year,143    cited,144    url: trustedUrl(titleEl ? titleEl.getAttribute("href") || titleEl.href : ""),145  };146}147 148function extractResults(doc, limit) {149  const rows = [];150  const seen = new Set();151  const candidates = Array.from(doc.querySelectorAll(".result, .result-op"));152 153  for (const el of candidates) {154    if (rows.length >= limit) break;155    const row = parseScholarRow(el, rows.length + 1);156    if (!row) continue;157    const key = `${row.title}\n${row.url}`;158    if (seen.has(key)) continue;159    seen.add(key);160    rows.push(row);161  }162 163  return rows;164}165 166async function waitForResults(doc, limit) {167  const deadline = Date.now() + 8000;168  let results = extractResults(doc, limit);169  while (Date.now() < deadline && results.length === 0) {170    const blocked = detectBlockedPage(doc);171    if (blocked) throw new Error(`${blocked}; complete it in the browser and run again`);172    await sleep(250);173    results = extractResults(doc, limit);174  }175  return results;176}177 178const query = requiredQuery();179const limit = integerParam("limit", 10, 1, 20);180assertCurrentSearchPage(query);181 182const blocked = detectBlockedPage(document);183if (blocked) throw new Error(`${blocked}; complete it in the browser and run again`);184 185const items = await waitForResults(document, limit);186if (items.length === 0) {187  throw new Error(`No Baidu Scholar results found for "${query}"; the page may be empty, blocked, or its structure changed`);188}189 190return items.slice(0, limit);