initial commit
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const toml = require('@iarna/toml');
|
||||
const puppeteer = require('puppeteer-extra');
|
||||
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
|
||||
puppeteer.use(StealthPlugin());
|
||||
|
||||
// --- Helper Functions ---
|
||||
|
||||
function loadConfig() {
|
||||
try {
|
||||
const configPath = path.join(__dirname, 'config.toml');
|
||||
const tomlString = fs.readFileSync(configPath, 'utf-8');
|
||||
const config = toml.parse(tomlString);
|
||||
console.log('✅ Configuration loaded successfully.');
|
||||
return config;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to load or parse config.toml:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function generateRandomData() {
|
||||
const randomString = Math.random().toString(36).substring(2, 10);
|
||||
const username = `user${randomString}`;
|
||||
const email = `${username}@gmail.com`;
|
||||
const password = `pass${randomString}`;
|
||||
const age = Math.floor(Math.random() * 30 + 20).toString(); // Random age between 20-49
|
||||
return { username, email, password, age };
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a locator string. If it's an HTML snippet, it generates a CSS selector.
|
||||
* If it's already a selector, it returns it as is.
|
||||
* @param {string} locatorStr - The locator string from the config.
|
||||
* @returns {string} A CSS selector.
|
||||
*/
|
||||
function parseLocator(locatorStr) {
|
||||
locatorStr = locatorStr.trim();
|
||||
if (!locatorStr.startsWith('<')) {
|
||||
return locatorStr; // It's already a selector
|
||||
}
|
||||
|
||||
const getAttr = (attr) => {
|
||||
const match = locatorStr.match(new RegExp(`${attr}=["']([^"']+)["']`));
|
||||
return match ? match[1] : null;
|
||||
};
|
||||
|
||||
const tagName = (locatorStr.match(/^<([a-zA-Z0-9]+)/) || [])[1] || '';
|
||||
const id = getAttr('id');
|
||||
// FIX: Handle numeric IDs by creating an attribute selector
|
||||
if (id) {
|
||||
if (/^\\d/.test(id)) { // If id starts with a digit
|
||||
return `${tagName}[id='${id}']`;
|
||||
}
|
||||
return `${tagName}#${id}`;
|
||||
}
|
||||
|
||||
const name = getAttr('name');
|
||||
if (name) return `${tagName}[name='${name}']`;
|
||||
|
||||
const placeholder = getAttr('placeholder');
|
||||
if (placeholder) return `${tagName}[placeholder='${placeholder}']`;
|
||||
|
||||
const type = getAttr('type');
|
||||
if (type) return `${tagName}[type='${type}']`;
|
||||
|
||||
console.warn(`Could not generate a reliable selector for: ${locatorStr}.`);
|
||||
return tagName;
|
||||
}
|
||||
|
||||
|
||||
async function handleCameraBoysGDPR(page) {
|
||||
// ... (This function remains the same)
|
||||
}
|
||||
|
||||
// --- Main Execution ---
|
||||
async function main() {
|
||||
const config = loadConfig();
|
||||
const sitesToProcess = config.sites || [];
|
||||
const browserConfig = config.browser || {};
|
||||
const globalCreds = config.global_credentials || {};
|
||||
const userDataDir = browserConfig.userDataDir;
|
||||
|
||||
if (!userDataDir) {
|
||||
console.error('❌ userDataDir is not set in config.toml. This is required.');
|
||||
return;
|
||||
}
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
headless: false,
|
||||
userDataDir: userDataDir,
|
||||
args: ["--start-maximized"]
|
||||
});
|
||||
|
||||
try {
|
||||
let isFirstSite = true;
|
||||
for (const site of sitesToProcess) {
|
||||
let creds;
|
||||
if (site.credentials && site.credentials.username) {
|
||||
creds = { ...globalCreds, ...site.credentials };
|
||||
console.log(`Using credentials specified for site: ${site.name}`);
|
||||
} else {
|
||||
creds = { ...globalCreds };
|
||||
console.log(`Using global credentials for site: ${site.name}`);
|
||||
}
|
||||
// If any credential is still missing, generate it randomly
|
||||
if (!creds.username || !creds.email || !creds.password || !creds.age) {
|
||||
const randomData = generateRandomData();
|
||||
creds = { ...randomData, ...creds };
|
||||
console.log('Filled in missing credentials with random data.');
|
||||
}
|
||||
|
||||
|
||||
console.log(`\n--- Processing Site: ${site.name} (Category: ${site.category || 'N/A'}) ---`);
|
||||
|
||||
const page = isFirstSite ? (await browser.pages())[0] : await browser.newPage();
|
||||
isFirstSite = false;
|
||||
|
||||
if (browserConfig.userAgent) {
|
||||
await page.setUserAgent(browserConfig.userAgent);
|
||||
}
|
||||
|
||||
await page.goto(site.url, { waitUntil: 'networkidle2' });
|
||||
|
||||
if (site.needsPreSubmitAction && site.name === 'CameraBoys') {
|
||||
await handleCameraBoysGDPR(page);
|
||||
}
|
||||
|
||||
console.log('Dynamically filling out the form...');
|
||||
const definedLocators = site.locators || {};
|
||||
|
||||
for (const fieldName in definedLocators) {
|
||||
if (fieldName === 'submit') continue; // Skip the submit button
|
||||
|
||||
const selector = parseLocator(definedLocators[fieldName]);
|
||||
let valueToFill = creds[fieldName];
|
||||
|
||||
// Special case for 'confirmEmail', use the email value
|
||||
if (fieldName === 'confirmEmail') {
|
||||
valueToFill = creds['email'];
|
||||
}
|
||||
|
||||
if (selector && valueToFill) {
|
||||
try {
|
||||
console.log(` - Filling field: ${fieldName}`);
|
||||
await page.type(selector, valueToFill, { delay: 100 });
|
||||
} catch (e) {
|
||||
console.warn(` - Could not fill field '${fieldName}' with selector '${selector}'. Error: ${e.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Form filled. Attempting to submit...');
|
||||
const submitSelector = parseLocator(definedLocators.submit);
|
||||
await page.click(submitSelector);
|
||||
|
||||
console.log(`✅ Submission attempt for ${site.name} is complete.`);
|
||||
}
|
||||
} catch(error) {
|
||||
console.error('❌ A critical error occurred during execution:', error.message);
|
||||
} finally {
|
||||
console.log('\n🎉 All tasks complete. The browser window will remain open for inspection.');
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user