BOE Scraper — Spain Official Gazette
Pricing
from $1.00 / 1,000 results
BOE Scraper — Spain Official Gazette
Scrape publications from the Boletín Oficial del Estado (BOE), Spain's official government gazette. Extract laws, regulations, public contracts, appointments, and legal notices. Filter by date, section, and department. Essential for legal compliance, public procurement, and regulatory monitoring.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
Rastriq — Structured data from the world
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
8 days ago
Last modified
Categories
Share
Extract publications from the Boletín Oficial del Estado (BOE), Spain's official government gazette. BOE Scraper collects laws, regulations, public contracts, appointments, and legal notices — structured and ready for compliance monitoring, procurement intelligence, and regulatory analysis.
BOE Scraper reads directly from the BOE's own open data JSON API (boe.es/datosabiertos), so there is no HTML parsing, no anti-bot handling, and no proxy required by default.
What is BOE Scraper?
BOE Scraper is an automated extractor for Spain's Boletín Oficial del Estado (boe.es), the country's official publication where all laws, royal decrees, public tenders, civil servant appointments, and legal notices are published daily. Use it to:
- Monitor regulatory changes — track new laws, decrees, and ministerial orders that affect your industry (Section I).
- Track public procurement — capture tenders and contract awards (Section V-A) for competitive intelligence.
- Follow appointments — monitor civil servant changes in specific departments or agencies (Section II-A).
- Watch private/legal notices — Section V-C (Anuncios particulares) is fully supported.
- Search by keyword and department — filter the whole gazette, or a single issuing body such as a ministry or the Tribunal Constitucional.
- Automate daily compliance feeds — schedule runs to receive fresh BOE data every morning.
- HR & recruitment — follow Section II-B for public-exam ("oposiciones") and civil-service job announcements.
- Academic & legal research — build a searchable corpus of Spanish legislation over time, filtered by section, department, or keyword.
- Government affairs — track ministerial appointments and institutional changes across specific departments (Section II-A).
Keyword search works best in Spanish, since that is the language BOE publishes in — e.g. vivienda (housing), empleo (employment), impuesto (tax), energía (energy), educación (education).
The Tribunal Constitucional does not have its own BOE section — it appears as a department (code
1410) inside the sections where it publishes (mainly Section I). Filter by that department code to isolate its notices.
BOE does not publish on Sundays or public holidays — those days are reported in the run summary as "no publication", not as errors.
Input parameters
The form is organized in four groups: Date range, Filters, Limits and ordering, and Advanced.
Date range
| Parameter | Type | Default | Description |
|---|---|---|---|
dateMode | select | latestIssue | latestIssue, lastNDays, or customRange. Fields below are ignored unless they apply to the selected mode. |
daysBack | integer | 7 | Used only when dateMode is lastNDays. Produces exactly daysBack calendar days, including today (Europe/Madrid), 1–365. |
dateFrom | date | — | Used only when dateMode is customRange. Format YYYY-MM-DD. |
dateTo | date | — | Used only when dateMode is customRange. Format YYYY-MM-DD. Range cannot exceed 365 days. |
latestIssue looks back up to 7 days from today and returns the most recent published edition — the fastest way to try the Actor.
Filters
| Parameter | Type | Default | Description |
|---|---|---|---|
sections | multiselect | all | BOE sections: 1, 2A, 2B, 3, 4, 5A, 5B, 5C. Empty = all sections. |
departmentCodes | multiselect + custom | all | Issuing department codes (e.g. 1410 for Tribunal Constitucional). A suggested list is provided; custom codes are accepted. Empty = all departments. |
includeKeywords | list | none | Only items whose search text contains these terms/phrases. |
excludeKeywords | list | none | Items whose search text contains any of these are dropped — exclusions always win over inclusions. |
keywordMatch | select | any | any (at least one include term matches), all (every term must match), or exactPhrase (each entry is a full phrase; at least one must match). |
searchFields | multiselect | ["title"] | Which fields build the search text: title, department, epigraph, identifier. |
Keyword matching is case- and accent-insensitive (licitación matches LICITACION).
Limits and ordering
| Parameter | Type | Default | Description |
|---|---|---|---|
sortOrder | select | newestFirst | Dates are processed and returned newest-first by default; set to oldestFirst to reverse. Applied before maxItems. |
maxItems | integer | 100 | Maximum items returned for the whole run, applied after sorting. Each item is a billed result — keep this low while testing. 0 keeps the legacy "unlimited" behavior for existing integrations, but is not offered as a form default because of the platform usage it can generate. |
If a run hits the limit, SUMMARY.limitReached is true — the Actor never silently promises "all N days" when the cap cut the output short.
Advanced
| Parameter | Type | Default | Description |
|---|---|---|---|
proxyConfiguration | proxy | disabled | Not needed by default — the BOE open data API has no anti-bot protection. Enable only if you experience blocks. |
Legacy compatibility (v0.1 inputs)
Existing integrations built on v0.1 keep working without changes: desde/hasta (YYYYMMDD or YYYY-MM-DD), keyword, secciones (list or comma-separated string), the individual seccion1…seccion5B booleans, and maxItems: 0 for unlimited. When both a new field and its legacy equivalent are present, the new field wins. A single deprecation warning is logged (never the full input, to avoid leaking proxy credentials) when legacy fields are used — consider migrating to the new fields above.
Output fields
Each dataset item preserves every field from v0.1 (existing integrations keep working) plus two new ones:
| Field | Type | Description |
|---|---|---|
identificador | string | Official BOE identifier, e.g. BOE-A-2026-11692 |
control | string | Internal BOE control number |
titulo | string | Full title of the publication |
url_html | string | Link to the HTML version |
url_xml | string | Link to the XML version |
url_pdf | string | Link to the official PDF |
seccion_codigo | string | Section code (1, 2A, 2B, 3, 4, 5A, 5B, 5C) |
seccion_nombre | string | Section name |
departamento_codigo | string | Issuing department code |
departamento_nombre | string | Issuing department name |
epigrafe_nombre | string | null | Sub-heading within the department, when present |
fecha_publicacion | string | Publication date as returned by BOE, YYYYMMDD |
diario_numero | string | Gazette issue number |
source | string | Fixed value "boe" |
fecha_publicacion_iso | string | New. Publication date, YYYY-MM-DD |
scraped_at | string | New. UTC timestamp of extraction, ISO 8601 |
A run summary is also written to the key-value store under SUMMARY: dates requested/fetched/without publication/failed, raw vs. filtered vs. pushed item counts, whether the limit was reached, and the sort order used. A run with any failed date is marked status: "partial" — it is never reported as a silent success.
Output example
{"identificador": "BOE-A-2026-11692","control": "2026/8701","titulo": "Recurso de inconstitucionalidad n.º 3001-2026, contra el apartado Uno del artículo único de la Ley de la Comunidad Autónoma de La Rioja 5/2025...","url_html": "https://www.boe.es/diario_boe/txt.php?id=BOE-A-2026-11692","url_xml": "https://www.boe.es/diario_boe/xml.php?id=BOE-A-2026-11692","url_pdf": "https://www.boe.es/boe/dias/2026/06/01/pdfs/BOE-A-2026-11692.pdf","seccion_codigo": "1","seccion_nombre": "I. Disposiciones generales","departamento_codigo": "1410","departamento_nombre": "TRIBUNAL CONSTITUCIONAL","epigrafe_nombre": "Recursos de inconstitucionalidad","fecha_publicacion": "20260601","diario_numero": "133","source": "boe","fecha_publicacion_iso": "2026-06-01","scraped_at": "2026-09-18T21:00:00Z"}
Example input (new-format equivalent of "last 30 days, procurement notices matching 'licitación'"):
{"dateMode": "lastNDays","daysBack": 30,"sections": ["5A"],"includeKeywords": ["licitación"],"keywordMatch": "any","searchFields": ["title"],"sortOrder": "newestFirst","maxItems": 200}
Download results in JSON, CSV, Excel, XML, or HTML from the Output tab, or pull them programmatically using the Apify API (GET /v2/datasets/{datasetId}/items).
How to use BOE Scraper
In Apify Console:
- Open BOE Scraper and leave the defaults —
dateMode: latestIssuefetches the most recent edition in seconds. - Adjust the date range, sections, departments, or keywords as needed.
- Click Start.
- Review
SUMMARYin the key-value store for a run overview, then download the dataset.
Via API:
curl -X POST "https://api.apify.com/v2/acts/rastriq~boe-scraper/runs?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"dateMode": "lastNDays", "daysBack": 7, "maxItems": 50}'
Via the Apify Python client:
from apify_client import ApifyClientclient = ApifyClient("<APIFY_TOKEN>")run = client.actor("rastriq/boe-scraper").call(run_input={"dateMode": "customRange","dateFrom": "2026-09-01","dateTo": "2026-09-18","sections": ["5A"],"includeKeywords": ["licitación"],"maxItems": 200,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["fecha_publicacion_iso"], item["titulo"])
Best practices
- Daily monitoring: leave
dateModeonlatestIssue(or setdateFrom/dateToto today) and schedule the Actor to run once a day — the cheapest way to build a running feed of new publications. - Multi-day catch-up: after a gap (e.g. the Actor didn't run over a long weekend), use
customRangecovering the missed days instead of relying onlastNDays, so you don't re-fetch days you already have. - Procurement-only feeds: set
sections: ["5A"]to track public tenders and contract awards without pulling the rest of the gazette. - Scheduled runs: use an Apify Schedule to run the Actor automatically (e.g. every morning at 9:00 Europe/Madrid) and feed new items to Slack, email, or a webhook.
- Keep
maxItemsrealistic for the range: each date can carry over a hundred items across all sections combined; for a full month across every section, raisemaxItemswell above the default100or you will hitSUMMARY.limitReachedbefore covering the whole range.
Limitations
- Keyword and department filtering happen after the BOE returns each day's full summary — the open data API does not support server-side filtering, so a large unfiltered date range still costs one HTTP request per day.
- BOE does not publish on Sundays; those dates are reported as "no publication" in
SUMMARY, not treated as gaps or errors. - A single run covers at most 365 days (
customRange/lastNDays); for a longer history, run the Actor multiple times over successive ranges (see Best practices above).
Pricing
BOE Scraper uses Apify's Pay Per Event pricing model (not a flat Compute Unit rate). As published on the Actor's Store page, the current events are:
- Actor start — a small one-time charge per run (scales with allocated memory; roughly $0.0001 per GB, minimum one event).
- Result (
apify-default-dataset-item) — charged per BOE item pushed to the dataset (currently around $0.001/item).
Standard Apify platform usage may also apply on top of these events. Prices can change — always check the Pricing tab on the Actor's Store page for the current, authoritative numbers before estimating a large run's cost. Because results are billed per item, testing with a low maxItems (5–10) before a full run is recommended.
Rough estimates at current per-item pricing, unfiltered (a typical BOE day carries roughly 100–300 items across all sections; narrowing by section, department, or keyword reduces both runtime and cost):
| Scope | Approx. items | Approx. duration | Approx. cost |
|---|---|---|---|
1 day (latestIssue) | 100–300 | 3–6 s | $0.10–0.30 |
1 week (lastNDays: 7) | 700–2,000 | 8–15 s | $0.70–2.00 |
1 month (lastNDays: 30, one section, e.g. 5A) | 300–1,000 | 15–30 s | $0.30–1.00 |
These are illustrative only — set maxItems to cap the actual spend regardless of how many items BOE published in the range.
Frequently Asked Questions
Is scraping the BOE legal?
The Boletín Oficial del Estado is public-domain data published by the Spanish government. BOE Scraper accesses the BOE's own open data API, explicitly designed for programmatic consumption.
Does BOE Scraper require an account or API key?
No. It uses the BOE's public open data API and needs no login or credentials from the target site.
How far back can I scrape?
Up to 365 days in a single customRange or lastNDays run. For longer history, run the Actor multiple times over successive ranges.
What are the BOE sections?
1 (general provisions: laws, decrees), 2A (appointments), 2B (public employment), 3 (grants and resolutions), 4 (justice), 5A (public procurement), 5B (other official announcements), 5C (private/legal notices). There is no separate section for the Tribunal Constitucional — filter by department code 1410 instead.
Why did I get fewer items than expected for my date range?
Check SUMMARY.limitReached — maxItems is a global cap applied after sorting, so a wide date range combined with a low maxItems can truncate the output before every date is fully represented. Raise maxItems or narrow the date range/filters.
I found a bug or my run failed. Where do I report it?
Open an issue in the Issues tab on this page, including your input configuration and the run ID.
Versión en español (resumen)
BOE Scraper extrae publicaciones del Boletín Oficial del Estado (boe.es) usando su API oficial de datos abiertos. Permite filtrar por modo de fecha (última edición, últimos N días o rango personalizado), secciones (incluida V-C, anuncios particulares), departamento emisor (por ejemplo, Tribunal Constitucional con código 1410) y palabras clave con inclusión/exclusión.
Los campos de salida reales son identificador, control, titulo, url_html, url_xml, url_pdf, seccion_codigo, seccion_nombre, departamento_codigo, departamento_nombre, epigrafe_nombre, fecha_publicacion, diario_numero, source, y los nuevos fecha_publicacion_iso y scraped_at. Cada ejecución guarda además un SUMMARY en el key-value store con el detalle de fechas procesadas, fallidas y sin publicación.
Los inputs del formulario v0.1 (desde, hasta, keyword, seccionX, secciones) se siguen aceptando por compatibilidad, pero el formulario nuevo es el recomendado.
El Actor se factura mediante el modelo Pay Per Event de Apify (un pequeño cargo de inicio más un cargo por resultado extraído), no únicamente por Compute Units; consulta la pestaña de Pricing del Actor para las cifras vigentes. Se recomienda probar con maxItems bajo antes de lanzar una ejecución grande.
Casos de uso adicionales: RR.HH. (oposiciones, sección II-B), investigación académica/legal, y seguimiento de nombramientos institucionales (sección II-A). Para monitorización diaria, programa el Actor con un Schedule de Apify dejando dateMode en latestIssue; para huecos de varios días, usa customRange en vez de lastNDays para no repetir fechas ya extraídas. El filtrado por keyword y departamento ocurre después de traer el sumario completo del día — la API del BOE no soporta filtrado en servidor — así que un rango amplio sin filtrar sigue costando una petición HTTP por día.