Formatos y fuentes de datos 4 min de lectura

Parseo de sitemaps: cómo recorrer el mapa del sitio antes de recopilar datos

Por qué empezar la recolección por el sitemap.xml: parseo de mapas índice, selección de las URL necesarias y ahorro en el rastreo del sitio antes del scraping.

EW
Equipo Web-Scraping.es
Recopilación de datos para las necesidades del negocio
Publicado: 9 abril 2025

El sitemap (mapa del sitio) es un archivo XML con la lista de las URL de un sitio que el propietario pone a disposición de los buscadores y de los rastreadores (crawlers). Para las tareas de recopilación de datos, el mapa del sitio no tiene precio: en lugar de recorrer a ciegas los enlaces de página en página, usted recibe un listado ya hecho de direcciones, a menudo con la fecha de la última modificación y la prioridad. Por eso el parseo del sitemap suele ser el primer paso antes del parseo del HTML. Este artículo continúa nuestro panorama de los formatos de documentos; como el sitemap es un caso particular de XML, las técnicas generales de trabajo con el árbol están descritas en el artículo sobre el parseo de XML.

Estructura del archivo

El sitemap estándar está descrito por el esquema de sitemaps.org. Cada URL es un elemento <url> con un <loc> obligatorio y los opcionales <lastmod>, <changefreq> y <priority>.

xml
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://example.com/product/101</loc>
    <lastmod>2026-05-12</lastmod>
    <priority>0.8</priority>
  </url>
  <url>
    <loc>https://example.com/product/102</loc>
    <lastmod>2026-06-01</lastmod>
  </url>
</urlset>

Un detalle importante: el espacio de nombres http://www.sitemaps.org/schemas/sitemap/0.9. Por su culpa, la búsqueda «ingenua» de la etiqueta loc sin tener en cuenta el namespace devolverá el vacío; es el error más frecuente al desmontar mapas (más sobre los namespaces, en el artículo sobre XML).

Índice de sitemaps y sitemaps anidados

En los sitios grandes, un solo archivo no da cabida a todos los enlaces (el límite es de 50 000 URL o 50 MB), así que se emplea un índice de mapas: un archivo con enlaces a otros sitemaps. El elemento raíz aquí es <sitemapindex> y, dentro, van elementos <sitemap> con sus <loc> anidados.

xml
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap><loc>https://example.com/sitemap-products.xml</loc></sitemap>
  <sitemap><loc>https://example.com/sitemap-articles.xml.gz</loc></sitemap>
</sitemapindex>

Por eso un parser fiable debe ser recursivo: primero leer el índice y, después, descargar y desmontar uno a uno cada mapa anidado. Observe que los archivos anidados se sirven muchas veces comprimidos en gzip (.xml.gz) — hay que descomprimirlos al vuelo.

Dónde buscar el mapa

La dirección del mapa suele figurar en el robots.txt, en la línea Sitemap:. Si no aparece allí, se comprueban las rutas estándar /sitemap.xml y /sitemap_index.xml. Conviene empezar precisamente por el robots.txt: es la forma más fiable de conocer la ubicación vigente.

Python

La vía más transparente: descargar el archivo y desmontarlo como un XML normal con lxml, sin olvidarse del namespace ni de la recursión por el índice.

python
import gzip
import requests
from lxml import etree

NS = {"sm": "http://www.sitemaps.org/schemas/sitemap/0.9"}

def fetch(url):
    data = requests.get(url, timeout=30).content
    if url.endswith(".gz"):
        data = gzip.decompress(data)
    return etree.fromstring(data)

def parse_sitemap(url, urls=None):
    urls = urls if urls is not None else []
    root = fetch(url)
    # si es un índice, descendemos a los mapas anidados
    for loc in root.xpath("//sm:sitemap/sm:loc/text()", namespaces=NS):
        parse_sitemap(loc.strip(), urls)
    # enlaces normales
    for loc in root.xpath("//sm:url/sm:loc/text()", namespaces=NS):
        urls.append(loc.strip())
    return urls

links = parse_sitemap("https://example.com/sitemap.xml")
print(len(links), "URL encontradas")

Si no quiere escribir a mano la recursión y el tratamiento del gzip, existe la biblioteca especializada ultimate-sitemap-parser: encuentra el mapa por sí sola, recorre los índices y devuelve la lista plana de páginas.

python
from usp.tree import sitemap_tree_for_homepage

tree = sitemap_tree_for_homepage("https://example.com/")
for page in tree.all_pages():
    print(page.url, page.last_modified)

JavaScript / Node.js

En Node, el mapa se desmonta cómodamente con la pareja fetch y fast-xml-parser (el mismo que se usa para el XML).

javascript
const { XMLParser } = require("fast-xml-parser");

async function parseSitemap(url) {
  const xml = await (await fetch(url)).text();
  const parser = new XMLParser();
  const doc = parser.parse(xml);

  if (doc.sitemapindex) {
    const maps = [].concat(doc.sitemapindex.sitemap);
    const all = [];
    for (const m of maps) all.push(...await parseSitemap(m.loc));
    return all;
  }
  return [].concat(doc.urlset.url).map((u) => u.loc);
}

parseSitemap("https://example.com/sitemap.xml").then((urls) =>
  console.log(urls.length)
);

Qué hacer con las fechas de actualización

El campo <lastmod> es la razón principal para amar los mapas del sitio. Comparándolo con el momento del recorrido anterior, se pueden descargar solo las páginas modificadas y no cargar el sitio con peticiones de más. Eso convierte un scraping puntual en una monitorización regular eficiente: no se recorre todo el sitio, solo el delta. Tenga en cuenta que lastmod no siempre está relleno, ni siempre con honestidad, así que úselo como pista y no como verdad absoluta.

Una vez reunida la lista de URL empieza la extracción de datos de las páginas propiamente dicha — eso ya es tarea del parseo de HTML. Si necesita recorrer con regularidad un sitio grande con mapa índice, gzip y filtrado por fecha, configuraremos el scraping llave en mano, programación incluida, con la entrega del resultado en el formato que le convenga, por ejemplo CSV o Excel.