feat(sitemap): 支持本地 XML 回退(官网 sitemap 受 WAF 保护)+ 记录 5.1-5.3 数据面结果
This commit is contained in:
@@ -33,19 +33,41 @@ function tokensFor(pathPart) {
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
async function fetchSitemap(url) {
|
||||
function parseLocs(xml) {
|
||||
return [...xml.matchAll(/<loc>([^<]+)<\/loc>/g)].map((m) => m[1].trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
// 官网 sitemap 受阿里云 WAF JS 挑战保护,直接 fetch 会返回挑战 HTML(0 个 <loc>)。
|
||||
// 支持从本地缓存的 XML 读取:SITEMAP_XML_<SITE> 环境变量,或 var/sitemap-<site>.xml。
|
||||
function localSitemapFile(name) {
|
||||
const fromEnv = process.env['SITEMAP_XML_' + name.toUpperCase()];
|
||||
if (fromEnv && fs.existsSync(fromEnv)) return fromEnv;
|
||||
const p = path.join(ROOT, 'var', `sitemap-${name}.xml`);
|
||||
return fs.existsSync(p) ? p : null;
|
||||
}
|
||||
|
||||
async function fetchSitemap(name, url) {
|
||||
const local = localSitemapFile(name);
|
||||
if (local) {
|
||||
console.log(`[site-map] ${name}: 使用本地 sitemap ${local}`);
|
||||
return parseLocs(await fs.promises.readFile(local, 'utf8'));
|
||||
}
|
||||
const res = await fetch(url, {
|
||||
headers: { 'User-Agent': 'Mozilla/5.0 (compatible; YehwangSiteMapBot/1.0)' },
|
||||
signal: AbortSignal.timeout(90000),
|
||||
});
|
||||
if (!res.ok) throw new Error(`sitemap HTTP ${res.status}: ${url}`);
|
||||
const xml = await res.text();
|
||||
return [...xml.matchAll(/<loc>([^<]+)<\/loc>/g)].map((m) => m[1].trim()).filter(Boolean);
|
||||
const locs = parseLocs(xml);
|
||||
if (!locs.length) {
|
||||
throw new Error(`sitemap 返回 0 个 <loc>(可能被 WAF 挑战):先下载 XML 到 var/sitemap-${name}.xml,或设置 SITEMAP_XML_${name.toUpperCase()}`);
|
||||
}
|
||||
return locs;
|
||||
}
|
||||
|
||||
async function buildSite(client, name) {
|
||||
const cfg = SITES[name];
|
||||
const urls = await fetchSitemap(cfg.sitemap);
|
||||
const urls = await fetchSitemap(name, cfg.sitemap);
|
||||
const rows = [];
|
||||
const seenPaths = new Set();
|
||||
for (const url of urls) {
|
||||
|
||||
Reference in New Issue
Block a user