🤖 Slido Voting Bot — Multi-Browser-Automation mit globalem OCR

4 parallele Chrome-Fenster, globaler Screenshot, EasyOCR-Positionserkennung, parallele Klicks via Threading. 50 Votes in 60 Sekunden — technische Demonstration von Browser-Automation.

PythonSeleniumEasyOCRpyautoguiThreadingChrome

🚀 Browser-Automation in Perfektion — 4 Fenster, ein globaler OCR-Check

Vereinbaren Sie ein unverbindliches Strategiegespräch

📞 02406 803 7603 ✉️ info@computerkumpel.de

📊 Technische Architektur

Fortgeschrittene Browser-Automation: Statt einzelner Element-Selektoren nutzt dieser Bot globale Screenshots + OCR, um UI-Elemente zu finden — unabhängig vom DOM. 4 parallele Chrome-Instanzen für maximale Geschwindigkeit.

🖥️
4 Browser parallel
Chrome-Instanzen im 2x2-Grid (je 900×550px), 75% Zoom für optimale OCR-Erkennung. ThreadPoolExecutor für parallelen Start.
👁️
Global OCR
EasyOCR scannt ganzen Bildschirm. Erkennt Zielnamen („Marcel") und Send-Buttons. Position-Caching vermeidet wiederholte Scans.
Parallele Klicks
Threading.Thread pro Klick-Ziel. Alle 4 Browser gleichzeitig bedienen. pyautogui.click() mit gecachten Koordinaten.
🔄
Runden-System
Runde 1: Position-Learning mit OCR. Runden 2-n: gecachte Positionen. Browser-Neustart pro Runde für Clean State.

⚙️ Ablauf pro Runde

1
🚀

Browser starten

4 Chrome via ThreadPoolExecutor. 75% Zoom, incognito, keine Extensions. Warten auf Radio-Buttons.

2
📸

OCR-Scan

pyautogui.screenshot() des Gesamtbildschirms. EasyOCR scannt nach Namen und Send-Buttons.

3
👆

Parallele Klicks

4 Threads klicken gleichzeitig alle gefundenen Positionen. 2.5s warten, dann Send-Buttons klicken.

4
🚪

Cleanup

Alle Browser parallel schließen. Bei Zielerreichung oder Zeitlimit (55s) abbrechen.

💻 Code — Multi-Browser Grid Setup

2x2 Grid mit optimierten Chrome-Instanzen

class UltimateSpeedBot:
    def __init__(self, target_name="Marcel", 
                 vote_count=50, url=None):
        self.target_name = target_name
        self.vote_count = vote_count
        self.browser_count = 4
        self.rows, self.cols = 2, 2
        self.window_width = 900
        self.window_height = 550
        self.gap = 50
        self.cached_marcel_positions = []
        self.cached_send_positions = []
    
    def create_optimized_browser_grid(self, index):
        chrome_options = Options()
        chrome_options.add_argument("--incognito")
        chrome_options.add_argument("--no-sandbox")
        chrome_options.add_argument("--disable-gpu")
        chrome_options.add_argument("--disable-extensions")
        
        # 75% Zoom = kritisch für OCR-Erkennung
        chrome_options.add_argument(
            "--force-device-scale-factor=0.75")
        
        # Anti-Detection
        chrome_options.add_experimental_option(
            "excludeSwitches", ["enable-automation"])
        chrome_options.add_experimental_option(
            'useAutomationExtension', False)
        
        # Position im Grid berechnen
        row, col = index // self.cols, index % self.cols
        x = col * (self.window_width + self.gap)
        y = row * (self.window_height + self.gap)
        
        service = Service(ChromeDriverManager().install())
        driver = webdriver.Chrome(service=service, 
                                  options=chrome_options)
        driver.set_window_position(x, y)
        driver.set_window_size(self.window_width, 
                               self.window_height)
        driver.implicitly_wait(2)
        driver.set_page_load_timeout(10)
        
        return driver

💻 Code — Globales OCR mit EasyOCR

Gesamtbildschirm-Screenshot + EasyOCR Erkennung

def learn_positions_from_global_screenshot(self):
    """Lernt alle Ziel-Positionen aus globalem Screenshot"""
    time.sleep(3)  # UI-Stabilisierung
    
    screenshot = pyautogui.screenshot()
    screenshot.save("ultimate_global_screenshot.png")
    
    import easyocr
    reader = easyocr.Reader(['de', 'en'])
    
    # OCR auf gesamtem Bildschirm
    results = reader.readtext("ultimate_global_screenshot.png")
    
    for (bbox, text, confidence) in results:
        if confidence > 0.4:
            text_lower = text.lower()
            
            # Zielnamen finden
            if self.target_name.lower() in text_lower:
                top_left = bbox[0]
                bottom_right = bbox[2]
                center_x = int((top_left[0] + bottom_right[0]) / 2)
                center_y = int((top_left[1] + bottom_right[1]) / 2)
                
                self.cached_marcel_positions.append({
                    'x': center_x, 'y': center_y,
                    'text': text, 'confidence': confidence
                })
            
            # Send-Buttons finden
            elif 'send' in text_lower:
                top_left = bbox[0]
                bottom_right = bbox[2]
                center_x = int((top_left[0] + bottom_right[0]) / 2)
                center_y = int((top_left[1] + bottom_right[1]) / 2)
                
                self.cached_send_positions.append({
                    'x': center_x, 'y': center_y,
                    'text': text, 'confidence': confidence
                })
    
    return len(self.cached_marcel_positions) > 0

💻 Code — Parallele Klicks & Runden-Management

Thread-basierte parallele Klicks auf alle Positionen

def click_all_marcel_positions(self):
    """Klickt alle gecachten Positionen parallel"""
    if not self.cached_marcel_positions:
        return 0
    
    results = []
    threads = []
    
    def threaded_click(pos, index):
        try:
            pyautogui.click(pos['x'], pos['y'])
            results.append((index, True))
        except:
            results.append((index, False))
    
    for i, pos in enumerate(self.cached_marcel_positions):
        t = threading.Thread(target=threaded_click,
                            args=(pos, i))
        threads.append(t)
        t.start()
    
    for t in threads:
        t.join()
    
    return sum(1 for _, ok in results if ok)

# Haupt-Challenge-Loop
def run_ultimate_speed_challenge(self):
    total_start = time.time()
    
    # Runde 1: Position-Learning mit OCR
    self.create_all_browsers_fast()
    self.learn_positions_from_global_screenshot()
    marcel_success = self.click_all_marcel_positions()
    
    time.sleep(2.5)  # Send-Button-Aktivierung
    self.learn_send_positions_after_marcel()
    send_success = self.click_all_send_positions()
    self.success_count += min(marcel_success, send_success)
    self.close_all_browsers_fast()
    
    # Runden 2-n: gecachte Positionen nutzen
    remaining = self.vote_count - self.success_count
    rounds = (remaining + len(self.cached_marcel_positions) 
              - 1) // len(self.cached_marcel_positions)
    
    for rnd in range(2, rounds + 2):
        if time.time() - total_start > 55:
            break  # 60-Sekunden-Grenze
        
        self.create_all_browsers_fast()
        m_ok = self.click_all_marcel_positions()
        time.sleep(1.5)
        s_ok = self.click_all_send_positions()
        self.success_count += min(m_ok, s_ok)
        self.close_all_browsers_fast()

🎯 Strategische Erkenntnisse

👁️

OCR statt DOM-Selektoren

DOM-Selektoren brechen bei jedem UI-Update. OCR-basierte Erkennung funktioniert visuell — framework-agnostisch, update-sicher.

Visual Automation > DOM-Automation für langfristige Stabilität.

Threading ≠ Multiprocessing

Für I/O-gebundene Tasks (Klicks, Screenshots) ist Threading schneller als Multiprocessing — kein Serialisierungs-Overhead.

Thread-Pool für UI-Automation; Process-Pool für CPU-intensive Tasks.

🔄

Caching = Geschwindigkeit

Erste Runde: OCR-Learning (2s). Folgerunden: gecachte Positionen (0.01s). 200x schneller ab Runde 2.

Learn once, execute many — das fundamentale Pattern für Automation.

Browser-Automation für Ihre Prozesse

Ob Formular-Automation, Datenextraktion oder Testing — ich baue Ihre maßgeschneiderte Automation-Lösung. Mit OCR, Selenium oder Playwright.

📞 Jetzt anrufen ✉️ E-Mail senden