playwright-advanced-ml-healer
Version:
Advanced AI-powered self-healing selectors for Playwright with 19+ healing types, neural networks, machine learning models, and Global DOM Learning ML Model
626 lines • 24.8 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.GlobalDOMLearningML = void 0;
/**
* Global DOM Learning ML Model
*
* This model crawls global websites, analyzes DOM patterns, and learns
* from real-world element structures to continuously improve healing capabilities.
*/
class GlobalDOMLearningML {
constructor(page) {
this.page = page;
this.browser = null;
this.context = null;
this.knowledgeBase = new Map();
this.learningHistory = [];
// Configuration
this.config = {
maxWebsites: 1000,
maxPagesPerWebsite: 10,
maxElementsPerPage: 500,
learningRate: 0.1,
confidenceThreshold: 0.7,
crawlDelay: 1000, // 1 second between requests
timeout: 30000, // 30 seconds per page
userAgents: [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
]
};
}
/**
* Initialize the global learning system
*/
async initialize() {
try {
console.log('🌍 Initializing Global DOM Learning ML Model...');
// Initialize browser context for crawling
this.context = await this.page.context().browser()?.newContext({
userAgent: this.getRandomUserAgent(),
viewport: { width: 1920, height: 1080 },
deviceScaleFactor: 1,
isMobile: false,
hasTouch: false,
javaScriptEnabled: true,
acceptDownloads: false,
ignoreHTTPSErrors: true
});
console.log('✅ Global DOM Learning ML Model initialized successfully');
}
catch (error) {
console.error('❌ Failed to initialize Global DOM Learning ML Model:', error);
}
}
/**
* Start global learning from diverse websites
*/
async startGlobalLearning() {
console.log('🚀 Starting Global DOM Learning...');
const websites = this.getDiverseWebsiteList();
let learnedCount = 0;
for (const website of websites) {
if (learnedCount >= this.config.maxWebsites)
break;
try {
console.log(`🌐 Learning from: ${website}`);
await this.learnFromWebsite(website);
learnedCount++;
// Delay between websites to be respectful
await this.delay(this.config.crawlDelay);
}
catch (error) {
console.error(`❌ Failed to learn from ${website}:`, error);
}
}
console.log(`🎓 Global learning completed! Learned from ${learnedCount} websites`);
await this.saveKnowledgeBase();
}
/**
* Learn from a specific website
*/
async learnFromWebsite(website) {
if (!this.context)
return;
const page = await this.context.newPage();
try {
// Navigate to website
await page.goto(website, {
waitUntil: 'domcontentloaded',
timeout: this.config.timeout
});
// Learn from homepage
await this.learnFromPage(page, website, 'homepage');
// Find and learn from additional pages
const additionalPages = await this.discoverAdditionalPages(page);
for (let i = 0; i < Math.min(additionalPages.length, this.config.maxPagesPerWebsite - 1); i++) {
try {
await page.goto(additionalPages[i], {
waitUntil: 'domcontentloaded',
timeout: this.config.timeout
});
await this.learnFromPage(page, website, `page-${i + 1}`);
}
catch (error) {
console.error(`Failed to learn from additional page: ${additionalPages[i]}`);
}
}
}
catch (error) {
console.error(`Failed to learn from website: ${website}`);
}
finally {
await page.close();
}
}
/**
* Learn from a specific page
*/
async learnFromPage(page, website, pageType) {
try {
// Extract DOM patterns
const domPatterns = await this.extractDOMPatterns(page);
// Analyze element structures
const elementStructures = await this.analyzeElementStructures(page);
// Learn form patterns
const formPatterns = await this.learnFormPatterns(page);
// Learn navigation patterns
const navigationPatterns = await this.learnNavigationPatterns(page);
// Learn button patterns
const buttonPatterns = await this.learnButtonPatterns(page);
// Learn input patterns
const inputPatterns = await this.learnInputPatterns(page);
// Store learned patterns
const learningData = {
website,
pageType,
timestamp: Date.now(),
domPatterns,
elementStructures,
formPatterns,
navigationPatterns,
buttonPatterns,
inputPatterns,
metadata: {
url: page.url(),
title: await page.title(),
domain: new URL(page.url()).hostname
}
};
this.learningHistory.push({
website,
patterns: [learningData],
timestamp: Date.now(),
success: true
});
// Update knowledge base
this.updateKnowledgeBase(learningData);
console.log(`✅ Learned from ${website} - ${pageType}`);
}
catch (error) {
console.error(`Failed to learn from page: ${page.url()}`);
}
}
/**
* Extract DOM patterns from a page
*/
async extractDOMPatterns(page) {
return await page.evaluate(() => {
const patterns = [];
// Analyze document structure
const body = document.body;
if (body) {
// Count element types
const elementCounts = {};
const allElements = body.querySelectorAll('*');
allElements.forEach(element => {
const tagName = element.tagName.toLowerCase();
elementCounts[tagName] = (elementCounts[tagName] || 0) + 1;
});
// Find common patterns
const commonPatterns = Object.entries(elementCounts)
.filter(([_, count]) => count > 5)
.sort(([_, a], [__, b]) => b - a)
.slice(0, 10);
patterns.push({
type: 'element_distribution',
data: commonPatterns,
totalElements: allElements.length
});
}
// Analyze form patterns
const forms = document.querySelectorAll('form');
if (forms.length > 0) {
const formPatterns = Array.from(forms).map(form => ({
action: form.action,
method: form.method,
inputCount: form.querySelectorAll('input').length,
buttonCount: form.querySelectorAll('button').length,
hasLabels: form.querySelectorAll('label').length > 0
}));
patterns.push({
type: 'form_patterns',
data: formPatterns
});
}
// Analyze navigation patterns
const navs = document.querySelectorAll('nav, [role="navigation"]');
if (navs.length > 0) {
const navPatterns = Array.from(navs).map(nav => ({
hasList: nav.querySelector('ul, ol') !== null,
hasLinks: nav.querySelectorAll('a').length,
hasButtons: nav.querySelectorAll('button').length,
depth: window.calculateDepth(nav)
}));
patterns.push({
type: 'navigation_patterns',
data: navPatterns
});
}
return patterns;
});
}
/**
* Analyze element structures
*/
async analyzeElementStructures(page) {
return await page.evaluate(() => {
const structures = [];
// Analyze button structures
const buttons = document.querySelectorAll('button, [role="button"], input[type="button"], input[type="submit"]');
if (buttons.length > 0) {
const buttonStructures = Array.from(buttons).map(button => ({
tagName: button.tagName.toLowerCase(),
type: button.getAttribute('type'),
text: button.textContent?.trim(),
className: button.className,
id: button.id,
hasIcon: button.querySelector('i, svg, img') !== null,
size: window.getElementSize(button),
position: window.getElementPosition(button)
}));
structures.push({
type: 'button_structures',
data: buttonStructures
});
}
// Analyze input structures
const inputs = document.querySelectorAll('input, textarea, select');
if (inputs.length > 0) {
const inputStructures = Array.from(inputs).map(input => ({
tagName: input.tagName.toLowerCase(),
type: input.getAttribute('type'),
placeholder: input.getAttribute('placeholder'),
name: input.getAttribute('name'),
id: input.id,
className: input.className,
hasLabel: window.hasAssociatedLabel(input),
hasValidation: window.hasValidationAttributes(input)
}));
structures.push({
type: 'input_structures',
data: inputStructures
});
}
return structures;
});
}
/**
* Learn form patterns
*/
async learnFormPatterns(page) {
return await page.evaluate(() => {
const patterns = [];
const forms = document.querySelectorAll('form');
forms.forEach(form => {
const inputs = form.querySelectorAll('input, textarea, select');
const buttons = form.querySelectorAll('button, input[type="submit"]');
// Analyze input patterns
const inputTypes = Array.from(inputs).map(input => ({
type: input.getAttribute('type') || 'text',
name: input.getAttribute('name'),
placeholder: input.getAttribute('placeholder'),
required: input.hasAttribute('required'),
pattern: input.getAttribute('pattern')
}));
// Analyze button patterns
const buttonTypes = Array.from(buttons).map(button => ({
type: button.getAttribute('type') || 'button',
text: button.textContent?.trim(),
position: window.getElementPosition(button)
}));
patterns.push({
inputCount: inputs.length,
buttonCount: buttons.length,
inputTypes,
buttonTypes,
hasValidation: form.querySelector('[required], [pattern], [min], [max]') !== null
});
});
return patterns;
});
}
/**
* Learn navigation patterns
*/
async learnNavigationPatterns(page) {
return await page.evaluate(() => {
const patterns = [];
const navs = document.querySelectorAll('nav, [role="navigation"], header, .nav, .navigation');
navs.forEach(nav => {
const links = nav.querySelectorAll('a');
const buttons = nav.querySelectorAll('button');
const lists = nav.querySelectorAll('ul, ol');
patterns.push({
linkCount: links.length,
buttonCount: buttons.length,
listCount: lists.length,
hasDropdown: nav.querySelector('.dropdown, [aria-expanded]') !== null,
hasSearch: nav.querySelector('input[type="search"], .search') !== null,
hasLogo: nav.querySelector('img[alt*="logo"], .logo') !== null
});
});
return patterns;
});
}
/**
* Learn button patterns
*/
async learnButtonPatterns(page) {
return await page.evaluate(() => {
const patterns = [];
const buttons = document.querySelectorAll('button, [role="button"], input[type="button"], input[type="submit"]');
buttons.forEach(button => {
const text = button.textContent?.trim();
const type = button.getAttribute('type');
const className = button.className;
patterns.push({
text,
type,
className,
hasIcon: button.querySelector('i, svg, img') !== null,
isPrimary: className.includes('primary') || className.includes('btn-primary'),
isSecondary: className.includes('secondary') || className.includes('btn-secondary'),
isDanger: className.includes('danger') || className.includes('btn-danger'),
size: window.getButtonSize(button)
});
});
return patterns;
});
}
/**
* Learn input patterns
*/
async learnInputPatterns(page) {
return await page.evaluate(() => {
const patterns = [];
const inputs = document.querySelectorAll('input, textarea, select');
inputs.forEach(input => {
const type = input.getAttribute('type');
const placeholder = input.getAttribute('placeholder');
const name = input.getAttribute('name');
const id = input.id;
patterns.push({
type,
placeholder,
name,
id,
hasLabel: window.hasAssociatedLabel(input),
isRequired: input.hasAttribute('required'),
hasValidation: window.hasValidationAttributes(input),
commonPatterns: window.findCommonInputPatterns(input)
});
});
return patterns;
});
}
/**
* Discover additional pages on a website
*/
async discoverAdditionalPages(page) {
try {
const links = await page.evaluate(() => {
const anchors = document.querySelectorAll('a[href]');
const urls = [];
anchors.forEach(anchor => {
const href = anchor.getAttribute('href');
if (href && href.startsWith('/') && !href.includes('#')) {
urls.push(href);
}
});
return [...new Set(urls)].slice(0, 20); // Limit to 20 unique internal pages
});
const baseUrl = new URL(page.url()).origin;
return links.map(link => baseUrl + link);
}
catch (error) {
return [];
}
}
/**
* Update knowledge base with new learning data
*/
updateKnowledgeBase(learningData) {
const domain = learningData.metadata.domain;
if (!this.knowledgeBase.has(domain)) {
this.knowledgeBase.set(domain, {
patterns: [],
elementStructures: [],
formPatterns: [],
navigationPatterns: [],
buttonPatterns: [],
inputPatterns: [],
lastUpdated: Date.now(),
visitCount: 0
});
}
const domainData = this.knowledgeBase.get(domain);
domainData.patterns.push(learningData.domPatterns);
domainData.elementStructures.push(learningData.elementStructures);
domainData.formPatterns.push(learningData.formPatterns);
domainData.navigationPatterns.push(learningData.navigationPatterns);
domainData.buttonPatterns.push(learningData.buttonPatterns);
domainData.inputPatterns.push(learningData.inputPatterns);
domainData.lastUpdated = Date.now();
domainData.visitCount++;
// Keep only recent data (last 10 visits)
if (domainData.patterns.length > 10) {
domainData.patterns = domainData.patterns.slice(-10);
domainData.elementStructures = domainData.elementStructures.slice(-10);
domainData.formPatterns = domainData.formPatterns.slice(-10);
domainData.navigationPatterns = domainData.navigationPatterns.slice(-10);
domainData.buttonPatterns = domainData.buttonPatterns.slice(-10);
domainData.inputPatterns = domainData.inputPatterns.slice(-10);
}
}
/**
* Get diverse website list for learning
*/
getDiverseWebsiteList() {
return [
// E-commerce
'https://www.amazon.com',
'https://www.ebay.com',
'https://www.walmart.com',
'https://www.target.com',
'https://www.bestbuy.com',
// Social Media
'https://www.facebook.com',
'https://www.twitter.com',
'https://www.instagram.com',
'https://www.linkedin.com',
'https://www.youtube.com',
// News & Media
'https://www.bbc.com',
'https://www.cnn.com',
'https://www.nytimes.com',
'https://www.reuters.com',
'https://www.theguardian.com',
// Technology
'https://www.github.com',
'https://www.stackoverflow.com',
'https://www.microsoft.com',
'https://www.apple.com',
'https://www.google.com',
// Banking & Finance
'https://www.chase.com',
'https://www.bankofamerica.com',
'https://www.wellsfargo.com',
'https://www.paypal.com',
'https://www.stripe.com',
// Travel
'https://www.booking.com',
'https://www.expedia.com',
'https://www.airbnb.com',
'https://www.kayak.com',
'https://www.tripadvisor.com',
// Education
'https://www.coursera.org',
'https://www.edx.org',
'https://www.udemy.com',
'https://www.khanacademy.org',
'https://www.mit.edu',
// Healthcare
'https://www.mayoclinic.org',
'https://www.webmd.com',
'https://www.healthline.com',
'https://www.medlineplus.gov',
'https://www.cdc.gov',
// Government
'https://www.usa.gov',
'https://www.whitehouse.gov',
'https://www.congress.gov',
'https://www.supremecourt.gov',
'https://www.irs.gov',
// Entertainment
'https://www.netflix.com',
'https://www.spotify.com',
'https://www.hulu.com',
'https://www.disneyplus.com',
'https://www.hbomax.com'
];
}
/**
* Get random user agent for crawling
*/
getRandomUserAgent() {
return this.config.userAgents[Math.floor(Math.random() * this.config.userAgents.length)];
}
/**
* Save knowledge base to persistent storage
*/
async saveKnowledgeBase() {
try {
// Convert Map to object for storage
const knowledgeData = Object.fromEntries(this.knowledgeBase);
// Save to file or database
// This would integrate with your existing storage system
console.log('💾 Knowledge base saved successfully');
}
catch (error) {
console.error('❌ Failed to save knowledge base:', error);
}
}
/**
* Get learned patterns for a specific domain
*/
getLearnedPatterns(domain) {
return this.knowledgeBase.get(domain) || null;
}
/**
* Get global patterns across all domains
*/
getGlobalPatterns() {
const globalPatterns = {
buttonPatterns: [],
inputPatterns: [],
formPatterns: [],
navigationPatterns: []
};
this.knowledgeBase.forEach((domainData, domain) => {
globalPatterns.buttonPatterns.push(...domainData.buttonPatterns);
globalPatterns.inputPatterns.push(...domainData.inputPatterns);
globalPatterns.formPatterns.push(...domainData.formPatterns);
globalPatterns.navigationPatterns.push(...domainData.navigationPatterns);
});
return globalPatterns;
}
/**
* Get learning statistics
*/
getLearningStats() {
return {
totalWebsites: this.knowledgeBase.size,
totalLearningSessions: this.learningHistory.length,
successfulSessions: this.learningHistory.filter(h => h.success).length,
lastLearningSession: this.learningHistory[this.learningHistory.length - 1]?.timestamp,
knowledgeBaseSize: Array.from(this.knowledgeBase.values()).reduce((acc, val) => acc + val.patterns.length, 0)
};
}
/**
* Delay utility
*/
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
exports.GlobalDOMLearningML = GlobalDOMLearningML;
// Inject helper functions
if (typeof window !== 'undefined') {
window.calculateDepth = (element) => {
let depth = 0;
let current = element;
while (current.parentElement) {
depth++;
current = current.parentElement;
}
return depth;
};
window.getElementSize = (element) => {
const rect = element.getBoundingClientRect();
return { width: rect.width, height: rect.height };
};
window.getElementPosition = (element) => {
const rect = element.getBoundingClientRect();
return { x: rect.left, y: rect.top };
};
window.hasAssociatedLabel = (input) => {
const id = input.getAttribute('id');
if (id) {
return document.querySelector(`label[for="${id}"]`) !== null;
}
return input.closest('label') !== null;
};
window.hasValidationAttributes = (input) => {
return input.hasAttribute('required') ||
input.hasAttribute('pattern') ||
input.hasAttribute('min') ||
input.hasAttribute('max') ||
input.hasAttribute('minlength') ||
input.hasAttribute('maxlength');
};
window.findCommonInputPatterns = (input) => {
const patterns = [];
const type = input.getAttribute('type');
const placeholder = input.getAttribute('placeholder');
if (type === 'email' && placeholder?.toLowerCase().includes('email'))
patterns.push('email_input');
if (type === 'password' && placeholder?.toLowerCase().includes('password'))
patterns.push('password_input');
if (type === 'text' && placeholder?.toLowerCase().includes('name'))
patterns.push('name_input');
if (type === 'tel' && placeholder?.toLowerCase().includes('phone'))
patterns.push('phone_input');
return patterns;
};
window.getButtonSize = (button) => {
const className = button.className.toLowerCase();
if (className.includes('btn-lg') || className.includes('large'))
return 'large';
if (className.includes('btn-sm') || className.includes('small'))
return 'small';
return 'medium';
};
}
//# sourceMappingURL=global-dom-learning-ml.js.map
;