@imaginerlabs/user-agent-generator
Version:
High-performance, configurable, batch-generating User-Agent spoofing library. Supports multiple browsers, devices, and returns detailed meta information. Perfect for web scraping, automated testing, proxy pools and more.
208 lines (207 loc) • 7.54 kB
JavaScript
;
/**
* User-Agent Generator Module
* User-Agent 生成器模块
*
* This module provides functionality to generate realistic User-Agent strings
* for different browsers, operating systems, and devices.
* 该模块提供生成不同浏览器、操作系统和设备的真实 User-Agent 字符串的功能。
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateUserAgent = generateUserAgent;
const utils_1 = require("./utils");
const metaBuilder_1 = require("./metaBuilder");
// Cache all data file contents
// 缓存所有数据文件的内容
const dataCache = {};
// Pre-generate a batch of random numbers
// 预生成一批随机数
const randomPool = [];
const POOL_SIZE = 1000;
for (let i = 0; i < POOL_SIZE; i++) {
randomPool.push(Math.random());
}
let randomIndex = 0;
/**
* Function to get random number
* 获取随机数的函数
*
* @returns Random number / 随机数
*/
function getRandom() {
if (randomIndex >= POOL_SIZE) {
randomIndex = 0;
// Refill random number pool
// 重新填充随机数池
for (let i = 0; i < POOL_SIZE; i++) {
randomPool[i] = Math.random();
}
}
return randomPool[randomIndex++];
}
// Mapping between browser types and their data files
// 浏览器类型与其数据文件的映射关系
const browserDataFile = {
chrome: 'chrome.json',
safari: 'safari.json',
firefox: 'firefox.json',
};
// Mapping between device types and their OS data files
// 设备类型与其操作系统数据文件的映射关系
const osDataFile = {
mac: 'macos.json',
windows: 'windows.json',
iphone: 'ios.json',
ipad: 'ipad.json',
};
// Device type specific UA string generation rules
// 设备类型特定的 UA 字符串生成规则
const deviceUAInfo = {
mac: {
// Generate macOS UA string fragment
// 生成 macOS UA 字符串片段
osString: (osVersion) => `Macintosh; Intel Mac OS X ${osVersion.replace(/\./g, '_')}`,
device: 'desktop',
os: 'macos',
},
windows: {
// Generate Windows UA string fragment
// 生成 Windows UA 字符串片段
osString: (osVersion) => {
const versionMap = {
'7': '6.1',
'8': '6.2',
'8.1': '6.3',
'10': '10.0',
'11': '10.0',
};
const ntVersion = versionMap[osVersion] || '10.0';
return `Windows NT ${ntVersion}; Win64; x64`;
},
device: 'desktop',
os: 'windows',
},
iphone: {
// Generate iPhone UA string fragment
// 生成 iPhone UA 字符串片段
osString: (osVersion) => `iPhone; CPU iPhone OS ${osVersion.replace(/\./g, '_')} like Mac OS X`,
device: 'mobile',
os: 'ios',
},
ipad: {
// Generate iPad UA string fragment
// 生成 iPad UA 字符串片段
osString: (osVersion) => `iPad; CPU OS ${osVersion.replace(/\./g, '_')} like Mac OS X`,
device: 'tablet',
os: 'ipados',
},
};
/**
* Get cached data
* 获取缓存的数据
*
* @param file Filename (e.g., chrome.json) / 文件名(如 chrome.json)
* @returns Cached data object / 缓存的数据对象
*/
function getCachedData(file) {
if (!dataCache[file]) {
try {
dataCache[file] = require(`../data/${file}`);
}
catch (error) {
throw new Error(`Failed to load data file: ${file}. Error: ${error}`);
}
}
return dataCache[file];
}
/**
* Select version from data array (supports both string and weighted object formats)
* 从数据数组中选择版本(支持字符串和权重对象格式)
*
* @param versions Version array / 版本数组
* @param random Random number / 随机数
* @returns Selected version / 选中的版本
*/
function selectVersion(versions, random = getRandom()) {
if (!versions || versions.length === 0) {
throw new Error('Versions array is empty or undefined');
}
// Check if it's a weighted version with subValue
// 检查是否为带子值的权重版本
if (versions[0] && typeof versions[0] === 'object' && 'subValue' in versions[0]) {
return (0, utils_1.pickWeightedVersionWithSubValue)(versions, random);
}
else {
return (0, utils_1.pickRandom)(versions, random);
}
}
/**
* Generate User-Agent string or structured object
* 生成 User-Agent 字符串或结构化对象
*
* @param options Generation parameters (browser, device, count, withMeta) / 生成参数(浏览器、设备、数量、是否包含元数据)
* @returns Single UA string/object, or array of UAs / 单个 UA 字符串/对象,或 UA 数组
*/
function generateUserAgent(options = {}) {
var _a;
const count = (_a = options.count) !== null && _a !== void 0 ? _a : 1;
// Handle edge case: count = 0
// 处理边界情况:count = 0
if (count === 0) {
return [];
}
const browser = options.browser || (0, utils_1.pickRandom)(['chrome', 'safari', 'firefox']);
const device = options.device || (0, utils_1.pickRandom)(['mac', 'windows', 'iphone', 'ipad']);
const result = [];
for (let i = 0; i < count; i++) {
let ua = '';
let meta;
const osInfo = deviceUAInfo[device];
// Use cached data
// 使用缓存的数据
const osData = getCachedData(osDataFile[device]);
const osVersion = selectVersion(osData.versions);
const osString = osInfo.osString(osVersion);
let browserVersion = '';
switch (browser) {
case 'chrome': {
const chromeData = getCachedData(browserDataFile.chrome);
const chromeVersion = selectVersion(chromeData.versions);
const webkitVersion = selectVersion(chromeData.webkitVersions);
const safariVersion = selectVersion(chromeData.safariVersions);
browserVersion = chromeVersion;
ua = `Mozilla/5.0 (${osString}) AppleWebKit/${webkitVersion} (KHTML, like Gecko) Chrome/${browserVersion} Safari/${safariVersion}`;
break;
}
case 'safari': {
const safariData = getCachedData(browserDataFile.safari);
browserVersion = selectVersion(safariData.versions);
const webkitVersion = selectVersion(safariData.webkitVersions);
ua = `Mozilla/5.0 (${osString}) AppleWebKit/${webkitVersion} (KHTML, like Gecko) Version/${browserVersion} Safari/${webkitVersion}`;
break;
}
case 'firefox': {
const firefoxData = getCachedData(browserDataFile.firefox);
browserVersion = selectVersion(firefoxData.versions);
ua = `Mozilla/5.0 (${osString}; rv:${browserVersion}) Gecko/20100101 Firefox/${browserVersion}`;
break;
}
}
// Whether to return structured meta information
// 是否返回结构化 meta 信息
if (options.withMeta) {
meta = (0, metaBuilder_1.buildMeta)({
browser,
browserVersion,
os: osInfo.os,
osVersion,
device: osInfo.device,
});
result.push({ ua, meta });
}
else {
result.push(ua);
}
}
return count === 1 && result.length > 0 ? result[0] : result;
}