{"id":28718669,"url":"https://github.com/wronai/formap","last_synced_at":"2026-04-14T19:32:00.345Z","repository":{"id":298304762,"uuid":"999480795","full_name":"wronai/formap","owner":"wronai","description":"web form mapper and filler Automatyczne mapowanie i wypełnianie formularzy internetowych przy użyciu Playwright.","archived":false,"fork":false,"pushed_at":"2025-06-10T12:31:28.000Z","size":77,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-10T12:35:56.859Z","etag":null,"topics":["autofiller","automation","browser","filler","form","formular","llm","lmm","local","node","npm","ollama","playwright","selenium"],"latest_commit_sha":null,"homepage":"https://wronai.github.io/formap/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wronai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-10T10:10:10.000Z","updated_at":"2025-06-10T12:31:35.000Z","dependencies_parsed_at":"2025-06-10T12:36:49.392Z","dependency_job_id":"07ebf6c9-546d-48ef-ac86-ebd089e4dc47","html_url":"https://github.com/wronai/formap","commit_stats":null,"previous_names":["wronai/formap"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/wronai/formap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wronai%2Fformap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wronai%2Fformap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wronai%2Fformap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wronai%2Fformap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wronai","download_url":"https://codeload.github.com/wronai/formap/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wronai%2Fformap/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31812968,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T18:05:02.291Z","status":"ssl_error","status_checked_at":"2026-04-14T18:05:01.765Z","response_time":153,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["autofiller","automation","browser","filler","form","formular","llm","lmm","local","node","npm","ollama","playwright","selenium"],"created_at":"2025-06-15T05:03:11.285Z","updated_at":"2026-04-14T19:32:00.327Z","avatar_url":"https://github.com/wronai.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🧠 FORMAP - Advanced Form Mapper \u0026 Auto-Filler\n\n[English below] Zaawansowane narzędzie do mapowania i automatycznego wypełniania formularzy internetowych przy użyciu Playwright i sztucznej inteligencji.\n\n## ✨ Funkcje\n\n- 🔍 Automatyczne wykrywanie pól formularza z zaawansowanym mapowaniem\n- 🤖 Integracja z lokalnym modelem językowym (LLM) dla lepszego rozumienia formularzy\n- 📁 Obsługa załączników (CV, listy motywacyjne, itp.)\n- 🎯 Inteligentne dopasowywanie etykiet do pól formularza\n- 💾 Zapis mapowania pól do pliku JSON\n- 🚀 Automatyczne wypełnianie formularzy na podstawie zapisanego mapowania\n- 🔒 Obsługa wszystkich standardowych pól formularza (tekst, wybór, radio, checkbox, pliki, itp.)\n- 🐍 Prosty interfejs wiersza poleceń i API Pythona\n\n---\n\n# 🧠 FORMAP - Advanced Form Mapper \u0026 Auto-Filler\n\nAutomatically map and fill web forms with ease using Playwright and AI.\n\n## ✨ Features\n\n- 🔍 Automatic form field detection with advanced mapping\n- 🤖 Local Language Model (LLM) integration for better form understanding\n- 📁 File upload support (CVs, cover letters, etc.)\n- 🎯 Smart label-to-field association\n- 💾 Save field mappings to JSON files\n- 🚀 Automatically fill forms using saved mappings\n- 🔒 Supports all standard form fields (text, select, radio, checkbox, file uploads, etc.)\n- 🐍 Simple CLI and Python API\n\n## 🚀 Szybki start / Quick Start\n\n### Wymagania / Prerequisites\n\n- Python 3.8+\n- Git (do sklonowania repozytorium / for cloning the repository)\n- [Poetry](https://python-poetry.org/) (do zarządzania zależnościami / for dependency management)\n\n### Instalacja / Installation\n\n1. **Zainstaluj Poetry (jeśli nie jest zainstalowany) / Install Poetry (if not installed)**:\n   ```bash\n   curl -sSL https://install.python-poetry.org | python3 -\n   ```\n\n2. **Sklonuj repozytorium / Clone the repository**:\n   ```bash\n   git clone https://github.com/yourusername/formap.git\n   cd formap\n   ```\n\n3. **Skonfiguruj środowisko / Set up the environment**:\n   ```bash\n   # Zainstaluj zależności\n   # Install dependencies\n   poetry install\n   \n   # Zainstaluj przeglądarkę do testów\n   # Install browser for testing\n   poetry run playwright install\n   ```\n   \n   # Zainstaluj przeglądarki Playwright\n   # Install Playwright browsers\n   python -m playwright install\n   ```\n\n## 🛠️ Użycie / Usage\n\n### 1. Mapowanie pól formularza / Map Form Fields\n\nAby zmapować pola formularza / To map the fields of a form:\n\n```bash\n# Aktywuj środowisko wirtualne jeśli nieaktywne\n# Activate virtual environment if not already activated\nsource venv/bin/activate\n\n# Uruchom mapowanie\n# Run the mapper\npython form-mapper/map_fields.py https://przykladowa-strona.pl/logowanie\n```\n\n# Włącz szczegółowe logowanie / Enable debug logging\npoetry run formap --debug detect https://example.com/form\n```\n\n### 2. Wypełnianie formularza / Fill a Form\n\nAby wypełnić formularz używając danych z pliku / To fill a form using data file:\n\n```bash\n# Wypełnij formularz używając danych z pliku\n# Fill form using data file\npoetry run formap fill https://example.com/form --data form_data.json\n\n# Użyj niestandardowego mapowania pól / Use custom field mapping\npoetry run formap fill https://example.com/form --data form_data.json --mapping form_map.json\n\n# Uruchom w trybie bezinterakcyjnym / Run in headless mode\npoetry run formap fill https://example.com/form --data form_data.json --headless\n```\n\n### 3. Użycie z kodu Pythona / Using from Python Code\n\n```python\nimport asyncio\nfrom formap import FormDetector, FormFiller\n\nasync def main():\n    # Mapowanie formularza / Form mapping\n    async with FormDetector() as detector:\n        fields = await detector.detect(\"https://example.com/form\")\n        print(f\"Znaleziono {len(fields)} pól formularza\")\n    \n    # Wypełnianie formularza / Form filling\n    async with FormFiller() as filler:\n        await filler.fill(\n            \"https://example.com/form\",\n            data={\"username\": \"test\", \"email\": \"test@example.com\"},\n            mapping=fields,\n            headless=True\n        )\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n## 📋 Przykłady użycia / Usage Examples\n\n### Przykład 1: Logowanie / Example 1: Login Form\n\n```bash\n# Mapowanie formularza logowania\n# Mapping a login form\npoetry run formap detect https://example.com/login\n# Po zapisaniu mapowania, wypełnij formularz\n# After saving the mapping, fill the form\npoetry run formap fill https://example.com/login --data login_data.json\n```\n\n### Przykład 2: Rejestracja / Example 2: Registration Form\n\n```bash\n# Mapowanie formularza rejestracji\n# Mapping a registration form\npoetry run formap detect https://example.com/register\n# Wypełnij formularz danymi\n# Fill the form with data\npoetry run formap fill https://example.com/register --data register_data.json\n```\n\n### Przykład 3: Formularz kontaktowy / Example 3: Contact Form\n\n```bash\n# Mapowanie formularza kontaktowego\n# Mapping a contact form\npoetry run formap detect https://example.com/contact\n# Wypełnij i wyślij formularz\n# Fill and submit the form\npoetry run formap fill https://example.com/contact --data contact_data.json\n```\n\n## 🐳 Uruchamianie w Dockerze / Docker Support\n\nMożesz również uruchomić FORMAP używając Dockera / You can also run FORMAP using Docker:\n\n```bash\n# Zbuduj obraz Dockera / Build the Docker image\ndocker build -t formap .\n\n# Uruchom mapowanie / Run the mapper\ndocker run -it --rm -v $(pwd):/app formap poetry run formap detect https://example.com/form\n\n# Uruchom wypełnianie / Run the filler\ndocker run -it --rm -v $(pwd):/app formap poetry run formap fill https://example.com/form --data form_data.json\n```\n\n## 📁 Project Structure\n\n```\nform-mapper/\n├── Dockerfile           # Docker configuration\n├── Makefile            # Common commands\n├── README.md           # This file\n├── requirements.txt     # Python dependencies\n├── map_fields.py       # Form field mapping script\n└── fill_form.py        # Form filling script\n```\n\n## 💡 Wskazówki / Tips\n\n- Upewnij się, że wszystkie wymagane pola są wypełnione przed zapisaniem mapowania.\n- Możesz edytować plik `form_map.json` ręcznie, aby dostosować mapowanie.\n- Użyj opcji `--headless` aby uruchomić przeglądarkę w trybie bezokienkowym.\n\n## 🤝 Współtworzenie / Contributing\n\nWkład jest mile widziany! Zapraszamy do przesyłania Pull Requestów. / Contributions are welcome! Please feel free to submit a Pull Request.\n\n## 📄 Licencja / License\n\nTen projekt jest dostępny na licencji MIT - zobacz plik [LICENSE](LICENSE) aby uzyskać więcej informacji. / This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n\n\n\n\nOto pełna struktura projektu do **mapowania i wypełniania formularzy za pomocą Playwright**, w stylu **MVP z Mistral 7B**, z kompletem:\n\n* `Makefile` do uruchamiania zadań\n* `Dockerfile` do konteneryzacji\n* `docker-compose.yml` do lokalnego uruchamiania\n* `README.md` z instrukcją\n\n---\n\n## 📁 Struktura projektu:\n\n```\nform-mapper/\n├── Dockerfile\n├── Makefile\n├── README.md\n├── docker-compose.yml\n├── map_fields.py\n├── fill_form.py\n├── requirements.txt\n└── example.env\n```\n\n---\n\n## 📄 `map_fields.py` i `fill_form.py`\n\n*(Już masz je wcześniej — kopiujesz z poprzedniej wiadomości.)*\n\n---\n\n## 📄 `requirements.txt`\n\n```txt\nplaywright==1.44.0\n```\n\n---\n\n## 📄 `Dockerfile`\n\n```dockerfile\nFROM python:3.11-slim\n\nWORKDIR /app\n\nCOPY requirements.txt .\nRUN pip install --no-cache-dir -r requirements.txt \u0026\u0026 \\\n    playwright install --with-deps\n\nCOPY . .\n\nCMD [\"bash\"]\n```\n\n---\n\n## 📄 `docker-compose.yml`\n\n```yaml\nversion: '3.8'\n\nservices:\n  formmapper:\n    build: .\n    container_name: formmapper\n    environment:\n      - PYTHONUNBUFFERED=1\n    volumes:\n      - .:/app\n    entrypoint: [\"tail\", \"-f\", \"/dev/null\"]  # Do debugowania interaktywnego\n```\n\n*(możesz zmienić `entrypoint`, by odpalało konkretne polecenie, np. `python map_fields.py`)*\n\n---\n\n## 📄 `Makefile`\n\n```makefile\n.PHONY: map fill up build shell\n\nmap:\n\tpython map_fields.py\n\nfill:\n\tpython fill_form.py\n\nbuild:\n\tdocker-compose build\n\nup:\n\tdocker-compose up -d\n\nshell:\n\tdocker-compose exec formmapper bash\n```\n\n---\n\n## 📄 `example.env`\n\n```env\nURL=https://example.com\nEMAIL=test@example.com\nUSERNAME=jan.kowalski\nPASSWORD=tajne123\n```\n\n(Można potem podciągać zmienne do `fill_form.py` z `os.getenv`.)\n\n---\n\n## 📄 `README.md`\n\n````markdown\n# 🧠 Form Mapper \u0026 Auto-Filler (Playwright + Mistral 7B-style)\n\nTen projekt automatycznie:\n1. Mapuje formularze HTML przez klawisz `Tab`\n2. Tworzy plik JSON z XPath i typami pól\n3. Na podstawie mapy automatycznie wypełnia formularze\n\n## 🔧 Wymagania\n\n- Python 3.11+\n- Docker (opcjonalnie)\n\n## 🐍 Lokalne uruchomienie\n\n### Instalacja\n```bash\npip install -r requirements.txt\nplaywright install\n````\n\n### Mapowanie pól\n\n```bash\nmake map\n```\n\n### Wypełnianie formularza\n\n```bash\nmake fill\n```\n\n## 🐳 Uruchomienie w Dockerze\n\n### Budowanie kontenera\n\n```bash\nmake build\n```\n\n### Włączenie środowiska\n\n```bash\nmake up\nmake shell  # potem np. python map_fields.py\n```\n\n## 📂 Pliki\n\n* `map_fields.py` – mapa formularzy przez `Tab`\n* `fill_form.py` – wypełnianie pól wg JSON\n* `form_map.json` – wynik mapowania\n* `example.env` – przykładowe dane\n\n## 📌 Autor\n\nProjekt edukacyjny inspirowany użyciem LLM (np. Mistral 7B) do automatyzacji formularzy.\n\n```\n\n---\n\nChcesz, bym dodał możliwość odczytu danych z `.env`, automatyczne rozpoznawanie checkboxów, czy też interaktywny CLI do wprowadzania danych?\n```\n\n\nOto prosty, **dwuczęściowy** skrypt w **Pythonie** używający **Playwright**, który:\n\n1. **Symuluje przechodzenie przez pola formularza przy pomocy klawisza `Tab`**, zapisując kolejne **XPathy i typy pól** (np. input, button, select).\n2. **Zapisuje mapę pól do pliku JSON**, która potem może być użyta do **automatycznego wypełniania formularza**.\n\n⚠️ **Dostosowany do ograniczeń Mistral 7B**: nie robi analizy semantycznej strony, tylko czysto techniczne mapowanie po `Tab`.\n\n---\n\n## 📦 Wymagania:\n\nZainstaluj Playwright:\n\n```bash\npip install playwright\nplaywright install\n```\n\n---\n\n## 🧠 Część 1: Mapowanie pól przez `Tab` i zapis do JSON\n\n```python\n# map_fields.py\nimport json\nimport asyncio\nfrom playwright.async_api import async_playwright\n\nasync def map_form_fields(url: str, output_json: str = \"form_map.json\"):\n    async with async_playwright() as p:\n        browser = await p.chromium.launch(headless=False)\n        page = await browser.new_page()\n        await page.goto(url)\n\n        print(f\"[INFO] Odwiedzono stronę: {url}\")\n\n        mapped_fields = []\n        visited_elements = set()\n\n        for i in range(50):  # maksymalnie 50 tabów\n            await page.keyboard.press(\"Tab\")\n            await page.wait_for_timeout(200)\n\n            active = await page.evaluate_handle(\"document.activeElement\")\n            tag = await active.evaluate(\"el =\u003e el.tagName.toLowerCase()\")\n            typ = await active.evaluate(\"el =\u003e el.type || ''\")\n            name = await active.evaluate(\"el =\u003e el.name || ''\")\n            id_attr = await active.evaluate(\"el =\u003e el.id || ''\")\n\n            xpath = await page.evaluate('''\n                el =\u003e {\n                    function getXPath(el) {\n                        if (el.tagName === 'HTML')\n                            return '/html';\n                        if (el === document.body)\n                            return '/html/body';\n                        var ix = 0;\n                        var siblings = el.parentNode.childNodes;\n                        for (var i = 0; i \u003c siblings.length; i++) {\n                            var sibling = siblings[i];\n                            if (sibling === el)\n                                return getXPath(el.parentNode) + '/' + el.tagName.toLowerCase() + '[' + (ix+1) + ']';\n                            if (sibling.nodeType === 1 \u0026\u0026 sibling.tagName === el.tagName)\n                                ix++;\n                        }\n                    }\n                    return getXPath(el);\n                }\n            ''', active)\n\n            if xpath not in visited_elements:\n                visited_elements.add(xpath)\n                mapped_fields.append({\n                    \"tag\": tag,\n                    \"type\": typ,\n                    \"name\": name,\n                    \"id\": id_attr,\n                    \"xpath\": xpath,\n                })\n\n        with open(output_json, \"w\") as f:\n            json.dump(mapped_fields, f, indent=2)\n            print(f\"[INFO] Zapisano mapę formularza do: {output_json}\")\n\n        await browser.close()\n\nif __name__ == \"__main__\":\n    url = \"https://przyklad.pl\"  # \u003c- PODAJ PRAWIDŁOWY ADRES STRONY\n    asyncio.run(map_form_fields(url))\n```\n\n---\n\n## 📝 Część 2: Wypełnianie formularza według mapy\n\n```python\n# fill_form.py\nimport json\nimport asyncio\nfrom playwright.async_api import async_playwright\n\nasync def fill_form(url: str, json_map: str, values: dict):\n    async with async_playwright() as p:\n        browser = await p.chromium.launch(headless=False)\n        page = await browser.new_page()\n        await page.goto(url)\n\n        with open(json_map, \"r\") as f:\n            fields = json.load(f)\n\n        for field in fields:\n            xpath = field[\"xpath\"]\n            typ = field[\"type\"]\n            tag = field[\"tag\"]\n\n            if typ in [\"text\", \"email\", \"password\", \"search\", \"tel\", \"url\"] or tag == \"textarea\":\n                value = values.get(field[\"name\"] or field[\"id\"] or xpath, \"test\")\n                try:\n                    el = await page.wait_for_selector(f\"xpath={xpath}\", timeout=1000)\n                    await el.fill(value)\n                except Exception as e:\n                    print(f\"[WARN] Nie udało się wypełnić pola {xpath}: {e}\")\n\n        await page.wait_for_timeout(3000)\n        await browser.close()\n\nif __name__ == \"__main__\":\n    values = {\n        \"email\": \"test@example.com\",\n        \"username\": \"jan.kowalski\",\n        \"password\": \"tajne123\"\n        # dodaj klucze na podstawie mapy\n    }\n    url = \"https://przyklad.pl\"  # \u003c- PODAJ TĘ SAMĄ STRONĘ\n    asyncio.run(fill_form(url, \"form_map.json\", values))\n```\n\n---\n\n## ✅ Jak tego używać?\n\n1. **Krok 1**: Uruchom `map_fields.py`, by stworzyć mapę formularza.\n2. **Krok 2**: Przejrzyj `form_map.json` i podaj odpowiednie wartości w `fill_form.py`.\n3. **Krok 3**: Uruchom `fill_form.py`, by automatycznie wypełnić pola.\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwronai%2Fformap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwronai%2Fformap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwronai%2Fformap/lists"}