File size: 4,989 Bytes
ea67eaf 7668e81 ea67eaf 7668e81 ea67eaf ec4bf22 ea67eaf ec4bf22 ea67eaf ec4bf22 ea67eaf 4d4616f ee5f61f ea67eaf 4d4616f ea67eaf 7668e81 ea67eaf 7668e81 ea67eaf 7668e81 ea67eaf 7668e81 ea67eaf ec4bf22 ea67eaf ec4bf22 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | /**
* 爬虫配置文件
* 集中管理所有爬虫配置,方便切换和调整
*/
export interface CrawlerConfig {
preset: string;
maxConcurrency: number;
requestHandlerTimeoutSecs: number;
maxRequestRetries: number;
pageLoadWaitMs: number;
launchOptions: {
headless: boolean | 'new';
args?: string[];
};
selectors: {
brand: string[];
price: string[];
originalPrice: string[];
rating: string[];
reviews: string[];
};
// 添加代理配置
useProxy: boolean;
proxyFile?: string;
}
const PRESETS: Record<string, Partial<CrawlerConfig>> = {
fast: {
maxConcurrency: 20,
requestHandlerTimeoutSecs: 30,
maxRequestRetries: 1,
pageLoadWaitMs: 500,
useProxy: true, // 启用代理
launchOptions: {
headless: 'new',
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu',
'--disable-software-rasterizer',
'--disable-extensions',
'--disable-background-networking',
'--disable-default-apps',
'--disable-sync',
'--disable-translate',
'--hide-scrollbars',
'--mute-audio',
'--no-first-run',
'--no-pings',
'--disable-features=IsolateOrigins,site-per-process'
]
}
},
stable: {
maxConcurrency: 5,
requestHandlerTimeoutSecs: 90,
maxRequestRetries: 1,
pageLoadWaitMs: 500,
useProxy: true, // 启用代理
launchOptions: {
headless: 'new',
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu',
'--disable-software-rasterizer',
'--disable-extensions',
'--disable-background-networking', // 禁止后台网络活动
'--disable-default-apps',
'--disable-sync',
'--disable-translate',
'--hide-scrollbars',
'--mute-audio',
'--no-first-run',
'--no-pings',
'--disable-features=IsolateOrigins,site-per-process',
'--dns-prefetch-disable', // 禁用 DNS 预取,有时能避免奇怪的阻塞
'--disable-logging'
]
}
},
stealth: {
maxConcurrency: 2, // 进一步降低并发数
requestHandlerTimeoutSecs: 240, // 延长超时时间
maxRequestRetries: 2, // 增加重试次数
pageLoadWaitMs: 800, // 增加页面等待时间
useProxy: true, // 启用代理
launchOptions: {
headless: 'new',
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu',
'--disable-software-rasterizer',
'--disable-extensions',
'--disable-background-networking',
'--disable-default-apps',
'--disable-sync',
'--disable-translate',
'--hide-scrollbars',
'--mute-audio',
'--no-first-run',
'--no-pings',
'--disable-features=IsolateOrigins,site-per-process',
// 新增反检测参数
'--disable-blink-features=AutomationControlled',
'--disable-automation',
'--disable-web-security',
'--allow-running-insecure-content',
'--disable-features=VizDisplayCompositor',
'--disable-features=ImprovedCookieControls,SameSiteByDefaultCookies,CookiesWithoutSameSiteMustBeSecure',
'--disable-features=WebRtcHideLocalIpsWithMdns',
'--disable-features=WebContentsForceDark',
'--disable-features=AutofillEnableAccountWalletStorage',
'--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
]
}
}
};
export const DEFAULT_SELECTORS = {
// 标题选择器 - 用于智能等待判断页面是否加载完成
brand: [
'.js_pdp_short-info__brand-link'
],
price: [
'span.js_pdp_price__retail-price__value_original'
],
originalPrice: [
'span.pdp_price__strike-through-price'
],
rating: [
'div.pdp_cr-rating-score span'
],
reviews: [
'span.js_pdp_cr-rating--review-count'
]
};
export function getCrawlerConfig(presetName: string = 'stable', overrides: Partial<CrawlerConfig> = {}): CrawlerConfig {
const preset = PRESETS[presetName] || PRESETS['stable'];
// 先合并基础配置
const baseConfig: CrawlerConfig = {
preset: presetName,
maxConcurrency: 5,
requestHandlerTimeoutSecs: 60,
maxRequestRetries: 3,
pageLoadWaitMs: 2000,
useProxy: false, // 默认不使用代理
selectors: DEFAULT_SELECTORS,
launchOptions: {
headless: 'new'
}
};
// 合并预设配置
const mergedConfig: Partial<CrawlerConfig> = {
...baseConfig,
...preset,
...overrides
};
// 特殊处理 launchOptions 的合并
mergedConfig.launchOptions = {
...(baseConfig.launchOptions),
...(preset.launchOptions || {}),
...(overrides.launchOptions || {})
};
return mergedConfig as CrawlerConfig;
} |