scrape_ with_ actions
Laksanakan rangkaian tindakan pelayar termasuk klik, tatal, taip dan auto-isi borang dengan tangkapan skrin. Sesuai untuk aliran log masuk, tatal tak terhingga, dialog modal dan tapak kompleks yang banyak JavaScript.
Kes Penggunaan
Aliran Log Masuk
Automasikan borang log masuk dan akses kandungan disahkan di sebalik dinding log masuk
Tatal Tak Terhingga
Scrape kandungan daripada halaman tatal tak terhingga seperti suapan media sosial dan penyenaraian produk
Dialog Modal
Berinteraksi dengan popup, modal dan tindanan dinamik
Tapak Banyak JavaScript
Kendalikan SPA dan tapak dengan pemuatan kandungan dinamik melalui AJAX
Borang Berbilang Langkah
Navigasi melalui wizard berbilang langkah dan penyerahan borang kompleks
Pengujian Visual
Tangkap tangkapan skrin pada setiap langkah untuk penyahpepijatan dan pengujian regresi visual
Endpoint
/api/v1/tools/scrape_with_actionsParameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Required | - | URL untuk dimuatkan sebelum menjalankan rangkaian tindakan Example: https://app.example.com/dashboard |
actions | array | Required | - | Senarai tersusun 1-20 tindakan pelayar untuk dijalankan sebelum scraping. Setiap item ialah objek dengan `type` iaitu `wait`, `click`, `type`, `press`, `scroll`, `screenshot`, `executeJavaScript`, `select`, `hover`, `navigate` atau `snapshot`, ditambah medan khusus mengikut jenis: `selector` (sasaran CSS, atau rujukan `@e1` daripada `snapshot` terdahulu), `text` (untuk `type`), `key` (untuk `press`), `script` (untuk `executeJavaScript`), `duration`/`condition` (untuk `wait`), `button`/`clickCount`/`delay` (untuk `click`), `direction`/`distance`/`toElement` (untuk `scroll`) `fullPage`/`quality`/`format` (untuk `screenshot`), `value` atau `values` (untuk `select`), `url`/`waitUntil` (untuk `navigate`) dan `interactiveOnly`/`maxNodes` (untuk `snapshot`). `select` menerima satu `value` atau tatasusunan `values`, dan rentetan biasa dipadankan dengan opsyen mengikut nilainya atau label yang dipaparkan; `hover` memerlukan `selector`, dengan `force` dan `position` sebagai pilihan. `snapshot` menyenaraikan elemen interaktif pada halaman, termasuk yang berada dalam shadow root terbuka dan iframe, dengan rujukan stabil pada setiap satu — `@e1`, `@e2`, … mengikut susunan dokumen — dan mana-mana tindakan seterusnya dalam rantaian yang sama boleh menyasarkan salah satu rujukan itu dan bukannya pemilih CSS; navigasi membatalkannya, jadi ambil `snapshot` baharu selepas halaman berubah. Pilihan pada mana-mana tindakan: `timeout` (setiap tindakan, lalai 10000ms — berbeza daripada `browserOptions.timeout` yang membajet keseluruhan rantaian), `description`, `continueOnError` (lalai false), `retries` (0-5, lalai 1) dan `captureAfter` (lalai false). Example: [{"type": "click", "selector": "#login"}, {"type": "type", "selector": "#email", "text": "user@example.com"}, {"type": "wait", "duration": 1000}, {"type": "screenshot"}] |
formats | array | Optional | ["json"] | Format output untuk dikembalikan: `markdown`, `html`, `json` atau `text`. Untuk imej, tambah tindakan `{"type": "screenshot"}` di tempat anda mahu ia diambil. Example: ["markdown"] |
captureIntermediateStates | boolean | Optional | false | Tangkap keadaan halaman selepas setiap tindakan: `intermediateStates[]` mendapat satu entri bagi setiap tindakan (`capturePoint` ialah kedudukan tindakan itu, bermula dari 1) dengan `url`, `title` dan format yang diminta pada ketika itu Example: true |
formAutoFill | object | Optional | - | Isi dan serah borang dalam satu langkah. Struktur: `{ fields: [{ selector, value, type: text|select|checkbox|radio|file, waitAfter }], submitSelector, waitAfterSubmit }` — `waitAfterSubmit` lalai kepada 2000ms. `type` setiap medan menentukan cara ia diisi: `text` (lalai) menaip nilai, `select` memilih pilihan mengikut nilai atau label, dan `checkbox` serta `radio` menanda input — pemilih yang sepadan dengan seluruh kumpulan, seperti `input[name=size]`, menanda ahli yang atribut `value`nya sama dengan `value`, dan checkbox dengan nilai `"false"` dinyahtanda. `file` tidak disokong dan menggagalkan tindakan itu. Example: {"fields": [{"selector": "#email", "value": "user@example.com", "type": "text"}], "submitSelector": "#login"} |
browserOptions | object | Optional | - | Konfigurasi pelayar: `headless` (lalai true), `userAgent`, `viewportWidth` (lalai 1280, julat 800-1920), `viewportHeight` (lalai 720, julat 600-1080), `timeout` (lalai 30000ms, julat 10000-120000) dan `stealth` (lalai false). Kekalkan `timeout` dalam tetingkap REST ~25s. Tetapkan `stealth` kepada true untuk menjalankan rantaian tindakan dalam enjin senyap Chromium pada profil `medium`, bukan kumpulan pelayar standard — boolean itu satu-satunya kawalan, jadi tahap, rawakan cap jari dan pilihan enjin tidak boleh ditetapkan dari sini. Ia lebih lambat bermula, dan ia memaparkan JavaScript, bukan menyelesaikan cabaran. `consent` (lalai `"off"`) mengendalikan sepanduk kuki dan persetujuan: `"reject"` menjalankan penolakan (opt-out) DuckDuckGo autoconsent pada sepanduk itu sekali selepas navigasi awal dan selepas setiap tindakan `navigate`, dihadkan kepada 2 s, manakala `"accept"` menerima sebaliknya. Apabila ia bukan `"off"`, hasilnya membawa `consent: { cmp, action, ms }` bagi navigasi awal, dan hasil setiap tindakan `navigate` membawa `result.consent` tersendiri. `cmp` ialah platform pengurusan persetujuan yang dipadankan, atau `null` jika tiada; `action` ialah `optOut`, `optIn`, `hide` (peraturan kosmetik menyembunyikan sepanduk), `timeout` (sepanduk dikesan tetapi tidak dijawab dalam had 2 s), `error` atau `none` (tiada yang dipadankan); `ms` ialah tempoh yang diambil. Rantaian tidak pernah gagal kerana tiada platform yang dipadankan. Lalainya off supaya rantaian yang mengklik sepanduk itu sendiri terus berfungsi. `proxyRotation` menghalakan pelayar senyap melalui proksi yang anda bekalkan: `{ enabled, proxies, rotationInterval }`, dengan `enabled` lalai false dan `rotationInterval` (lalai 300000) ialah masa minimum dalam ms pada satu proksi sebelum senarai beralih ke proksi seterusnya. Ia memerlukan `stealth: true` dan ditolak jika tidak. Proksi berjalan bagi setiap konteks pada enjin Chromium sahaja; `proxyRotation` bagi setiap panggilan ditolak pada Camoufox, yang menggunakan proksinya semasa pelayar dilancarkan dan berkongsi pelayar itu merentas panggilan. Setiap entri dalam `proxies` ialah URL proksi — `"http://user:pass@host:port"` (kodkan peratus kata laluan yang mengandungi `@`, `:` atau `/`), atau `"host:port"` sahaja bagi proksi HTTP tanpa pengesahan; `http`, `https`, `socks4` dan `socks5` diterima. Proksi pada alamat loopback, peribadi, link-local atau metadata awan ditolak, dan kelayakan tidak pernah dipaparkan semula — `metadata.browserOptions` dalam hasil menunjukkannya dalam bentuk tersunting. CrawlForge tidak membekalkan proksi: pelayar senyap terhos berjalan dari alamat pusat data, dan proksi kediaman ialah apa yang melepasi sekatan reputasi IP yang tidak dapat diatasi oleh mana-mana cap jari. Example: {"viewportWidth": 1440, "viewportHeight": 900, "timeout": 20000} |
extractionOptions | object | Optional | - | Pilihan pengekstrakan kandungan: `selectors` (peta CSS kunci→nilai bagi data untuk dikeluarkan), `includeMetadata` (lalai true), `includeLinks` (lalai true) dan `includeImages` (lalai true). Example: {"selectors": {"title": "h1", "price": ".price"}} |
continueOnActionError | boolean | Optional | false | Teruskan menjalankan tindakan yang selebihnya apabila satu gagal, bukannya membatalkan rangkaian Example: false |
maxRetries | number | Optional | 0 | Percubaan semula keseluruhan rantaian apabila gagal (0-3). Setiap percubaan semula menavigasi semula ke URL permulaan dan mengulang semua tindakan, jadi setiap satu menelan kos yang sama seperti larian asal; setiap percubaan dilaporkan di bawah `attempts[]` Example: 0 |
screenshotOnError | boolean | Optional | true | Tangkap tangkapan skrin apabila ralat berlaku Example: true |
respect_robots | boolean | Optional | true | Hormati robots.txt tapak sasaran. Jika ditinggalkan, nilai lalai yang patuh (`true`) terpakai: URL yang dilarang untuk `CrawlForge` ditolak sebelum pelayar dibuka dan titik akhir ini tidak mengenakan sebarang caj untuknya, dan setiap tindakan `navigate` diperiksa dengan cara yang sama. Halaman itu diperiksa semula di mana sahaja ia berakhir — selepas ubah hala, klik atau penghantaran borang — dan jika ia tiba di laluan yang dilarang, panggilan itu gagal tanpa mengembalikan apa-apa daripada halaman tersebut. `Crawl-delay` tapak itu dihormati walau apa pun nilai ini: `navigate`, serta `click`, `press`, `select` atau `check` yang mungkin menghantar halaman ke tempat lain, menunggu selama itu selepas permintaan terakhir ke hos halaman sebelum ia dijalankan. Tetapkan kepada `false` hanya untuk sasaran yang anda mempunyai perjanjian sendiri dengannya — tindakan mengatasi itu direkodkan pada API key anda. Example: true |
max_inline_chars | number | Optional | 40000 | Hasil terbesar yang dikembalikan sebaris, dalam aksara JSON-nya (1,000-10,000,000). Melebihinya, respons membawa `preview` (`max_inline_chars` aksara pertama medan teks utama hasil), `result_handle`, `total_chars`, `truncated: true` dan `expires_at`, dan [read_result](/docs/api-reference/tools/read-result) membaca selebihnya dengan 1 credit setiap panggilan. Hasil tersimpan disimpan selama 1 jam. Example: 40000 |
redact_pii | boolean | object | Optional | false | Buang data peribadi daripada teks yang dikembalikan oleh panggilan ini, sebelum hasilnya disimpan atau dihantar balik. `true` ialah singkatan bagi `{ mode: "fast" }` — keempat-empat kelas regex, bertag. Setiap kali anda meminta penyuntingan, respons membawa `redaction: { entities, count, mode }` di dalam `data`, walaupun tiada apa-apa yang sepadan (`count: 0`), jadi "tiada apa-apa ditemui" tidak pernah disalah anggap sebagai "parameter itu diabaikan"; kelas tanpa padanan ditinggalkan dan bukan dilaporkan sebagai `0`. Penyuntingan berjalan **sebelum** hasil itu disimpan, jadi hasil besar yang dibaca kemudian dengan [read_result](/docs/api-reference/tools/read-result) sudah pun disunting. Dua batas yang disengajakan: alamat (`url`, `link`, `href`, `canonical_url`) tidak pernah disunting, dan kiraan yang diperoleh daripada teks (`content_length`, `word_count`, `character_count`) menggambarkan teks itu sebagaimana ia diekstrak, sebelum penyuntingan. Example: true |
Jenis Tindakan Tersedia
{"type": "wait", "duration": 2000}{"type": "click", "selector": "#button"}{"type": "type", "selector": "#search", "text": "query"}{"type": "press", "key": "Enter"}{"type": "scroll", "toElement": "#content"}{"type": "screenshot"}ALLOW_JAVASCRIPT_EXECUTION=true; ditolak pada API terhos.{"type": "executeJavaScript", "script": "window.scrollTo(0, 0)"}<select>: selector menamakan menu jatuh turun, kemudian value (satu opsyen) atau values (beberapa). Rentetan biasa dipadankan dengan opsyen mengikut nilainya atau label yang dipaparkan.selector — untuk menu dan tooltip yang hanya muncul semasa tuding. force dan position berkelakuan sama seperti pada click.url lain dalam sesi pelayar yang sama, jadi kuki, localStorage dan keadaan log masuk daripada tindakan terdahulu kekal. waitUntil pilihan ialah load, domcontentloaded (lalai), networkidle, atau commit. URL baharu itu melalui pemeriksaan robots.txt dan SSRF yang sama seperti URL awal, jadi ia bukan jalan untuk memintas kawalan tersebut. Setiap navigasi diperiksa untuk dinding bot: result tindakan itu membawa httpStatus dan, apabila dinding dikenal pasti, blocked: { vendor, evidence }. Tindakan itu sendiri tetap berjaya — dinding itu dilaporkan, bukan menyebabkan kegagalan.[document] "Example Domain", kemudian @e1 [textbox] "Search..." dan @e2 [button] "Search". Elemen dalam iframe atau shadow root mendapat rujukan @eN biasa seperti elemen lain. Tetapkan interactiveOnly (lalai true) kepada false untuk turut menyenaraikan tajuk dan mercu tanda (landmark), yang tidak pernah diberi rujukan; maxNodes (lalai 200, maksimum 1000) mengehadkan bilangan nod yang disenaraikan pepohon itu — dengan tetapan lalai, satu rujukan bagi setiap nod — dan hasilnya melaporkan truncated: true apabila had itu menghentikan pemeriksaan. Entri tindakan ini dalam actionResults membawa pepohon itu sebagai result.tree, bersama snapshotId, url, title, refCount, nodeCount, truncated, interactiveOnly dan source — aria apabila pepohon itu datang daripada snapshot kebolehcapaian asli pelayar, walk apabila pemeriksaan sandaran menghasilkannya.{"type": "snapshot", "interactiveOnly": true, "maxNodes": 200}Menyasarkan elemen mengikut rujukan
snapshot meletakkan rujukan stabil pada setiap elemen interaktif yang ditemuinya, jadi rantaian itu berbunyi snapshot, bertindak pada rujukan, snapshot semula: [{"type": "snapshot"}, {"type": "type", "selector": "@e1", "text": "crawlforge"}, {"type": "click", "selector": "@e2"}]. Rujukan hanya sah pada dokumen tempat snapshot itu diambil: sebarang navigasi — tindakan navigate, atau klik yang memuatkan halaman baharu — membatalkan semua rujukan, dan bertindak pada rujukan lapuk akan gagal dengan ralat yang meminta anda mengambil snapshot baharu. Elemen dalam shadow root terbuka dan iframe mendapat rujukan @eN biasa dan disasarkan dengan cara yang sama.
Dinding bot pada setiap navigasi
Setiap navigasi dalam rantaian — pemuatan halaman awal dan setiap tindakan navigate — diperiksa untuk dinding bot, halaman ralat HTTP atau halaman cabaran perantara, termasuk halaman perantara HTTP 202 seperti cabaran AWS WAF atau Amazon. Hasilnya menyenaraikan semuanya mengikut susunan di bawah navigations, dengan indeks 0 bagi pemuatan awal, setiap satu sebagai { url, finalUrl, httpStatus, blocked }: httpStatus ialah null apabila tidak diketahui, dan blocked: { vendor, evidence } hanya muncul apabila dinding dikenal pasti (cloudflare, akamai, datadome, perimeterx, amazon, vercel, …). Klik atau penghantaran borang yang memuatkan halaman lain juga merupakan navigasi: ia mendapat entri sendiri, dengan trigger menamakan jenis tindakan (click, press, …), dan finalUrl peringkat atas ialah tempat rantaian berakhir, manakala url kekal sebagai URL yang anda minta. Dinding di pertengahan tidak menghentikan rantaian, jadi tindakan kemudian boleh terus menavigasi. Sama ada panggilan itu berjaya ditentukan oleh dokumen tempat rantaian berakhir: rantaian yang berakhir pada dinding tidak pernah dilaporkan sebagai berjaya. Melalui API ini ia gagal dengan 502 BLOCKED, membawa blocked dan navigations, dan tiada apa-apa dicaj; halaman ralat HTTP tanpa dinding yang dinamakan gagal dengan 502 TOOL_ERROR. Alat ini melaporkan dinding; ia tidak menyelesaikannya — apabila sekatan itu terletak pada alamat rangkaian, hantar proksi anda sendiri dalam browserOptions.proxyRotation (bersama stealth: true).
Contoh Permintaan
# 1. Snapshot the page to learn its interactive elements and their refs.
curl -X POST https://crawlforge.dev/api/v1/tools/scrape_with_actions \
-H "X-API-Key: cf_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/login",
"actions": [{"type": "snapshot"}],
"formats": ["json"]
}'
# actionResults[0].result.tree comes back as:
# [document] "Sign in"
# @e1 [textbox] "Email"
# @e2 [textbox] "Password"
# @e3 [button] "Sign in"
# 2. Target those refs instead of guessing selectors. The chain snapshots
# again first, which stamps the refs onto this fresh load.
curl -X POST https://crawlforge.dev/api/v1/tools/scrape_with_actions \
-H "X-API-Key: cf_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/login",
"actions": [
{"type": "snapshot"},
{"type": "type", "selector": "@e1", "text": "user@example.com"},
{"type": "type", "selector": "@e2", "text": "secret123"},
{"type": "click", "selector": "@e3"},
{"type": "wait", "duration": 1000},
{"type": "screenshot"}
],
"formats": ["markdown"]
}'Contoh Respons
{ "success": true, "data": { "success": true, "url": "https://app.example.com/login", "finalUrl": "https://app.example.com/dashboard", "httpStatus": 200, "engine": "chromium", "navigations": [ { "url": "https://app.example.com/login", "finalUrl": "https://app.example.com/login", "httpStatus": 200 }, { "url": "https://app.example.com/dashboard", "finalUrl": "https://app.example.com/dashboard", "httpStatus": 200, "trigger": "click" } ], "actionResults": [ { "id": "action_1759480001102_k2m8x1q0z", "type": "click", "success": true, "executionTime": 640 }, { "id": "action_1759480001790_p7c4n9d2a", "type": "wait", "success": true, "executionTime": 1001 }, { "id": "action_1759480002805_h5t1v8r3e", "type": "screenshot", "success": true, "executionTime": 212, "result": { "format": "png", "fullPage": false, "resourceUri": "crawlforge://screenshot/action_1759480002805_h5t1v8r3e" } } ], "totalActions": 3, "successfulActions": 3, "failedActions": 0, "actionsExecuted": 3, "content": { "markdown": "# Dashboard\n\nWelcome back — you are now signed in..." }, "screenshots": [ { "actionId": "action_1759480002805_h5t1v8r3e", "format": "png", "fullPage": false, "timestamp": 1759480002805, "resourceUri": "crawlforge://screenshot/action_1759480002805_h5t1v8r3e" } ] }, "credits_used": 5, "credits_remaining": 995, "processing_time": 9000}data.urlURL yang anda minta. Ia kekal sama walau sejauh mana rantaian itu bergerakdata.finalUrlTempat rantaian berakhir, selepas sebarang ubah hala, klik atau penghantaran borangdata.httpStatusStatus dokumen bingkai utama terakhir yang dimuatkan oleh rantaiandata.navigationsSetiap navigasi mengikut susunan, dengan indeks 0 bagi pemuatan awal. Entri yang berpunca daripada klik atau penghantaran borang membawa `trigger`, iaitu jenis tindakan yang menggerakkan halamandata.actionResultsSatu entri bagi setiap tindakan, dengan `type`, `success`, tempoh masa dan `result` tindakan itu sendiridata.actionsExecutedBilangan tindakan yang dijalankan; `successfulActions` dan `failedActions` memecahkannyadata.content.markdownKandungan halaman dalam setiap format yang diminta selepas semua tindakan selesaidata.screenshotsSentiasa ada: satu entri bagi setiap tindakan `screenshot`, ditambah satu yang diambil apabila berlaku ralat, dan kosong apabila tiada. Setiap satu ialah URI sumber `crawlforge://screenshot/{actionId}` dan bukannya base64 sebaris, dan endpoint REST ini menghantar URI itu tanpa menyelesaikannya — jadi buat masa ini bait tersebut hanya boleh dibaca daripada pelayan CrawlForge MCPcredits_usedCredits ditolak untuk permintaan ini (5 setiap scrape)processing_timeJumlah masa dalam ms termasuk semua tindakan dan tungguPengendalian Ralat
Runtime pelayar tidak dikonfigurasikan (503 TOOL_NOT_AVAILABLE)
Alat ini memerlukan runtime automasi pelayar. Apabila bahagian belakang pelaksanaan terhos tidak dikonfigurasikan, panggilan memulangkan 503 serta-merta dan tiada credits dicaj.
Bahagian belakang pelaksanaan tamat masa (504 MCP_UPSTREAM_TIMEOUT)
Navigasi serta rantaian tindakan melebihi bajet masa bahagian belakang pelaksanaan. Pendekkan tempoh menunggu, kurangkan bilangan tindakan, atau cuba semula. Kegagalan tidak dicaj.
Disekat oleh robots.txt (502 TOOL_ERROR)
robots.txt sasaran melarang URL ini untuk CrawlForge, jadi tiada pelayar dilancarkan dan tiada apa-apa dicaj. Setiap tindakan navigate diperiksa dengan cara yang sama, bukan hanya URL awal. Begitu juga di mana sahaja halaman itu berakhir: apabila ubah hala, klik atau penghantaran borang membawanya ke laluan yang dilarang, mesej itu menamakan kedua-dua URL (“The page moved from … to …”), rantaian berhenti di situ dan tiada apa-apa dicaj. Halaman log masuk dan carian sering dilarang, jadi aliran yang melaluinya memerlukan tindakan mengatasi itu. Tetapkan respect_robots: false untuk mengatasinya jika anda mempunyai perjanjian sendiri dengan sasaran — tindakan mengatasi itu direkodkan pada API key anda.
Berakhir pada dinding bot (502 BLOCKED)
Dokumen tempat rantaian berakhir ialah dinding bot atau halaman cabaran perantara, jadi panggilan itu gagal dan bukannya memulangkan dinding itu sebagai halaman, dan tiada apa-apa dicaj. Badan respons membawa blocked: { vendor, evidence } yang menamakan dinding itu, navigations rantaian dan, apabila diketahui, httpStatus akhir, supaya anda dapat melihat navigasi mana yang terkena. Halaman ralat HTTP atau halaman pemegang tempat yang tidak dapat dikaitkan oleh alat ini dengan vendor gagal dengan 502 TOOL_ERROR pula, juga tanpa caj. Dinding pada navigasi yang lebih awal tidak menggagalkan panggilan; ia dilaporkan di bawah navigations. Alat ini melaporkan dinding dan tidak menyelesaikannya; apabila sekatan itu terletak pada alamat rangkaian, halakan rantaian melalui proksi anda sendiri dengan browserOptions.proxyRotation.
Tindakan Tidak Sah (400 Bad Request)
Satu atau lebih tindakan mempunyai parameter tidak sah. Semak jenis tindakan dan medan yang diperlukan.
Credits Tidak Mencukupi (402 Payment Required)
Akaun anda tidak mempunyai credits yang mencukupi (perlu 5). Beli lebih banyak credits atau naik taraf pelan anda.
Had Kadar Melebihi (429 Too Many Requests)
Anda telah melebihi had kadar pelan anda. Tunggu sebentar atau naik taraf pelan anda untuk had lebih tinggi.
Gunakan tindakan wait antara interaksi untuk memastikan JavaScript ada masa untuk dilaksanakan. Untuk penyahpepijatan, tambah tindakan screenshot selepas setiap langkah untuk melihat apa yang dilihat pelayar.
Kos Credit
Pelan Free: 1,000 credits percubaan sekali sahaja = 200 rangkaian tindakan
Pelan Hobby: 5,000 credits/bulan = 1,000 rangkaian tindakan ($19/mo)
Pelan Professional: 100,000 credits/bulan = 20,000 rangkaian tindakan ($99/mo)
Pelan Business: 500,000 credits/bulan = 100,000 rangkaian tindakan ($399/mo)
Alat Berkaitan
Bersedia untuk mencuba scrape_with_actions? Daftar percuma dan dapatkan 1,000 credits untuk mula membina.