Saltar al contenido
crawlforgeEnglish
Producto3 de noviembre de 20268 min de lecturaRead in English

Cada sitio con sus propias reglas

La 0.20.0 deja que cada sitio apague reglas o cambie su gravedad sin volver a rastrear, añade cinco reglas gratuitas y habla diez idiomas.

Screaming Frog publicó hace unos días su versión 25.0, y en las notas hubo dos cosas que me llamaron la atención: los avisos ya se pueden configurar en cada rastreo, y la interfaz aparece en siete idiomas (inglés, español, alemán, francés, italiano, neerlandés y turco, según su propia página). Leí la publicación como leo la de cualquier herramienta que hace el mismo trabajo, buscando lo que encaja con la forma de trabajar de CrawlForge, que gira en torno a la cartera de sitios, los diffs entre rastreos y el informe que se le pasa a otra persona. Hubo cosas que encajaban y cosas que no. La 0.20.0 sale de ahí, seis días después de la entrada de la 0.19.0, la de los metadatos que se quedan fuera del head.

Trae reglas configurables por sitio, cinco reglas nuevas del nivel gratuito (el catálogo pasa de 66 a 71) y toda la salida en diez idiomas. Va cada cosa en su apartado.

El criterio vive en el fichero del sitio

ColorVivo gestiona más de cien blogs de clientes y no todos siguen las mismas normas. Puede que una plantilla escriba descripciones largas a propósito, o que otra ponga dos <h1> en cada página y nadie tenga intención de cambiarlo. Ver esos avisos todas las semanas acaba tapando los que importan. Desde la 0.20.0, el YAML de cada sitio que se pasa con --config acepta un bloque rules::

rules:
  disable: [META-DESC-TOO-LONG, CONTENT-H1-MULTIPLE]
  severity:
    META-TITLE-TOO-LONG: low

La decisión importante era en qué momento se aplica. El rastreo no lo mira: evalúa todas las reglas y guarda cada hallazgo en bruto con la gravedad del catálogo. crawl, list y audit guardan el bloque dentro del fichero del rastreo, en crawl_meta.config_json, una columna que ya existía, así que el esquema no cambia. Lo aplican los comandos que leen el fichero, que son report, inspect, export, diff y portfolio. Si a uno de ellos le pasas --config, ese bloque sustituye al guardado solo para esa ejecución, y un fichero sin rules: lo enseña todo:

crawlforge crawl https://cliente.com/ --config cliente.yaml   # guarda el bloque
crawlforge report crawl-cliente-com.sqlite                    # lo aplica
crawlforge report crawl-cliente-com.sqlite --config otro.yaml

Cambiar de criterio nunca obliga a rastrear otra vez. Un ID de regla o una gravedad que no existen dan un error que los nombra, y apagar una regla y cambiarle la gravedad en el mismo bloque también es un error.

Aquí está la diferencia de diseño con la otra herramienta. Allí los avisos se configuran por rastreo desde la interfaz. Aquí son un YAML por sitio, que puede vivir en un repositorio junto al código del sitio con su historial, y los datos en bruto se quedan en el fichero del rastreo. Una regla apagada en el YAML sigue teniendo sus hallazgos guardados, y basta leer el fichero sin el bloque para recuperarlos.

Treinta consultas que nadie tocó

El motor lee hallazgos en más de treinta sitios: el informe, la ficha de URL, las exportaciones, el diff y la cartera. Lo evidente habría sido editar cada consulta para filtrar y cambiar gravedades, y también lo más fácil de dejar a medias. En su lugar, la conexión de solo lectura a SQLite crea dos vistas TEMP llamadas issues y v_issue_summary, que tapan a las de verdad. Cada consulta que ya existía lee los hallazgos configurados sin que nadie la haya editado.

v_issue_summary necesitó su propia vista porque una vista de main resuelve los nombres en main. La vista de resumen original seguía leyendo la tabla issues real y no se enteraba de la temporal, así que hubo que redefinirla también.

El diff y la cartera

El diff es donde una configuración por sitio podía mentir con más facilidad. Si el rastreo anterior no tenía bloque y el posterior apaga una regla, comparar cada fichero con su propia configuración haría que todos los hallazgos de esa regla salieran como resueltos sin que se hubiera arreglado nada. Por eso el diff evalúa los dos rastreos con una sola configuración, la que se pase con --config o, si no hay, la del rastreo posterior. --fail-on juzga la gravedad ya cambiada, y cuando los dos ficheros guardan configuraciones distintas el diff avisa.

portfolio hace lo contrario a propósito y lee cada sitio con la configuración que tenga guardada, porque cada cliente tiene sus normas. Todas las salidas que aplican una configuración lo dicen con una línea del tipo «2 rules disabled, 1 severity changed», y la hoja Summary del XLSX también.

Lo probé con un rastreo de 700 MB de diariodelamancha.com. Con META-TITLE-TOO-LONG bajada a low, sus 19.807 hallazgos pasaron de medium a low, y el informe tardó 1,57 segundos frente a 1,35 sin configuración. Después, un diff en el que solo el fichero posterior tenía bloque: los hallazgos bajaron de 81.748 a 74.246 en el rastreo anterior y de 366.740 a 357.641 en el posterior, y los resueltos se quedaron en 4.281. No apareció ni un resuelto que no se hubiera arreglado.

Cinco reglas nuevas

SOCIAL-OG-IMAGE-BROKEN (medium) salta cuando la primera og:image devuelve un error, directamente o al final de hasta diez redirecciones. En tu propio dominio cuenta cualquier código desde el 400, y en uno ajeno solo el 404, el 410 o un dominio muerto. Estaba planificada como pro y sale como free. El parser apunta esa imagen como un enlace con element='meta' y el rastreo la pide igual que un <img>, o la sondea si está en otro dominio. Cuenta para --max-urls y queda fuera de las reglas de página, porque en las pruebas una og:image en http:// disparaba HTTP-MIXED-CONTENT, un falso positivo de verdad que ahora tiene su protección. Entre el 86 y el 99 % de las og:image ya están como <img> en alguna parte del sitio, así que las peticiones de más son entre el 1 y el 14 %: 22 de 260 en diariodelamancha y 42 de 303 en revistacloud. No hizo falta migración, porque la columna links.element nunca tuvo restricción.

HREFLANG-LANG-MISMATCH (medium) detecta el hreflang que apunta a la propia página con un idioma distinto del de <html lang>. Solo compara la subetiqueta de idioma, así que es-ES y es coinciden, y los códigos retirados cuentan como el mismo idioma (iw y he, in e id, nb y no). Es medium porque no puede saber cuál de los dos lados está mal.

HREFLANG-SELF-ONLY (low) salta cuando todas las entradas hreflang apuntan a la propia página. Dio con un caso real en diariodelamancha.com, /minijuegos/, cuyo único hreflang es es y apunta a sí misma. En especialmundial.com hay 2.915 páginas con hreflang (1.964 en español y 951 en inglés) y no dio ningún hallazgo, porque los conjuntos están bien hechos.

LINK-ANCHOR-EMPTY (medium) es para el enlace interno sin texto, sin imagen y sin aria-label, aria-labelledby ni title. Los enlaces que envuelven una imagen se dejan a las reglas de alt que ya había, para que nada salte dos veces. Es medium a propósito: una regla nueva que todavía no ha saltado en ningún sitio real no debería romperle a nadie una puerta --fail-on high en su CI el día que actualiza. Quien la quiera más alta puede subirla en su bloque rules:. En colorvivo.com los 2.344 enlaces internos sin texto envuelven una imagen, y no dio ningún hallazgo.

LINK-ANCHOR-GENERIC (low) avisa de los enlaces internos cuyo texto entero es una frase hecha: «read more», «click here», «leer más», «aquí», «weiterlesen», «lire la suite», «czytaj więcej», «続きを読む» y el resto de las listas, una por idioma para los diez. Las frases inconfundibles se miran en todas las páginas, porque un «Read more» sin traducir en una plantilla en español es el caso más habitual. Las palabras ambiguas como «Go», «Plus» o «Link» solo cuentan cuando <html lang> declara ese idioma. El primer rastreo real de diariodelamancha dio un falso positivo, una etiqueta que se llamaba literalmente «más», en /tag/mas/. Ahora se excluye el enlace cuyo texto coincide con el slug de su destino. Sobre los anclajes guardados del rastreo anterior, esa exclusión evita 144 falsos positivos de ese tipo (las etiquetas más, detalles, información y enlace), y la única coincidencia que quedó era un «aquí» de verdad en mitad de un párrafo. Los slugs se decodifican antes, así que también funciona con /tag/wi%C4%99cej/.

Lo que no copié es el aviso de imagen sin title, porque Google no usa ese atributo.

El cambio del parser lo medí con páginas reales, alternando versiones. La de Wikipedia en español, de 768 KB, pasó de 4,29 a 4,38 ms por página (+2,1 %), y la inglesa, de 1,1 MB, de 5,80 a 5,93 (+2,2 %). La primera versión costaba un 7,7 %, porque cada búsqueda de atributo en lol_html pasa el nombre a minúsculas y lo copia, y con un selector CSS se arregló. El banco de regresión de publicación, alternando la 0.19.0 y la 0.20.0 con el Mac cargado, no mostró ninguna regresión: 58.460, 57.093, 48.145 y 49.943 elementos por segundo la 0.19.0, y 57.751, 59.880, 60.428 y 63.477 la 0.20.0.

Diez idiomas

La salida se puede leer en inglés, que es el idioma por defecto y el de origen, y en español, alemán, francés, italiano, neerlandés, turco, portugués de Brasil, japonés y polaco. Se elige con --lang o con la variable CRAWLFORGE_LANG:

crawlforge rules --lang ja
crawlforge report crawl-cliente-com.sqlite --lang pl

Hasta ahora, las cadenas de la línea de comandos tenían una columna por idioma dentro de una macro de Rust, y los textos de las reglas eran campos name_es, name_en, desc_es y desc_en. Eso aguanta con dos idiomas y no con un tercero, y quien quisiera traducir tenía que saber Rust. Ahora todo está en ficheros Fluent: locales/<lang>/cli.ftl, con 291 mensajes, y rules.ftl, con el nombre y la descripción de las 71 reglas. Se incrustan al compilar, de modo que sigue siendo un solo binario, y la dependencia nueva es fluent-bundle. Para traducir basta con copiar locales/en/ y pasar un test.

Ese test sustituye a la garantía de antes, la de que una cadena sin traducir no compilaba. Para cada idioma que tiene mensajes falla si falta una clave, si sobra una o si las variables no son las del inglés, y lista todos los problemas de una vez. La refactorización se comprobó byte a byte: la salida en inglés y en español de report (terminal, Markdown y HTML), diff, inspect, portfolio, rules y la exportación CSV, comparada con el binario anterior, salió idéntica, 828 cadenas de 828. Para llegar ahí hubo que desactivar las marcas de aislamiento Unicode de Fluent, que cambiaban cada byte de la salida.

El polaco tiene tres formas de plural: 1 adres URL, 3 adresy URL, 5 adresów URL, 22 adresy URL, 25 adresów URL. Los recuentos se le pasan ahora a Fluent como números, porque algunos iban como texto ya formateado y eso rompía los plurales a partir de 1.000. En japonés, las tablas de la terminal se alinean por ancho visual (un carácter ancho ocupa dos columnas), las descripciones se cortan por columna y hay un kinsoku básico para que ninguna línea empiece por 。、)o 」.

Las traducciones están hechas a máquina y nadie nativo las ha revisado. Lo decidió el responsable del proyecto y prefiero decirlo claro. Manda el inglés, y las correcciones son bienvenidas: el apartado «Adding or improving a language» de CONTRIBUTING explica cómo hacerlas.

Traducir sacó errores en el propio texto inglés. Había «finding(s)» donde tocaba un plural de verdad, un «1 URLs», puntuación rota en ASSET-FORM-BROKEN y etiquetas escritas en inglés a fuego dentro del código Rust, como las cabeceras de la cartera, la fila | URLs | y los motivos por los que una página no es indexable. También había columnas de ancho fijo que obligaban al alemán a escribir «k. A.» en vez de «unbekannt». Ahora las columnas se ajustan al idioma.

Las exportaciones XLSX y CSV siguen en inglés a propósito, porque las leen máquinas. rules.json lleva ya los diez idiomas. Esta web sigue en inglés y en español.

Se construye en público

Cada dos semanas: mediciones, fallos y ejemplos de uso. Nada más.

← Volver a la bitácora