匹配范围
*://weixin.sogou.com/*weixin-article-search用途 通过搜狗微信搜索公开微信文章,返回文章标题、链接、摘要和发布时间。适合在浏览器环境中做轻量检索,不抓取正文。 执行前提 需要浏览器能访问 https://weixin.sogou.com/。搜狗微信可能因访问频率、地区、Cookie 状态或风控策略要求验证码;出现验证码或安全验证时,脚本会报错并提示先在浏览器页面完成人机验证后重试。 参数 query…
*://weixin.sogou.com/*dom.read1return await (async () => {2 const input = typeof params === "object" && params ? params : {};3 const query = String(input.query || "").trim();4 if (!query) {5 throw new Error("缺少参数 query:请输入要搜索的微信文章关键词。");6 }7 8 const toPositiveInteger = (value, fallback, max) => {9 if (value === undefined || value === null || value === "") return fallback;10 const text = String(value).trim();11 if (!/^\d+$/.test(text)) {12 throw new Error(`参数必须是正整数:${text}`);13 }14 const parsed = Number(text);15 if (!Number.isSafeInteger(parsed) || parsed < 1 || (max && parsed > max)) {16 throw new Error(`参数超出范围:${text}`);17 }18 return parsed;19 };20 21 const page = toPositiveInteger(input.page, 1, 100);22 const limit = toPositiveInteger(input.limit, 10, 10);23 const clean = (value) =>24 String(value || "")25 .replace(/\s+/g, " ")26 .replace(/<!--red_beg-->|<!--red_end-->/g, "")27 .replace(/document\.write\(timeConvert\('\d+'\)\)/g, "")28 .trim();29 const absolutize = (href, base) => {30 if (!href) return "";31 try {32 return new URL(href, base).toString();33 } catch {34 return String(href || "");35 }36 };37 38 const searchUrl = new URL("https://weixin.sogou.com/weixin");39 searchUrl.searchParams.set("query", query);40 searchUrl.searchParams.set("type", "2");41 searchUrl.searchParams.set("page", String(page));42 searchUrl.searchParams.set("ie", "utf8");43 44 const response = await fetch(searchUrl.toString(), {45 method: "GET",46 credentials: "include",47 headers: {48 Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",49 },50 });51 if (!response.ok) {52 throw new Error(`搜狗微信搜索请求失败:HTTP ${response.status}。可能是访问频率过高、验证码或站点策略变化。`);53 }54 55 const html = await response.text();56 const doc = new DOMParser().parseFromString(html, "text/html");57 const bodyText = clean(doc.body && doc.body.innerText);58 if (/验证码|安全验证|异常访问|访问过于频繁|请输入验证码/.test(bodyText)) {59 throw new Error("搜狗微信要求验证码或安全验证。请在浏览器打开 weixin.sogou.com 完成人机验证后重试。");60 }61 62 const cards = Array.from(doc.querySelectorAll(".news-list li"));63 const extracted = cards.map((item) => {64 const linkEl = item.querySelector("h3 a[href]");65 const summaryEl = item.querySelector("p.txt-info");66 const timeEl = item.querySelector(".s-p .s2");67 return {68 title: clean(linkEl && linkEl.textContent),69 url: absolutize(linkEl && linkEl.getAttribute("href"), searchUrl.toString()),70 summary: clean(summaryEl && summaryEl.textContent),71 publish_time: clean(timeEl && timeEl.textContent),72 };73 });74 const rows = extracted.filter((row) => row.title && row.url);75 const empty =76 /没有找到相关的微信文章|未找到相关|暂无相关|没有找到/.test(bodyText) ||77 Boolean(doc.querySelector(".no-result, .no_result, .s-noresult"));78 79 if (extracted.length !== rows.length) {80 throw new Error("搜狗微信返回了缺少标题或链接的结果卡片,页面结构可能已变化,已拒绝返回不完整结果。");81 }82 if (rows.length === 0 && empty) {83 return [];84 }85 if (rows.length === 0) {86 throw new Error("未能识别搜狗微信文章结果。可能是页面结构、验证码或接口策略发生变化。");87 }88 89 return rows.slice(0, limit).map((row, index) => ({90 rank: (page - 1) * 10 + index + 1,91 page,92 title: row.title,93 url: row.url,94 summary: row.summary,95 publish_time: row.publish_time,96 }));97})();