""" Průzkumný skript: zkouší najít strukturovaná data puzzle na dailykillersudoku.com (cage definice, řešení). """ import asyncio import json import sys sys.stdout.reconfigure(encoding="utf-8") from playwright.async_api import async_playwright URL = "https://www.dailykillersudoku.com/puzzle/70000" async def main(): async with async_playwright() as p: browser = await p.chromium.launch(headless=True) context = await browser.new_context(viewport={"width": 1280, "height": 900}) page = await context.new_page() # Zachytávat network requesty api_responses = [] async def on_response(response): url = response.url if any(k in url for k in ["api", "puzzle", "data", "json", "cage", "grid"]): try: body = await response.text() api_responses.append({"url": url, "status": response.status, "body": body[:2000]}) except: api_responses.append({"url": url, "status": response.status, "body": "(could not read)"}) page.on("response", on_response) print(f"Načítám {URL} ...") await page.goto(URL, wait_until="networkidle", timeout=60_000) # 1) Network requesty print("\n=== Zachycené API/data requesty ===") for r in api_responses: print(f"\n URL: {r['url']}") print(f" Status: {r['status']}") if r['body'] and len(r['body']) < 2000: print(f" Body: {r['body'][:500]}") # 2) Globální JS proměnné print("\n=== Globální proměnné ===") globals_check = await page.evaluate("""() => { const names = ['puzzle', 'puzzleData', 'gameData', 'game', 'board', 'grid', 'cages', 'cells', 'solution', 'killerData', 'sudoku', 'level', 'data', 'config', 'state', 'app', 'store', 'vuex', '__NUXT__', '__NEXT_DATA__', 'initialData', 'pageData', 'props', 'serverData']; const found = {}; for (const name of names) { if (typeof window[name] !== 'undefined') { const val = window[name]; found[name] = { type: typeof val, keys: typeof val === 'object' && val !== null ? Object.keys(val).slice(0, 20) : null }; } } return found; }""") print(json.dumps(globals_check, indent=2)) # 3) SVG/Canvas analýza print("\n=== SVG/Canvas elementy ===") svg_info = await page.evaluate("""() => { const svgs = document.querySelectorAll('svg'); const canvases = document.querySelectorAll('canvas'); return { svg_count: svgs.length, canvas_count: canvases.length, svg_ids: Array.from(svgs).map(s => s.id || s.className || '(no id)').slice(0, 5), canvas_ids: Array.from(canvases).map(c => c.id || c.className || '(no id)').slice(0, 5) }; }""") print(json.dumps(svg_info, indent=2)) # 4) Data atributy print("\n=== Elementy s data- atributy ===") data_attrs = await page.evaluate("""() => { const all = document.querySelectorAll('[data-cage], [data-cell], [data-sum], [data-group], [data-value], [data-row], [data-col]'); return { count: all.length, samples: Array.from(all).slice(0, 5).map(el => ({ tag: el.tagName, attrs: Object.fromEntries(Array.from(el.attributes).filter(a => a.name.startsWith('data-')).map(a => [a.name, a.value])) })) }; }""") print(json.dumps(data_attrs, indent=2)) # 5) Tabulky a mřížky print("\n=== Tabulky / grid struktury ===") tables = await page.evaluate("""() => { const tables = document.querySelectorAll('table'); const grids = document.querySelectorAll('[class*=grid], [class*=puzzle], [class*=board], [class*=cage], [class*=cell], [id*=grid], [id*=puzzle], [id*=board]'); return { table_count: tables.length, grid_elements: Array.from(grids).slice(0, 10).map(el => ({ tag: el.tagName, id: el.id, class: el.className.toString().substring(0, 100), children: el.children.length })) }; }""") print(json.dumps(tables, indent=2)) # 6) Script tagy s daty print("\n=== Script tagy s daty ===") scripts = await page.evaluate("""() => { const scripts = document.querySelectorAll('script'); const results = []; for (const s of scripts) { const text = s.textContent || ''; if (text.length > 10 && text.length < 50000) { const keywords = ['puzzle', 'cage', 'cell', 'grid', 'solution', 'board', 'sum']; const found = keywords.filter(k => text.toLowerCase().includes(k)); if (found.length > 0) { results.push({ keywords: found, length: text.length, snippet: text.substring(0, 500) }); } } } return results; }""") print(json.dumps(scripts, indent=2, ensure_ascii=False)[:5000]) # 7) Vue/React/Angular state print("\n=== Framework state ===") framework = await page.evaluate("""() => { // Vue const vueEl = document.querySelector('[data-v-app]') || document.querySelector('#app') || document.querySelector('#__nuxt'); let vueData = null; if (vueEl && vueEl.__vue_app__) { vueData = 'Vue 3 app found'; } else if (vueEl && vueEl.__vue__) { vueData = 'Vue 2 app found'; try { const d = vueEl.__vue__.$data; vueData = {type: 'Vue 2', keys: Object.keys(d)}; } catch(e) {} } // __NUXT__ if (typeof __NUXT__ !== 'undefined') { try { vueData = {type: 'Nuxt', keys: Object.keys(__NUXT__)}; } catch(e) {} } // React let reactData = null; const reactRoot = document.querySelector('#__next') || document.querySelector('#root'); if (reactRoot) { const fiberKey = Object.keys(reactRoot).find(k => k.startsWith('__reactFiber') || k.startsWith('__reactInternalInstance')); if (fiberKey) reactData = 'React app found'; } return {vue: vueData, react: reactData}; }""") print(json.dumps(framework, indent=2)) # 8) Všechny window properties (custom) print("\n=== Custom window properties ===") custom_props = await page.evaluate("""() => { const iframe = document.createElement('iframe'); document.body.appendChild(iframe); const defaultKeys = new Set(Object.keys(iframe.contentWindow)); document.body.removeChild(iframe); const custom = Object.keys(window).filter(k => !defaultKeys.has(k) && !k.startsWith('__')); return custom.slice(0, 50); }""") print(json.dumps(custom_props, indent=2)) await browser.close() if __name__ == "__main__": asyncio.run(main())