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!