灵猴市集Linghou Market

汽车之家车系口碑评分

汽车之家autohome-series-score

用途 读取汽车之家车系口碑页公开数据,返回指定车系的口碑评分、百车故障数、品牌、车系名、维度评分和车主印象。 执行前提 先打开对应车系的汽车之家口碑页,例如 https://k.autohome.com.cn/7538。脚本优先读取当前页面的 #_NEXTDATA__,当前页面不是目标车系时会尝试请求 https://k.autohome.com.cn/<…

汽车车系口碑评分
版本1.0.0
扫描passed
更新2026-06-28
超时30000ms

匹配范围

*://*.autohome.com.cn/*

排除范围

未声明

能力声明

dom.read

代码

源码已展开
1return await (async () => {2  const input = typeof params === "object" && params !== null ? params : {};3  const seriesId = String(input.seriesId || "").trim();4 5  if (!/^\d+$/.test(seriesId)) {6    throw new Error("params.seriesId is required and must contain digits only.");7  }8 9  const cleanText = (value) =>10    String(value || "")11      .replace(/\s+/g, " ")12      .replace(/\u00a0/g, " ")13      .trim();14 15  const toNumber = (value) => {16    if (value === null || value === undefined || value === "") return null;17    const number = Number(String(value).replace(/[^\d.-]/g, ""));18    return Number.isFinite(number) ? number : null;19  };20 21  const firstDefined = (...values) => values.find((value) => value !== undefined && value !== null && value !== "");22 23  const walkObjects = (root, visit, seen = new Set()) => {24    if (!root || typeof root !== "object" || seen.has(root)) return;25    seen.add(root);26    visit(root);27 28    if (Array.isArray(root)) {29      for (const item of root) walkObjects(item, visit, seen);30      return;31    }32 33    for (const value of Object.values(root)) {34      walkObjects(value, visit, seen);35    }36  };37 38  const parseNextData = (doc) => {39    const node = doc.querySelector("#__NEXT_DATA__");40    if (!node || !node.textContent.trim()) return null;41    return JSON.parse(node.textContent);42  };43 44  const getDocumentForSeries = async () => {45    const currentMatch = window.location.hostname === "k.autohome.com.cn" && window.location.pathname.includes(seriesId);46    if (currentMatch) return document;47 48    const response = await fetch(`https://k.autohome.com.cn/${seriesId}`, {49      credentials: "include",50    });51 52    if (!response.ok) {53      throw new Error(`Failed to fetch score page for series ${seriesId}: HTTP ${response.status}.`);54    }55 56    const html = await response.text();57    return new DOMParser().parseFromString(html, "text/html");58  };59 60  const doc = await getDocumentForSeries();61  const nextData = parseNextData(doc);62 63  let seriesData = null;64  let qualityData = null;65  let scoreList = [];66 67  if (nextData) {68    const candidates = [];69    walkObjects(nextData, (item) => candidates.push(item));70 71    seriesData =72      candidates.find(73        (item) =>74          String(firstDefined(item.seriesid, item.seriesId, item.seriesID)) === seriesId &&75          firstDefined(item.seriesname, item.seriesName, item.average, item.seriesAverage)76      ) || null;77 78    qualityData =79      candidates.find(80        (item) =>81          String(firstDefined(item.seriesId, item.seriesid, item.seriesID)) === seriesId &&82          firstDefined(item.pph, item.newCarPPH, item.userCount)83      ) || null;84 85    const scoreOwner = candidates.find((item) => Array.isArray(item.seriesScoreList));86    scoreList = Array.isArray(scoreOwner?.seriesScoreList) ? scoreOwner.seriesScoreList : [];87  }88 89  const titleText = cleanText(doc.querySelector("title")?.textContent);90  const headingText = cleanText(doc.querySelector("h1")?.textContent);91  const toolbarText = cleanText(doc.querySelector("[class*='toolbar'] a[href*='autohome.com.cn']")?.textContent);92  const brandFromToolbar = toolbarText.includes("-") ? cleanText(toolbarText.split("-")[0]) : null;93  const scoreText = cleanText(doc.body?.textContent);94  const scoreMatch = scoreText.match(/口碑评分\s*(\d+(?:\.\d+)?)/);95  const pphMatch = scoreText.match(/百车故障数\s*(\d+)/);96 97  const dimensions = scoreList.map((item) => ({98    name: cleanText(firstDefined(item.typeName, item.name)),99    score: toNumber(firstDefined(item.score, item.value)),100    rank: toNumber(item.rank),101  }));102 103  const impressions = Array.from(doc.querySelectorAll("[class*='score_tag'] li"))104    .map((item) => cleanText(item.textContent))105    .filter(Boolean)106    .map((text) => {107      const match = text.match(/^(.*?)(\d+)$/);108      return {109        text: cleanText(match ? match[1] : text),110        count: match ? toNumber(match[2]) : null,111      };112    });113 114  return {115    seriesId,116    seriesName: cleanText(firstDefined(seriesData?.seriesname, seriesData?.seriesName, headingText)) || null,117    brandName: cleanText(firstDefined(seriesData?.brandName, seriesData?.brandname, brandFromToolbar)) || null,118    overallScore: toNumber(firstDefined(seriesData?.average, seriesData?.seriesAverage, scoreMatch?.[1])),119    pph: toNumber(firstDefined(seriesData?.newCarPPH, qualityData?.pph, pphMatch?.[1])),120    reviewCount: toNumber(firstDefined(seriesData?.averagenum, seriesData?.rowcount, qualityData?.userCount)),121    priceRange: cleanText(firstDefined(seriesData?.pricerange, seriesData?.priceRange)) || null,122    levelName: cleanText(firstDefined(seriesData?.levelname, seriesData?.levelName)) || null,123    dimensions,124    impressions,125    pageTitle: titleText || null,126    sourceUrl: doc === document ? window.location.href : `https://k.autohome.com.cn/${seriesId}`,127  };128})();