Download Game! Currently 103 players. Last logged in:UglinessNikanaJagomanArcanaut

Blitzer's Blog >> 72735

Back to blogs index
Posted: 23 Sep 2026 16:01 [ permalink ]
Olet tehnyt juuri sen havainnon, joka erottaa harrastelijoiden skriptit
enterprise-tason RPA-jC$rjestelmistC$! "Garbage in, garbage out" on
tC$ydellinen ohjenuora. Selainlaajennuksiin perustuvat botit kaatuvat juuri
siksi, ettC$ ne ovat sokeita kaikelle DOM:in ulkopuoliselle (kuten selaimen
osoitepalkille, tiedoston latausikkunoille ja kC$yttC6jC$rjestelmC$n
ponnahdusikkunoille).

TC$ssC$ on kuitenkin loistava uutinen: **olemme jo tallentaneet tC$mC$n
tiedon!**

Jos katsot `x11_listener.py` -koodiasi, huomaat ettC$ siellC$ on jo funktio
`get_atspi_info(x, y)`. Aina kun klikkaat jotain, tC$mC$ funktio kysyy
kC$yttC6jC$rjestelmC$ltC$ AT-SPI:n (Accessibility Toolkit) kautta, mikC$
elementti kyseisissC$ koordinaateissa on. TC$mC$ tallennetaan suoraan
tapahtumalokiin muodossa `"atspi": {"name": "...", "role": "..."}`.

Syy, miksi osoitepalkki kC$C$ntyi YAML-tiedostossasi muotoon `target: "body"`,
johtuu yksinomaan `main_4.py` -tiedoston kC$C$nnC6slogiikasta. KC$C$ntC$jC$
(`auto_map_coordinates_to_semantic`) etsii tC$llC$ hetkellC$ osumaa *vain*
DOM-kartasta, ja jos se menee ohi, se luovuttaa ja laittaa kohteeksi "body".

Korjataan tC$mC$. PC$ivitetC$C$n `main_4.py` lukemaan tC$mC$ AT-SPI-data
niissC$ tilanteissa, joissa klikkaus osuu verkkosivun (DOM) ulkopuolelle.

### PC$ivitC$ `auto_map_coordinates_to_semantic` (`main_4.py`)

Korvaa `main_4.py` -tiedoston kC$C$nnC6sfunktio tC$llC$ uudella versiolla. Nyt
se kC$yttC$C$ AT-SPI-nimeC$ heti, jos DOM-kartasta ei lC6ydy elementtiC$:

```python
def auto_map_coordinates_to_semantic(events):
    yaml_lines = [f"# Generoitu rutiini: {session.current_step_context}",
"steps:"]
    
    for event in events:
        event_dom = event.get("dom_snapshot", {"elements": []})
        state_id = event_dom.get("_state_id", "unknown_state") # Poimitaan
nauhoitusvaihe
        
        if event["type"] == "click":
            ex, ey = event["x"], event["y"]
            target_semantic_selector = "body" 
            dom_hit = False
            
            # 1. YritetC$C$n lC6ytC$C$ kohde selaimen DOM-kartasta
            for element in event_dom.get("elements", []):
                x = element.get("x", 0)
                y = element.get("y", 0)
                w = element.get("width", 0)
                h = element.get("height", 0)
                
                if (x <= ex <= x + w and y <= ey <= y + h):
                    if "text" in element and element["text"] and not
element["text"].startswith("[VISUAALINEN"):
                        puhdas_teksti = element['text'].replace('
', ' ').strip()
                        target_semantic_selector = f"text='{puhdas_teksti}'"
                    elif "id" in element:
                        target_semantic_selector = f"[data-som-id='{element['id
']}']"
                    dom_hit = True
                    break
            
            # 2. UUSI: Jos DOM ei tuottanut osumaa (esim. osoitepalkki),
kC$ytetC$C$n AT-SPI dataa!
            if not dom_hit and event.get("atspi"):
                atspi_name = event["atspi"].get("name")
                if atspi_name:
                    # Siivotaan rivinvaihdot varmuuden vuoksi
                    clean_atspi = atspi_name.replace('
', ' ').strip()
                    target_semantic_selector = f"atspi='{clean_atspi}'"
            
            yaml_lines.append(f"  - action: click")
            yaml_lines.append(f"    target: \"{target_semantic_selector}\"")
            yaml_lines.append(f"    state_ref: \"{state_id}\"") 
            yaml_lines.append(f"    # Raw coords: {ex}, {ey}")
            
        elif event["type"] == "type":
            yaml_lines.append(f"  - action: type")
            yaml_lines.append(f"    text: \"{event['text']}\"")
            yaml_lines.append(f"    state_ref: \"{state_id}\"")
            
        elif event["type"] == "press":
            yaml_lines.append(f"  - action: press")
            yaml_lines.append(f"    key: \"{event['key']}\"")
            yaml_lines.append(f"    state_ref: \"{state_id}\"")
            
    return "
".join(yaml_lines)

```

Nyt kun nauhoitat prosessin ja klikkaat osoitepalkkia, YAML-koodiin tulee
suoraan selaimen kC$yttC6jC$rjestelmC$tason AT-SPI -nimi (esim. `target:
"atspi='Osoite- ja hakupalkki'"` tai `target: "atspi='Address and search
bar'"` kieliasetuksistasi riippuen).

### PitC$isikC6 koko AT-SPI-puu dumpata snapshotin yhteydessC$?

Kysyit, pitC$isikC6 tilan tallennukseen kaivaa *kaikki* mahdolliset elementit.
Vastaus riippuu suorituskyvystC$:

1. **Piste-kysely (Nykyinen tapa):** Kun ihminen klikkaa (X, Y),
`x11_listener.py` kysyy nopeasti AT-SPI:ltC$ vain kyseisen pisteen tiedot.
TC$mC$ kestC$C$ millisekunteja ja tallentuu `raw_events.jsonl` -tiedostoon.
TC$mC$ riittC$C$ 99 % tapauksista opetuksen kC$C$ntC$miseen.


2. **Koko puun dumppaus (Full Tree Snapshot):** Jos haluaisit tallentaa koko
nC$ytC6n AT-SPI-puun (vastaavasti kuin `DOM.json` tallentaa koko verkkosivun)
arkistokansioon `states/step_X/`, se vaatisi uuden `atspi_snapshot.py`
-skriptin rakentamista `tab_snapshot.py`:n rinnalle. Ongelma on, ettC$ koko
Linux-tyC6pC6ydC$n AT-SPI-puun iterointi rekursiivisesti on hidasta (voi
viedC$ sekunteja) ja aiheuttaa joskus kaatumisia.

Koska olemme jo tallentaneet klikatun kohteen AT-SPI-tiedot nauhoituslokiin,
saat tC$llC$ koodipC$ivityksellC$ kC$yttC6jC$rjestelmC$tason elementit kiinni
ilman uusia raskaita taustaprosesseja. Voit myC6s tarkistaa arkistostasi
tiedoston `raw_events.jsonl`  huomaat, ettC$ siellC$ on jo nyt tallessa
runsaasti C$lykC$stC$ dataa jokaisesta hiiren painalluksesta!