Continue work on itb

This commit is contained in:
2024-12-26 17:36:59 +01:00
parent eadd4eeabe
commit 63d1264f5a
10 changed files with 1281 additions and 342 deletions

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python3
import sys
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
import xml.etree.ElementTree as ET
@@ -10,84 +11,15 @@ class ScreenshotGenerator:
options.add_experimental_option("debuggerAddress", f"127.0.0.1:{debug_port}")
self.driver = webdriver.Chrome(options=options)
# Load JavaScript files
js_dir = os.path.join(os.path.dirname(__file__), "..", "js")
self.js_code = ""
for filename in ["viewport.js", "mouse.js", "dom_analyzer.js"]:
with open(os.path.join(js_dir, filename)) as f:
self.js_code += f.read() + "\n"
def get_page_content(self) -> dict:
script = """
function processElement(element) {
// Check if element is actually visible in viewport
const rect = element.getBoundingClientRect();
if (!element.offsetParent && element !== document.body) return null;
if (rect.width === 0 || rect.height === 0) return null;
// Check if element is within viewport bounds
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
if (rect.bottom < 0 || rect.top > viewportHeight ||
rect.right < 0 || rect.left > viewportWidth) {
return null;
}
const styles = window.getComputedStyle(element);
const text = Array.from(element.childNodes)
.filter(node => node.nodeType === Node.TEXT_NODE)
.map(node => node.textContent.trim())
.join(' ');
const interactions = [];
if (element.tagName === 'BUTTON' || element.tagName === 'A' ||
element.getAttribute('role') === 'button' ||
element.getAttribute('onclick') ||
styles.cursor === 'pointer') {
interactions.push('click');
}
if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA' ||
element.getAttribute('contenteditable') === 'true') {
interactions.push('text_input');
const placeholder = element.getAttribute('placeholder');
if (placeholder) interactions.push('placeholder:' + placeholder);
}
if (element.tagName === 'SELECT' ||
element.getAttribute('role') === 'listbox' ||
element.getAttribute('type') === 'checkbox' ||
element.getAttribute('type') === 'radio') {
interactions.push('select');
}
if (element.scrollHeight > element.clientHeight ||
element.scrollWidth > element.clientWidth) {
interactions.push('scroll');
}
const children = Array.from(element.children)
.map(child => processElement(child))
.filter(child => child !== null);
return {
tag: element.tagName.toLowerCase(),
text,
location: {x: Math.round(rect.left), y: Math.round(rect.top)},
size: {width: Math.round(rect.width), height: Math.round(rect.height)},
interactions,
children
};
}
const body = document.body;
return {
viewport: {
scroll_x: window.pageXOffset,
scroll_y: window.pageYOffset,
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
max_scroll_y: Math.max(document.documentElement.scrollHeight - window.innerHeight, 0),
min_scroll_x: Math.max(document.documentElement.scrollLeft, 0)
},
content: body ? processElement(body) : null
};
"""
return self.driver.execute_script(script)
return self.driver.execute_script(self.js_code + "; return analyzePageContent();")
def format_xml(self, xml_str: str) -> str:
root = ET.fromstring(xml_str)