RPA-verktyg – Wiki

Referensdokumentation för det interna RPA-verktyget (Playwright + webbaserad flödesbyggare). Öppna den här sidan lokalt i en webbläsare när du bygger flöden. Se README.md för installation och kom-igång-instruktioner – den här sidan är en djupare referens över alla stegtyper, villkor och mekanismer.

Översikt

Ett flöde är en JSON-fil (data/flows/<namn>.json) i grafform: {"format":"graph", "nodes":[…], "edges":[…], "start":"<nod-id>"}. Varje nod har ett id, en type och typ-specifika fält (platt – ingen nästling). Kanterna bestämmer körordningen. Webb-UI:t (python run_webui.py, http://127.0.0.1:8765) bygger grafen visuellt – dra kablar mellan noderna.

Gamla flöden i det nästlade {"steps":[…]}-formatet läses fortfarande; de migreras automatiskt till grafform vid inläsning och skrivs om vid nästa sparning.

Motorn är rpa/graph_engine.pyrun_graph() börjar på startnoden och följer kanterna. Efter en vanlig nod följs handtaget out. if-noder har ett handtag per gren (case0, case1, … + else); loop-noder har each (en gång per varv) och done (efteråt), och kroppens sista nod kopplas tillbaka till loop-nodens in. rpa/flow_engine.py är kvar som omslag och kör de enskilda stegen.

Kom igång

  1. python -m venv .venv & pip install -r requirements.txt & python -m playwright install chromium
  2. python -m rpa.codegen <url> för att hitta exakta selectors mot en riktig, inloggad sida (öppnar en inspector, ingen gissning behövs).
  3. python run_webui.py och öppna http://127.0.0.1:8765 för att bygga flödet.
  4. "Kör flöde" sparar och kör flödet i en synlig webbläsare, med live-logg och en variabelpanel.

Fullständiga instruktioner finns i README.md i projektroten.

Stegreferens

by-fältet (var förekommande) styr hur ett element hittas: text (skiftlägesokänslig delsträng), css (CSS-selector, stödjer Playwrights utökningar som :text-is(), :has-text(), :scope) eller role (ARIA-roll + tillgängligt namn). scope är page (hela sidan, standard) eller item (bara inom aktuell loop-post). nth väljer vilken matchning (0 = första).

CSS-selektorer: flera varianter i samma sträng

En css-selektor kan vara en kommaseparerad lista – varje del är en egen fullständig selektor, och elementet matchar om någon del gör det. Praktiskt för att täcka flera filändelser:

a[href$=".png"], a[href$=".jpg"], a[href$=".jpeg"], a[href$=".gif"]
  • Skiftläge: attributvärden matchas skiftlägeskänsligt – .JPG matchar inte .jpg. Lägg till i-flaggan (stöds i Chromium): a[href$=".jpg" i].
  • $= vs *=: $=".png" kräver att värdet slutar.png – matchar inte bild.png?token=…. Använd *=".png" (innehåller) då.
  • Ofta stabilast: matcha på en ikon-/typklass i stället för filändelsen, t.ex. .ids-icon-file-image (alla bildtyper) eller .ids-icon-file-pdf – en selektor, oberoende av skiftläge och query-strängar.

Samma kommalista fungerar överallt där by=css gäller, inklusive if-villkorens value.

Navigation & väntan

goto Gå till URL

  • url – adressen att navigera till

wait Vänta (sekunder)

  • seconds – fast paus

wait_for_load Vänta på sidladdning

Väntar på domcontentloaded. Inga fält.

go_back Gå tillbaka

Webbläsarens "bakåt" (historik). Inga fält. Praktiskt efter att ha klickat in på en post från en lista (t.ex. för att öppna en detaljvy), för att komma tillbaka till listan och fortsätta en loop.

wait_for_login Vänta på inloggning

  • timeout – sekunder (default 180)

Pollar sidan tills någon text i config.LOGGED_IN_INDICATORS syns (eller ger upp). Fungerar för BankID, 2FA eller annan manuell inloggning – verktyget bryr sig bara om att en inloggad-indikator dyker upp, inte om hur du loggade in.

wait_for_selector Vänta på element

  • by, value, role?, scope?, nth?
  • timeout – sekunder (default 15)

Sidinteraktion

click Klicka

  • by, value, role?, scope?, nth?

type Skriv i textfält

  • by, value, role?, scope?, nth?
  • text – texten som skrivs (stödjer {variabel})

press_key Tryck tangent

  • key – t.ex. Enter, Tab, Escape
  • value tomt → tangenten trycks mot hela sidan. Annars by/value/role/scope/nth för att trycka på ett specifikt element.

select_option Välj i dropdown

  • by, value, role?, scope?, nth?
  • option – synlig text på alternativet

check Kryssa checkbox/radio

  • by, value, role?, scope?, nth?
  • checkedtrue (kryssa i, default) eller false (kryssa ur)

download Ladda ner

  • by, value, role?, scope?, nth?

Klickar och sparar den nedladdade filen i data/downloads/. Misslyckad nedladdning loggas men avbryter inte flödet.

save_attachment Ladda ner bilaga

  • by, value, role?, scope?, nth? – pekar ut länken (eller ett element som innehåller en <a>). I en loop över bilagerader: by=css, scope=item, value=a[href].
  • filename? – filnamn i data/downloads/ (tomt = tas från filens URL; stödjer {variabel}). Krock döps om till namn (2).ext.
  • var? – lägger den sparade sökvägen i en listvariabel (så flera bilagor samlas i en lista)
  • timeout? – sekunder (default 15)

Hittar en <a> och: har den en riktig href (t.ex. PDF-bilagor) hämtas filen direkt via webbläsarens session (behåller inloggningen, ingen ny flik/skrivardialog). Är det en javascript:-länk (t.ex. bild­bilagor) klickas den i stället – öppnas då en popup med en nedladdningslänk följer steget den och hämtar filen därifrån (popupens URL, en fil-/nedladdningslänk i den, eller ett klick som startar nedladdningen). 0 bilagor → list ger antal 0 och loopen kör inga varv. Misslyckad hämtning loggas men avbryter inte flödet.

Olika hantering för PDF vs. bild: lägg ett if i loopen med villkoret element_exists, by=css, scope=item, value .ids-icon-file-pdf (eller a[href$=".pdf"]) för PDF-grenen och else för bild. Behövs oftast inte – ett enda save_attachment klarar båda – men gör det möjligt att t.ex. bara spara PDF:er, eller döpa dem olika.

list            value "etj-file-attachment-link", var "bilaga_element"
loop over "bilaga_element":
  save_attachment  by=css  scope=item  value="a[href]"  var="bilagor"
save_var        var "bilagor", filename "bilagor.json"
run_script      scripts/merge_and_print.py
                --files-from bilagor.json --out data/downloads/klar.pdf --print

capture_pdf Fånga PDF (skriv ut-knapp)

  • by, value, role?, scope?, nth? – triggern att klicka (t.ex. "SKRIV UT"). Lämna value tomt för att fånga sidan som redan visas.
  • filename? – filnamn i data/downloads/ (default utskrift.pdf, stödjer {variabel})
  • var? – variabel att lägga den sparade sökvägen i (praktiskt för ett efterföljande run_script-steg)
  • timeout? – sekunder att vänta på ett PDF-nätverkssvar (default 15)

För "Skriv ut"-knappar som öppnar webbläsarens skrivardialog i stället för att ladda ner en fil. Steget neutraliserar window.print, klickar ev. triggern och fångar PDF:en i tur och ordning via: (1) ett PDF-nätverkssvar, (2) en inbäddad PDF i sidan (embed/iframe/object/a med .pdf), (3) Chrome printToPDF av sidan som den ser ut (fungerar även i icke-headless läge). Misslyckad fångst loggas men avbryter inte flödet.

screenshot Ta skärmdump

  • name? – filnamn utan .png (default screenshot)

Sparas i data/screenshots/.

Variabler & data

set_var Sätt variabel

  • var, text (stödjer {variabel})

increment Öka variabel

  • var – variabeln att öka
  • by? – steg (default 1, negativt värde minskar)

Saknad eller icke-numerisk variabel behandlas som 0. Lägg ett sådant steg sist i en loop så blir {var} 1, 2, 3 … och kan användas för att särskilja filnamn (capture_pdf filename stödjer {variabel}). Behöver du bara varvnumret räcker loopens inbyggda index_var (default {index}).

clear_var Nollställ variabel

  • var – variabeln att ta bort

Nästa list_append / save_attachment / extract_row skapar den på nytt som tom lista. Lägg först i en loop för att nollställa en samlar-lista per varv (t.ex. bilagor per ärende).

extract_text Läs text till variabel

  • by, value, role?, scope?, nth?, var

Läser ett elements text till en variabel (skalärt textvärde).

extract_row Extrahera rad (flera kolumner)

  • var – listvariabel att lägga raden i
  • scope? – normalt item (körs inuti en loop)
  • fields – lista av {name, by, value, role?}, ett per kolumn

Läser flera namngivna fält (celler) från aktuell post i ett svep och lägger dem som en rad-post (dict) i listvariabeln – motsvarar Power Automates "Extract data from table". Ger strukturerade kolumner istället för en textklump, vilket gör att save_var skriver riktiga kolumnrubriker i CSV (fältnamnen) och att en enskild kolumn kan refereras senare med {item.Kolumnnamn} (se interpolering).

{
  "type": "extract_row",
  "var": "Tabell_lista",
  "scope": "item",
  "fields": [
    { "name": "Uppdaterat", "by": "css", "value": "td:nth-child(1)" },
    { "name": "Ärendetyp",  "by": "css", "value": "td:nth-child(2)" },
    { "name": "Status",     "by": "css", "value": "td:nth-child(6)" }
  ]
}

list_append Lägg till i lista

  • var – listvariabel (skapas automatiskt)
  • Antingen by/value/role/scope/nth (läser elementets text) eller text (literalt värde, stödjer {variabel}) om value lämnas tomt

Lägger till ett textvärde per anrop – jämför med extract_row som lägger till en hel namngiven rad i ett anrop.

save_var Spara variabel (JSON/CSV)

  • var – variabeln att spara
  • filename – i data/exports/, inga sökvägar tillåtna
  • format?json/csv, gissas från filändelsen om tomt
  • mode?overwrite (default) eller append

CSV: en lista av dicts (t.ex. från extract_row) ger riktiga kolumnrubriker från dict-nycklarna. En lista av vanliga textvärden (t.ex. från list_append med literalt värde) får en enda kolumn med rubriken value – det är inte en bugg, CSV kräver en kolumnrubrik och "value" är namnet på den enda kolumnen när posterna saknar egna fältnamn. Använd extract_row om du vill ha meningsfulla kolumnnamn istället.

load_var Läs in variabel (JSON/CSV)

  • var, filename (samma regler som save_var)

CSV med en enda kolumn "value" läses tillbaka som en lista av textvärden; CSV med flera kolumner läses tillbaka som en lista av dicts (samma struktur som extract_row producerar) – round-trip fungerar alltså sömlöst i båda riktningarna.

run_script Kör Python-script

  • path – relativ mot projektroten, eller absolut
  • args? – mellanslagsseparerade argument
  • timeout? – sekunder (default 60)
  • var? – sparar scriptets stdout (JSON-tolkat om möjligt, annars text)

Loggar stdout/stderr rad för rad. Flödet stoppas om scriptet avslutar med en felkod.

Kör med samma rättigheter som webui-processen – bara för egna, betrodda script.

list Lista poster

  • value – CSS-selector som matchar flera element
  • var – variabeln att spara resultatet i

Sparar {selector, count, preview} i variabeln – preview är textinnehållet i de tre första träffarna, bara för att kunna sanity-checka selectorn i variabelpanelen innan man bygger en hel loop kring den. Loop bryr sig bara om selector/count.

ocr_read OCR – läs text ur bild/PDF

  • sourcepdf (fil i data/downloads/), window (fönstertitel-regex), region (x/y/w/h skärmkoordinater) eller image (fil)
  • var – variabeln att spara texten i
  • pattern? – regex; namngiven grupp (?P<value>…) annars hela träffen
  • near? / near_mode? – returnera värdet same_line (efter en etikett) eller below (raden under)
  • lang? – OCR-språk, default sv-SE

Windows-only (winocr = Windows.Media.Ocr + pymupdf för PDF). Kräver att OCR-språket är installerat i Windows – annars ett fel med exakt DISM-kommandot. En PDF med textlager läses direkt utan OCR.

lookup Slå upp i tabell

  • from_var – en variabel som håller en JSON-map (från Läs in variabel); punktnotation cfg.elvis.tabell går bra
  • file – …eller en JSON-fil i data/exports/
  • key – nyckel att slå upp, stödjer {variabel} (t.ex. {grupp}|{spec})
  • var – resultatet (kan vara ett objekt → {var.fält} funkar sen)
  • ci? – skiftlägesokänsligt (default på); on_missing?error / empty / ett defaultvärde

merge_json Skriv nyckel till JSON-fil

  • file – JSON-fil i data/exports/ (skapas om den saknas)
  • key / valuedata[key] = value, båda stödjer {variabel}

För kom-ihåg-tabeller: fråga användaren om ett värde med prompt och spara det här, så finns det nästa körning (läs tillbaka med Läs in variabel + lookup).

read_url Läs aktuell URL

  • var – aktuell sidas URL
  • pattern? – regex-utplock, t.ex. ett ärende-id ur adressen

Kontrollflöde

prompt Fråga användaren (paus)

  • modeconfirm (OK/Avbryt; Avbryt stoppar flödet), input (ett textfält → var), fields (visa de angivna variablerna redigerbara)
  • message – text, stödjer {variabel}
  • fields? – komma-separerade variabelnamn (för mode=fields)

Pausar körningen och visar en ruta på skärmen (egen process). fields är till för att låta användaren rätta OCR-fel innan värdena skrivs vidare.

stop Stoppa flödet

  • message – felmeddelande, stödjer {variabel}

Avbryter körningen (t.ex. när ett ärende inte kan hanteras mekaniskt).

loop Loop (för varje post)

  • over – variabelnamn att loopa över
  • item_var? – variabelnamn för aktuellt värde vid loop över en lista (default item)
  • index_var? – variabelnamn för varvräknaren 1, 2, 3 … (default index); sätts oavsett looptyp och kan användas som {index} i t.ex. filnamn

Utgångar: each (körs en gång per post, sätter item/index) och done (efter sista varvet). Kroppens sista nod måste ha en kant tillbaka till loop-nodens in – annars körs varv 0 en gång och done nås aldrig. Se Loop: DOM vs. lista för de två over-lägena.

if Om / annars om / annars

  • branches – lista av {condition}, i ordning (första sanna vinner)

Utgångar: case0, case1, … (en per gren) samt else (ingen gren matchade). Koppla varje grens noder till respektive utgång. Matchar ingen gren och det saknas en else-kant tar den vägen slut. Se Villkor.

call_flow Anropa subflöde

  • target – ett externt sparat flödesnamn, ELLER #<subflow-id> för en lokal subgraf i samma fil
  • in – lista av {name, value}; name = subflödets indata, value stödjer {variabel}
  • out – lista av {from, to}; kopierar subflödets slutvariabel from till anroparens variabel to

Kör ett annat flöde som ett steg (vanliga handtag in/out). Subflödet får en egen tom variabel-namnrymd som seedas ur in (och subflödets deklarerade inputs-default); bara det du listar i out följer med tillbaka. Samma webbläsare/ flik och inställningar som anroparen. Cirkulära anrop (A→B→A) och för djup kedja avbryts med FlowError. Se Subflöden & flikar.

Universella fält (alla noder)

  • enabledfalse hoppar över noden (kryssruta i UI:t); körningen fortsätter via out.
  • label – valfritt namn på noden (visas i körloggen).
  • on_error"stop" (default) avbryter körningen om noden misslyckas/får timeout; "continue" loggar felet och går vidare. Väljs i listan bredvid etikettfältet.

jump_to_label finns inte längre – rita en kant i stället.

Villkor (If)

if-noden utvärderar branches i ordning – första grenen vars condition är sann följer sin case-utgång och resten hoppas över. Ingen gren sann → else-utgången följs om den är kopplad, annars fortsätter flödet till nästa steg.

kindFältBetyder
element_existsby, value, role?, scope?, nth?Sant om selectorn matchar minst ett element
element_not_existssamma som ovanSant om selectorn INTE matchar något
var_equalsvar, textSant om variabelns textvärde är exakt text
var_not_equalsvar, textSant om variabelns textvärde INTE är text
var_containsvar, textSant om text finns som delsträng i variabeln
Playwrights CSS-utökning :text-is("...") (exakt, skiftlägeskänslig matchning) är ofta bättre än by=text (skiftlägesokänslig delsträng) när du vill särskilja t.ex. en cell som är exakt "Tilldelat" från en som innehåller "Automatiskt tilldelat".
{
  "id": "kollaTilldelad",
  "type": "if",
  "branches": [
    {
      "condition": {
        "kind": "element_not_exists",
        "by": "css", "scope": "item",
        "value": ":text-is(\"Tilldelat\")"
      }
    }
  ]
}
// kant kollaTilldelad --case0--> (noderna som bara ska köras för rader som INTE
// redan är Tilldelat), och deras sista nod --out--> tillbaka till loopens in.

Variabler i text ({variabelnamn})

Följande fält stödjer {variabelnamn}, ersatt med variabelns textvärde vid körning:

  • by=text/by=role sökvärden (i alla steg som har dem)
  • type-stegets text
  • set_var-stegets text
  • list_append-stegets literala text (när value är tomt)
  • capture_pdf-stegets filename (undantaget – övriga stegs filnamn interpoleras inte)

Fungerar INTE i CSS-selectors (by=css), URL:er eller filnamn (utom capture_pdf, se ovan) – där tas {...} bokstavligt.

Punkt-notation: {variabel.fält} läser ett namngivet fält ur en dict-variabel (t.ex. en rad från extract_row eller en inläst flerkolumns-CSV). Okänt variabel- eller fältnamn lämnas oersatt i texten (bra för att upptäcka stavfel – flödet kraschar inte, men texten blir synligt fel i loggen).

// item = {"Ärendetyp": "Egenremiss", "Status": "Tilldelat"}
"{item.Ärendetyp}"  →  "Egenremiss"
"{item}"            →  '{"Ärendetyp": "Egenremiss", "Status": "Tilldelat"}'  (hela dicten som JSON)
"{okänd_variabel}"  →  "{okänd_variabel}"  (oersatt, ingen krasch)

Loop: DOM vs. lista

loop stödjer två helt olika typer av over-variabel:

DOM-loop (från "Lista poster")Listloop (vanlig lista)
Variabelns form {selector, count, preview} En vanlig JSON-array, t.ex. från list_append eller load_var
Vad varje varv ger Ett riktigt DOM-element (aktuell rad) – scope=item i inre steg söker inom det Inget DOM-element; aktuellt värde läggs i variabeln item (eller item_var)
Hitta rätt element på sidan Automatiskt (scope=item) Måste sökas upp manuellt, t.ex. med by=text, value="{item.Namn}"
Innan detta stöd fanns kunde loop bara hantera "Lista poster"-resultat – att sätta over till en vanlig listvariabel gav TypeError: list indices must be integers or slices, not str. Det är åtgärdat; loop-steget avgör nu automatiskt vilken typ variabeln har.

Klicka på ett element i (eller på) aktuell loop-rad

I en DOM-loop söker scope=item inom aktuell rad. Oftast vill du klicka ett barn-element – en länk, en cell, en knapp – inte hela raden (rader har sällan någon klick-hanterare):

list             value "table.ids-data-table tbody tr", var "rader"
loop over "rader":
  click          by=css  scope=item  value="a"                (länken i raden, t.ex. filnamnet)
  click          by=css  scope=item  value="td:nth-child(5)"  (en viss cell)

Vill du träffa raden/elementet självt (t.ex. spara den i en lista, eller om hela raden faktiskt är en länk) använd value=":scope" – CSS-pseudoklassen för "det element sökningen utgår från":

  list_append    by=css  scope=item  value=":scope"   var "traffar"

Loggen visar vad som faktiskt träffades, t.ex. Klickar: css='a' → <a.ids-link href=/case/123 "Bilresa - aktivitetshäfte.pdf"> – jämför det mot vad du menade att klicka.

Recept (vanliga arbetsflöden)

Ladda ner alla bilagor från ett ärende

Bilagorna ligger på ärendets detaljsida. Antalet varierar (0, 1 eller flera). PDF-bilagor har en riktig länk; bildbilagor öppnar en popup med en nedladdningslänk – save_attachment hanterar båda.

click            (öppna ärendet, t.ex. td:nth-child(5))
wait             1–2 s
clear_var        var "bilagor"                       (nollställ per ärende)
list             value "etj-file-attachment-link", var "bilaga_element"
loop over "bilaga_element":
  save_attachment  by=css  scope=item  value="a[href]"  var="bilagor"
go_back          (tillbaka till listan inför nästa varv)

Filerna hamnar i data/downloads/ med sina riktiga namn; namnkrock döps om till namn (2).ext. bilagor blir en lista med sökvägarna.

Bara PDF:er, eller olika hantering för PDF vs. bild

loop over "bilaga_element":
  if  element_exists  by=css  scope=item  value=".ids-icon-file-pdf":
        save_attachment  by=css  scope=item  value="a[href]"  var="pdf_lista"
  else:
        save_attachment  by=css  scope=item  value="a[href]"  var="bild_lista"

.ids-icon-file-pdf / .ids-icon-file-image är ikon­klasserna i raden. Utelämna else-grenen för att hoppa över bilder helt.

Slå ihop bilagor till en PDF och skriv ut

Hjälpskriptet scripts/merge_and_print.py (kräver pypdf + Pillow) tar en ordnad blandning av PDF:er och bilder: bilder blir centrerade A4-sidor, PDF:er läggs in sida för sida.

save_var        var "bilagor", filename "bilagor.json"
run_script      path "scripts/merge_and_print.py"
                args "--files-from bilagor.json --out data/downloads/arende_{index}.pdf --print"
ArgumentBetydelse
--files-from <fil>JSON-array med sökvägar (fil i data/exports/ eller en sökväg) – t.ex. det save_var skrev
--file <sökväg>En fil till (upprepa för fler; ordningen bevaras)
--pdf-latestNyaste *.pdf i data/downloads/ först
--out <sökväg>Utfil (default data/downloads/merged.pdf)
--printSkicka utfilen till skrivare
--printer "Namn"Specifik skrivare (default: Windows standardskrivare)

Skriptet skriver en rad JSON till stdout ({"out": ..., "pages": 3, "printed": true, "skipped": []}) – sätt run_script-stegets var för att fånga den.

Numrera nedladdade filer i en loop

  • Löpande varvnummer räcker: använd {index} direkt i filename (loopen sätter det automatiskt).
  • Tät numrering av bara de faktiskt sparade filerna: lägg ett increment-steg (var "n") precis före nedladdningen och använd {n} i filename. Nollställ med clear_var om räknaren ska börja om per ärende.

Göra ett steg "hit or miss"

Sätt stegets on_error till "continue" (listan bredvid etikettfältet) så loggas ett fel/timeout och nästa steg körs ändå – bra för ett wait_for_selector eller click som bara ibland är relevant. På en loop/if gäller det hela blocket.

Grenar, sammanslagning & loopar

I grafen finns inga hopp – du ritar kanter. Vanliga mönster:

  • Gren + sammanslagning: koppla if-nodens case-/else-utgångar till varsin nodkedja, och låt varje kedjas sista nod peka på samma efterföljande nod.
  • Loop: loop.each → kroppens första nod; kroppens sista nod → loop.in (loopback); loop.done → det som ska hända efteråt.
  • Ett utgångshandtag styr bara en kant (motorn följer den första). Vill du köra flera saker: kedja dem, eller lägg in en nod som samlar ihop.
  • Ett skydd stoppar körningen efter väldigt många nodsteg (troligen en loop utan avslut) – FlowError istället för att hänga sig.

Subflöden & flikar

För att hålla stora flöden läsbara går det att bryta ut delar och anropa dem med en call_flow-nod:

  • Lokala subgrafer ligger i samma flödesfil under nyckeln subflows: [{id, name, nodes, edges, start, inputs}]. I canvasen är de egna flikar bredvid "Main" (+ skapar en, dubbelklick döper om). call_flow med target: "#<id>" kör en.
  • Externa flöden – ett vanligt sparat flöde anropas med target = dess namn.
  • Indata/utdata mappas explicit (in/out på noden). Subflödet är en "ren funktion": det ser inte anroparens variabler och bara det som listas i out kommer tillbaka.
  • Varje subflow-flik har en "Kör denna flik"-knapp som kör just den subgrafen (med en dialog för dess egna inputs) – bra för att testa isolerat.
// Main: ... -> call_flow(target="#dubbla", in=[{name:"x", value:"{v}"}],
//                        out=[{from:"y", to:"r"}]) -> ...
// subflows: [{ id:"dubbla", name:"Dubbla", inputs:[{name:"x"}],
//              nodes:[{id:"s1", type:"set_var", var:"y", text:"{x}{x}"}], edges:[] }]

Felsökning

VerktygVad det gör
Variabelpanel (webui)Klicka på ett variabelnamn efter en körning för att se dess faktiska innehåll (typ + JSON/text)
Trace (python -m rpa.show_trace)Öppnar Playwrights Trace Viewer – skärmdumpar, DOM, nätverk per steg, sparas automatiskt varje körning i data/traces/
python -m rpa.codegen <url>Öppnar en inspector mot en riktig, inloggad sida (samma profil) – hovra/klicka för att få exakta selectors, istället för att gissa
Håll webbläsaren öppenVid "Kör flöde", välj "Håll öppen vid fel"/"Håll alltid öppen" i dropdownen för att kunna inspektera sidan manuellt efteråt
KörloggenVisar varje stegs faktiska (interpolerade) selector/text-värde, inte den oersatta mallen. För click/type/check/select_option/download/save_attachment visas dessutom vilket element som träffades: → <tagg.klass href=… "text">

Datamappar

Allt under data/ är gitignorat – kan innehålla inloggningssession och personlig information.

MappInnehåll
data/flows/Sparade flöden (JSON)
data/browser_profile/Persistent Chromium-profil (inloggningssession)
data/downloads/Nedladdade filer ("Ladda ner"-steget)
data/exports/JSON/CSV från "Spara variabel"/"Läs in variabel"
data/screenshots/Från "Ta skärmdump"
data/traces/Playwright-traces, en per körning
data/discover/HTML/skärmdumpar från rpa.discover

Språk (i18n)

Webb-UI:t har engelska som standardspråk med svenska som växlingsbar översättning (språkväljare i headern, sparas i webbläsarens localStorage). Bara själva gränssnittet (steg-namn, fältetiketter, knappar) är översatt – körloggens meddelanden kommer alltid på svenska direkt från Python-backend, oavsett valt UI-språk.

Inställningar & export

"⚙ Settings" i headern öppnar en dialog med körningsinställningar, sparade som ett settings-objekt tillsammans med flödets nodes/edges i samma JSON-fil (data/flows/<namn>.json):

NyckelStandardBetyder
headlessfalseKör utan synligt fönster. Kräver en redan giltig inloggningssession.
viewport_width / viewport_height1280 / 900Webbläsarens fönsterstorlek
locale"sv-SE"Webbläsarens språk/region
slow_mo0Millisekunder paus mellan varje Playwright-åtgärd, för felsökning
notify_on_completefalseSkrivbordsnotis när körningen är klar

"Export as script" laddar ner en fristående .py-fil som kör exakt samma flöde (STEPS + SETTINGS inbäddade som Python-literaler) genom att importera rpa och anropa samma run_flow()-motor som webui:t – ingen logik dupliceras, beteendet blir identiskt. Praktiskt för schemaläggning (Task Scheduler) av ett flöde byggt i UI:t.

python mitt_flode.py
python mitt_flode.py --headless          # tvinga headless oavsett sparad inställning
python mitt_flode.py --close-mode never  # håll webbläsaren öppen efteråt
Scriptet kräver att rpa-paketet går att importera – kör det från projektroten, eller kopiera med hela rpa/-mappen.

Version & git

Projektet är kopplat till en git-remote (git.kristoffersson.info/repos/RPA-Remisser.git). Push kräver en personlig token (finns inte sparad i klartext någonstans i repot – måste anges vid varje push-tillfälle i den här miljön eftersom credential-cachning inte fungerar i sandboxen).