From 44aba27033bb3ba662a1aecc7c27c936865d0c93 Mon Sep 17 00:00:00 2001 From: DIYgod Date: Thu, 29 May 2025 12:51:04 +0800 Subject: [PATCH] fix: smzdm --- lib/config.ts | 6 + lib/routes/smzdm/article.ts | 22 +- lib/routes/smzdm/baoliao.ts | 22 +- lib/routes/smzdm/haowen-fenlei.ts | 22 +- lib/routes/smzdm/haowen.ts | 22 +- lib/routes/smzdm/keyword.ts | 15 +- lib/routes/smzdm/product.ts | 22 +- lib/routes/smzdm/ranking.ts | 324 ++++++++++++++++-------------- lib/routes/smzdm/utils.ts | 6 + 9 files changed, 291 insertions(+), 170 deletions(-) create mode 100644 lib/routes/smzdm/utils.ts diff --git a/lib/config.ts b/lib/config.ts index 2d435b5c3..294257f8d 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -401,6 +401,9 @@ export type Config = { zsxq: { accessToken?: string; }; + smzdm: { + cookie?: string; + }; }; const value: Config | Record = {}; @@ -842,6 +845,9 @@ const calculateValue = () => { zsxq: { accessToken: envs.ZSXQ_ACCESS_TOKEN, }, + smzdm: { + cookie: envs.SMZDM_COOKIE, + }, }; for (const name in _value) { diff --git a/lib/routes/smzdm/article.ts b/lib/routes/smzdm/article.ts index c8457ea73..f87cbb81d 100644 --- a/lib/routes/smzdm/article.ts +++ b/lib/routes/smzdm/article.ts @@ -4,6 +4,9 @@ import got from '@/utils/got'; import { load } from 'cheerio'; import { parseDate } from '@/utils/parse-date'; import timezone from '@/utils/timezone'; +import { config } from '@/config'; +import { getHeaders } from './utils'; +import ConfigNotFoundError from '@/errors/types/config-not-found'; export const route: Route = { path: '/article/:uid', @@ -11,7 +14,12 @@ export const route: Route = { example: '/smzdm/article/6902738986', parameters: { uid: '用户 id,网址上直接可以看到' }, features: { - requireConfig: false, + requireConfig: [ + { + name: 'SMZDM_COOKIE', + description: '什么值得买登录后的 Cookie 值', + }, + ], requirePuppeteer: false, antiCrawler: false, supportBT: false, @@ -29,9 +37,15 @@ export const route: Route = { }; async function handler(ctx) { + if (!config.smzdm.cookie) { + throw new ConfigNotFoundError('什么值得买排行榜 is disabled due to the lack of SMZDM_COOKIE'); + } + const link = `https://zhiyou.smzdm.com/member/${ctx.req.param('uid')}/article/`; - const response = await got(link); + const response = await got(link, { + headers: getHeaders(), + }); const $ = load(response.data); const title = $('.info-stuff-nickname a').text(); @@ -49,7 +63,9 @@ async function handler(ctx) { const out = await Promise.all( list.map((item) => cache.tryGet(item.link, async () => { - const response = await got(item.link); + const response = await got(item.link, { + headers: getHeaders(), + }); const $ = load(response.data); item.description = $('.m-contant article').html(); item.pubDate = timezone(parseDate($('meta[property="og:release_date"]').attr('content'), 'YYYY-MM-DD HH:mm:ss'), 8); diff --git a/lib/routes/smzdm/baoliao.ts b/lib/routes/smzdm/baoliao.ts index 931aa07b3..a3314e5d2 100644 --- a/lib/routes/smzdm/baoliao.ts +++ b/lib/routes/smzdm/baoliao.ts @@ -4,6 +4,9 @@ import got from '@/utils/got'; import { load } from 'cheerio'; import { parseDate } from '@/utils/parse-date'; import timezone from '@/utils/timezone'; +import { config } from '@/config'; +import { getHeaders } from './utils'; +import ConfigNotFoundError from '@/errors/types/config-not-found'; export const route: Route = { path: '/baoliao/:uid', @@ -11,7 +14,12 @@ export const route: Route = { example: '/smzdm/baoliao/7367111021', parameters: { uid: '用户id,网址上直接可以看到' }, features: { - requireConfig: false, + requireConfig: [ + { + name: 'SMZDM_COOKIE', + description: '什么值得买登录后的 Cookie 值', + }, + ], requirePuppeteer: false, antiCrawler: false, supportBT: false, @@ -29,9 +37,15 @@ export const route: Route = { }; async function handler(ctx) { + if (!config.smzdm.cookie) { + throw new ConfigNotFoundError('什么值得买排行榜 is disabled due to the lack of SMZDM_COOKIE'); + } + const link = `https://zhiyou.smzdm.com/member/${ctx.req.param('uid')}/baoliao/`; - const response = await got(link); + const response = await got(link, { + headers: getHeaders(), + }); const $ = load(response.data); const title = $('.info-stuff-nickname').text(); @@ -49,7 +63,9 @@ async function handler(ctx) { const out = await Promise.all( list.map((item) => cache.tryGet(item.link, async () => { - const response = await got(item.link); + const response = await got(item.link, { + headers: getHeaders(), + }); const $ = load(response.data); item.description = $('article.txt-detail').html(); item.pubDate = timezone(parseDate($('.time').first().text().trim().replace('更新时间:', '')), 8); diff --git a/lib/routes/smzdm/haowen-fenlei.ts b/lib/routes/smzdm/haowen-fenlei.ts index 3d7c9dc45..35ece724b 100644 --- a/lib/routes/smzdm/haowen-fenlei.ts +++ b/lib/routes/smzdm/haowen-fenlei.ts @@ -4,13 +4,21 @@ import got from '@/utils/got'; import { load } from 'cheerio'; import timezone from '@/utils/timezone'; import { parseDate } from '@/utils/parse-date'; +import { config } from '@/config'; +import { getHeaders } from './utils'; +import ConfigNotFoundError from '@/errors/types/config-not-found'; export const route: Route = { path: '/haowen/fenlei/:name/:sort?', categories: ['shopping'], example: '/smzdm/haowen/fenlei/shenghuodianqi', parameters: { name: '分类名,可在 URL 中查看', sort: '排序方式,默认为最新' }, features: { - requireConfig: false, + requireConfig: [ + { + name: 'SMZDM_COOKIE', + description: '什么值得买登录后的 Cookie 值', + }, + ], requirePuppeteer: false, antiCrawler: false, supportBT: false, @@ -32,12 +40,18 @@ export const route: Route = { }; async function handler(ctx) { + if (!config.smzdm.cookie) { + throw new ConfigNotFoundError('什么值得买排行榜 is disabled due to the lack of SMZDM_COOKIE'); + } + const name = ctx.req.param('name'); const sort = ctx.req.param('sort') || '0'; const link = sort === '0' ? `https://post.smzdm.com/fenlei/${name}/` : `https://post.smzdm.com/fenlei/${name}/hot_${sort}/`; - const response = await got.get(link); + const response = await got.get(link, { + headers: getHeaders(), + }); const $ = load(response.data); const title = $('div.crumbs.nav-crumbs').text().split('>').pop(); @@ -58,7 +72,9 @@ async function handler(ctx) { list.map((item) => cache.tryGet(item.link, async () => { try { - const response = await got(item.link); + const response = await got(item.link, { + headers: getHeaders(), + }); const $ = load(response.data); item.description = $('article').html(); item.pubDate = timezone(parseDate($('meta[property="og:release_date"]').attr('content')), 8); diff --git a/lib/routes/smzdm/haowen.ts b/lib/routes/smzdm/haowen.ts index ce710e7b8..11e5aa5dd 100644 --- a/lib/routes/smzdm/haowen.ts +++ b/lib/routes/smzdm/haowen.ts @@ -4,6 +4,9 @@ import ofetch from '@/utils/ofetch'; import { load } from 'cheerio'; import { parseDate } from '@/utils/parse-date'; import timezone from '@/utils/timezone'; +import { getHeaders } from './utils'; +import ConfigNotFoundError from '@/errors/types/config-not-found'; +import { config } from '@/config'; export const route: Route = { path: '/haowen/:day?', @@ -21,7 +24,12 @@ export const route: Route = { }, }, features: { - requireConfig: false, + requireConfig: [ + { + name: 'SMZDM_COOKIE', + description: '什么值得买登录后的 Cookie 值', + }, + ], requirePuppeteer: false, antiCrawler: false, supportBT: false, @@ -34,10 +42,16 @@ export const route: Route = { }; async function handler(ctx) { + if (!config.smzdm.cookie) { + throw new ConfigNotFoundError('什么值得买排行榜 is disabled due to the lack of SMZDM_COOKIE'); + } + const day = ctx.req.param('day') ?? '1'; const link = `https://post.smzdm.com/hot_${day}/`; - const response = await ofetch(link); + const response = await ofetch(link, { + headers: getHeaders(), + }); const $ = load(response); const title = $('li.filter-tab.active').text(); @@ -55,7 +69,9 @@ async function handler(ctx) { const out = await Promise.all( list.map((item) => cache.tryGet(item.link ?? '', async () => { - const response = await ofetch(item.link ?? ''); + const response = await ofetch(item.link ?? '', { + headers: getHeaders(), + }); const $ = load(response); const content = $('#articleId'); content.find('.item-name').remove(); diff --git a/lib/routes/smzdm/keyword.ts b/lib/routes/smzdm/keyword.ts index 1161ebcf6..d26ef8bba 100644 --- a/lib/routes/smzdm/keyword.ts +++ b/lib/routes/smzdm/keyword.ts @@ -3,6 +3,9 @@ import got from '@/utils/got'; import { load } from 'cheerio'; import { parseDate } from '@/utils/parse-date'; import timezone from '@/utils/timezone'; +import { getHeaders } from './utils'; +import ConfigNotFoundError from '@/errors/types/config-not-found'; +import { config } from '@/config'; export const route: Route = { path: '/keyword/:keyword', @@ -11,7 +14,12 @@ export const route: Route = { example: '/smzdm/keyword/女装', parameters: { keyword: '你想订阅的关键词' }, features: { - requireConfig: false, + requireConfig: [ + { + name: 'SMZDM_COOKIE', + description: '什么值得买登录后的 Cookie 值', + }, + ], requirePuppeteer: false, antiCrawler: false, supportBT: false, @@ -24,10 +32,15 @@ export const route: Route = { }; async function handler(ctx) { + if (!config.smzdm.cookie) { + throw new ConfigNotFoundError('什么值得买排行榜 is disabled due to the lack of SMZDM_COOKIE'); + } + const keyword = ctx.req.param('keyword'); const response = await got(`https://search.smzdm.com`, { headers: { + ...getHeaders(), Referer: `https://search.smzdm.com/?c=home&s=${encodeURIComponent(keyword)}&order=time&v=a`, }, searchParams: { diff --git a/lib/routes/smzdm/product.ts b/lib/routes/smzdm/product.ts index 14e9ca19a..d8673e4f9 100644 --- a/lib/routes/smzdm/product.ts +++ b/lib/routes/smzdm/product.ts @@ -2,6 +2,9 @@ import { Route, DataItem } from '@/types'; import ofetch from '@/utils/ofetch'; import { load } from 'cheerio'; import cache from '@/utils/cache'; +import { getHeaders } from './utils'; +import ConfigNotFoundError from '@/errors/types/config-not-found'; +import { config } from '@/config'; export const route: Route = { path: '/product/:id', @@ -9,7 +12,12 @@ export const route: Route = { example: '/smzdm/product/zm5vzpe', parameters: { id: '商品 id,网址上直接可以看到' }, features: { - requireConfig: false, + requireConfig: [ + { + name: 'SMZDM_COOKIE', + description: '什么值得买登录后的 Cookie 值', + }, + ], requirePuppeteer: false, antiCrawler: false, supportBT: false, @@ -28,9 +36,15 @@ export const route: Route = { }; async function handler(ctx) { + if (!config.smzdm.cookie) { + throw new ConfigNotFoundError('什么值得买排行榜 is disabled due to the lack of SMZDM_COOKIE'); + } + const link = `https://wiki.smzdm.com/p/${ctx.req.param('id')}`; - const response = await ofetch(link); + const response = await ofetch(link, { + headers: getHeaders(), + }); const $ = load(response); const title = $('title').text(); @@ -55,7 +69,9 @@ async function handler(ctx) { const out = await Promise.all( items.map((item) => cache.tryGet(item.link, async () => { - const response = await ofetch(item.link); + const response = await ofetch(item.link, { + headers: getHeaders(), + }); const $ = load(response); // filter outdated articles diff --git a/lib/routes/smzdm/ranking.ts b/lib/routes/smzdm/ranking.ts index 608273fdc..160ee4019 100644 --- a/lib/routes/smzdm/ranking.ts +++ b/lib/routes/smzdm/ranking.ts @@ -1,6 +1,9 @@ +import { config } from '@/config'; import { Route, ViewType } from '@/types'; import got from '@/utils/got'; import timezone from '@/utils/timezone'; +import { getHeaders } from './utils'; +import ConfigNotFoundError from '@/errors/types/config-not-found'; const getTrueHour = (rank_type, rank_id, hour) => { const rank_two_hour = ['11', '17', '28', '29']; @@ -13,6 +16,159 @@ const getTrueHour = (rank_type, rank_id, hour) => { } }; +const typeOptions = [ + { + value: 'pinlei', + label: '好价品类榜', + }, + { + value: 'dianshang', + label: '好价电商榜', + }, + { + value: 'haitao', + label: '海淘 TOP 榜', + }, + { + value: 'haowen', + label: '好文排行榜', + }, + { + value: 'haowu', + label: '好物排行榜', + }, +]; +const idOptions = [ + { + label: '好价品类榜-全部', + value: '11', + }, + { + label: '好价品类榜-食品生鲜', + value: '12', + }, + { + label: '好价品类榜-电脑数码', + value: '13', + }, + { + label: '好价品类榜-运动户外', + value: '14', + }, + { + label: '好价品类榜-家用电器', + value: '15', + }, + { + label: '好价品类榜-白菜', + value: '17', + }, + { + label: '好价品类榜-服饰鞋包', + value: '74', + }, + { + label: '好价品类榜-日用百货', + value: '75', + }, + { + label: '好价电商榜-券活动', + value: '24', + }, + { + label: '好价电商榜-京东', + value: '23', + }, + { + label: '好价电商榜-天猫', + value: '25', + }, + { + label: '好价电商榜-亚马逊中国', + value: '26', + }, + { + label: '好价电商榜-国美在线', + value: '27', + }, + { + label: '好价电商榜-苏宁易购', + value: '28', + }, + { + label: '好价电商榜-网易', + value: '29', + }, + { + label: '好价电商榜-西集网', + value: '30', + }, + { + label: '好价电商榜-美国亚马逊', + value: '31', + }, + { + label: '好价电商榜-日本亚马逊', + value: '32', + }, + { + label: '好价电商榜-ebay', + value: '33', + }, + { + label: '海淘 TOP 榜-全部', + value: '39', + }, + { + label: '海淘 TOP 榜-海外直邮', + value: '34', + }, + { + label: '海淘 TOP 榜-美国榜', + value: '35', + }, + { + label: '海淘 TOP 榜-欧洲榜', + value: '36', + }, + { + label: '海淘 TOP 榜-澳新榜', + value: '37', + }, + { + label: '海淘 TOP 榜-亚洲榜', + value: '38', + }, + { + label: '海淘 TOP 榜-晒物榜', + value: 'hsw', + }, + { + label: '好文排行榜-原创', + value: 'yc', + }, + { + label: '好文排行榜-资讯', + value: 'zx', + }, + { + label: '好物排行榜-新晋榜', + value: 'hwall', + }, + { + label: '好物排行榜-消费众测', + value: 'zc', + }, + { + label: '好物排行榜-新锐品牌', + value: 'nb', + }, + { + label: '好物排行榜-好物榜单', + value: 'hw', + }, +]; + export const route: Route = { path: '/ranking/:rank_type/:rank_id/:hour', categories: ['shopping', 'popular'], @@ -21,161 +177,11 @@ export const route: Route = { parameters: { rank_type: { description: '榜单类型', - options: [ - { - value: 'pinlei', - label: '好价品类榜', - }, - { - value: 'dianshang', - label: '好价电商榜', - }, - { - value: 'haitao', - label: '海淘 TOP 榜', - }, - { - value: 'haowen', - label: '好文排行榜', - }, - { - value: 'haowu', - label: '好物排行榜', - }, - ], + options: typeOptions, }, rank_id: { description: '榜单ID', - options: [ - { - label: '好价品类榜 - 全部', - value: '11', - }, - { - label: '好价品类榜 - 食品生鲜', - value: '12', - }, - { - label: '好价品类榜 - 电脑数码', - value: '13', - }, - { - label: '好价品类榜 - 运动户外', - value: '14', - }, - { - label: '好价品类榜 - 家用电器', - value: '15', - }, - { - label: '好价品类榜 - 白菜', - value: '17', - }, - { - label: '好价品类榜 - 服饰鞋包', - value: '74', - }, - { - label: '好价品类榜 - 日用百货', - value: '75', - }, - { - label: '好价电商榜 - 券活动', - value: '24', - }, - { - label: '好价电商榜 - 京东', - value: '23', - }, - { - label: '好价电商榜 - 天猫', - value: '25', - }, - { - label: '好价电商榜 - 亚马逊中国', - value: '26', - }, - { - label: '好价电商榜 - 国美在线', - value: '27', - }, - { - label: '好价电商榜 - 苏宁易购', - value: '28', - }, - { - label: '好价电商榜 - 网易', - value: '29', - }, - { - label: '好价电商榜 - 西集网', - value: '30', - }, - { - label: '好价电商榜 - 美国亚马逊', - value: '31', - }, - { - label: '好价电商榜 - 日本亚马逊', - value: '32', - }, - { - label: '好价电商榜 - ebay', - value: '33', - }, - { - label: '海淘 TOP 榜 - 全部', - value: '39', - }, - { - label: '海淘 TOP 榜 - 海外直邮', - value: '34', - }, - { - label: '海淘 TOP 榜 - 美国榜', - value: '35', - }, - { - label: '海淘 TOP 榜 - 欧洲榜', - value: '36', - }, - { - label: '海淘 TOP 榜 - 澳新榜', - value: '37', - }, - { - label: '海淘 TOP 榜 - 亚洲榜', - value: '38', - }, - { - label: '海淘 TOP 榜 - 晒物榜', - value: 'hsw', - }, - { - label: '好文排行榜 - 原创', - value: 'yc', - }, - { - label: '好文排行榜 - 资讯', - value: 'zx', - }, - { - label: '好物排行榜 - 新晋榜', - value: 'hwall', - }, - { - label: '好物排行榜 - 消费众测', - value: 'zc', - }, - { - label: '好物排行榜 - 新锐品牌', - value: 'nb', - }, - { - label: '好物排行榜 - 好物榜单', - value: 'hw', - }, - ], + options: idOptions, }, hour: { description: '时间跨度', @@ -196,7 +202,12 @@ export const route: Route = { }, }, features: { - requireConfig: false, + requireConfig: [ + { + name: 'SMZDM_COOKIE', + description: '什么值得买登录后的 Cookie 值', + }, + ], requirePuppeteer: false, antiCrawler: false, supportBT: false, @@ -209,6 +220,10 @@ export const route: Route = { }; async function handler(ctx) { + if (!config.smzdm.cookie) { + throw new ConfigNotFoundError('什么值得买排行榜 is disabled due to the lack of SMZDM_COOKIE'); + } + const { rank_type, rank_id, hour } = ctx.req.param(); // When the hour is 3, some special rank_id require a special hour num @@ -217,6 +232,7 @@ async function handler(ctx) { const response = await got(`https://www.smzdm.com/top/json_more`, { headers: { Referer: 'https://www.smzdm.com/top/', + ...getHeaders(), }, searchParams: { rank_type, @@ -239,7 +255,7 @@ async function handler(ctx) { const list = [...list1, ...list2]; return { - title: `${rank_type}榜-${rank_id}-${hour}小时`, + title: `什么值得买${typeOptions.find((item) => item.value === rank_type)?.label}-${idOptions.find((item) => item.value === rank_id)?.label}-${hour}小时`, link: 'https://www.smzdm.com/top/', allowEmpty: true, item: list.map((item) => ({ diff --git a/lib/routes/smzdm/utils.ts b/lib/routes/smzdm/utils.ts new file mode 100644 index 000000000..e1cd02d54 --- /dev/null +++ b/lib/routes/smzdm/utils.ts @@ -0,0 +1,6 @@ +import { config } from '@/config'; + +export const getHeaders = () => ({ + cookie: config.smzdm.cookie, + 'x-requested-with': 'XMLHttpRequest', +});