From 09a652fcd60b7d4f24909ee3700e46339b85746b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A5=87=E8=B6=A3=E4=BF=9D=E7=BD=97?= Date: Wed, 5 Aug 2026 21:57:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A7=92=E8=89=B2=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E9=80=82=E9=85=8D=E5=8E=9F=E7=A5=9E=E5=92=8C?= =?UTF-8?q?=E6=98=9F=E7=A9=B9=E9=93=81=E9=81=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- download-character-img/index.js | 53 ++++++++++++++++++++++++++++++--- download-character-img/utils.js | 3 +- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/download-character-img/index.js b/download-character-img/index.js index e4cbeb2..f823312 100644 --- a/download-character-img/index.js +++ b/download-character-img/index.js @@ -21,7 +21,9 @@ const { * @property {string} [url] 完整 parse API 地址(与 baseUrl + wikiTitle 二选一) * @property {string} [wikiTitle] Wiki 页面标题 * @property {string} savePath 图片保存目录 - * @property {string} imageSelector 图片 CSS 选择器 + * @property {string} [scopeSelector] 限定搜索范围的容器选择器,如 table.fandom-table + * @property {number} [scopeIndex=0] 当存在多个 scope 时,取第几个(从 0 开始) + * @property {string} imageSelector 图片 CSS 选择器(相对于 scope 或整页) * @property {string} [imageUrlAttr='src'] 图片 URL 所在属性,如 src、data-src * @property {(name: string) => string} [nameTransform] 文件名二次处理 * @property {number} [downloadDelayMs] 下载间隔,默认 500ms @@ -30,6 +32,30 @@ const { /** @type {WikiConfig[]} */ const wikiConfigs = [ + { + name: 'genshin', + baseUrl: 'https://genshin-impact.fandom.com', + wikiTitle: 'Character/List', + savePath: path.join(__dirname, 'output', 'genshin'), + scopeSelector: 'table.fandom-table', + scopeIndex: 0, + imageSelector: 'td:first-child img[data-relevant="1"]', + imageUrlAttr: 'data-src', + nameTransform: (name) => name.replace(/-icon$/, ''), + verifyApiUrl: 'https://paul.ren/api/page/get?slug=photo-collection-genshin', + }, + { + name: 'sr', + baseUrl: 'https://honkai-star-rail.fandom.com', + wikiTitle: 'Character/List', + savePath: path.join(__dirname, 'output', 'sr'), + scopeSelector: 'table.article-table', + scopeIndex: 0, + imageSelector: 'td:first-child img[data-relevant="1"]', + imageUrlAttr: 'data-src', + nameTransform: (name) => name.replace(/character-/, '').replace(/-icon$/, ''), + verifyApiUrl: 'https://paul.ren/api/page/get?slug=photo-collection-sr', + }, { name: 'nte', baseUrl: 'https://neverness-to-everness.fandom.com/wiki/Character/List', @@ -95,12 +121,29 @@ async function fetchWikiHtml(config) { return html; } -function extractImages(html, imageSelector, imageUrlAttr = 'src') { +function extractImages(html, config) { + const { + imageSelector, + imageUrlAttr = 'src', + scopeSelector, + scopeIndex = 0, + } = config; const $ = cheerio.load(html); + const $container = scopeSelector + ? $(scopeSelector).eq(scopeIndex) + : null; + + if (scopeSelector && $container.length === 0) { + return []; + } + + const $images = $container ? $container.find(imageSelector) : $(imageSelector); const results = []; const seenNames = new Set(); - $(imageSelector).each((_, element) => { + console.log('表格搜索数量:', $images.length); + + $images.each((_, element) => { const $img = $(element); const rawUrl = resolveImageUrl($img, imageUrlAttr); @@ -119,6 +162,8 @@ function extractImages(html, imageSelector, imageUrlAttr = 'src') { results.push({ url: cleanedUrl, rawName }); }); + console.log('已去重结果数量:', results.length); + return results; } @@ -148,7 +193,7 @@ async function downloadWiki(config) { fs.mkdirSync(config.savePath, { recursive: true }); const html = await fetchWikiHtml(config); - const images = extractImages(html, config.imageSelector, config.imageUrlAttr ?? 'src'); + const images = extractImages(html, config); console.log(`共找到 ${images.length} 张角色图`); diff --git a/download-character-img/utils.js b/download-character-img/utils.js index 54ca78f..f56adee 100644 --- a/download-character-img/utils.js +++ b/download-character-img/utils.js @@ -10,7 +10,8 @@ function cleanImageUrl(url) { function generateImageName(url) { const fileNameMatch = url.match(/\/([^/]+)\.png/i); if (fileNameMatch && fileNameMatch[1]) { - return fileNameMatch[1].toLowerCase().replace(/_/g, '-'); + // 去除 .、&、(、) 等特殊字符 + return fileNameMatch[1].toLowerCase().replace(/_/g, '-').replaceAll(/\.|%26|%28|%29|%e2%80%a2/g, "").replace(/-{2,}/g, '-'); } return null; }