Watch at EaseHistorias. Respuestas. Perspectiva.

Tecnología · GUÍA PRÁCTICA

Divide una exportación HTML de Joplin en libretas portátiles con sus adjuntos

Este procedimiento por lotes, probado en Linux, convierte una exportación HTML completa en formato de directorio en paquetes separados por libreta y comprueba si faltan archivos o quedan enlaces que dependen de Joplin o de otra libreta.

Ilustración editorial original que muestra cómo una exportación HTML de Joplin se convierte en dos paquetes de libretas, cada uno con su propia copia de los adjuntos compartidos que necesita.
Ilustración editorial original: la carpeta contenedora de cada libreta lleva sus propios recursos necesarios. Un adjunto utilizado por ambas libretas se copia en los dos paquetes. Watch at Ease

Para sacar una libreta de una exportación HTML de Joplin, reúne sus notas HTML con los recursos a los que realmente hacen referencia. HTTrack puede copiar esas dependencias y reescribir los enlaces locales. El procedimiento por lotes que sigue parte de una exportación íntegra, enumera todas las notas de cada libreta de nivel superior y crea una carpeta contenedora independiente para cada libreta.

La comprobación final es tan importante como la copia. En nuestra prueba, HTTrack indicó cero errores, aunque los enlaces a otra libreta seguían apuntando al servidor local que ya habíamos detenido. Después de copiar, comprueba el inventario de notas y los adjuntos, y revisa un informe explícito de enlaces antes de considerar que un paquete se puede leer de forma independiente.

Decide si necesitas paquetes separados

Si solo quieres trasladar toda la colección archivada a otra unidad, conserva el directorio exportado completo. Las carpetas de las libretas y el directorio compartido _resources pueden moverse juntos. Si tienes pocas libretas, también puede resultar más sencillo exportarlas por separado.

El procedimiento por lotes resulta útil cuando ya tienes una exportación HTML grande en formato de directorio y quieres poder trasladar cada libreta de forma independiente. En una conversación de 2026 del foro de Joplin se describe una biblioteca de unas 100 libretas: repetir manualmente la exportación de cada una era el obstáculo práctico.

Este procedimiento conserva el formato HTML de lectura de la exportación. Si tu objetivo es importar las notas en otra aplicación, considera utilizar un formato compatible con ella o un conversor como Jimmy. Joplin documenta JEX como una copia de seguridad sin pérdidas que se puede volver a importar y conserva los metadatos de las notas; guarda una junto con la exportación original.

Parte de una exportación completa de la aplicación de escritorio

Utiliza el menú de exportación de la aplicación de escritorio de Joplin para crear una exportación HTML en formato de directorio de las libretas que necesitas. Elige la opción que genera archivos HTML separados y carpetas de libretas. El código fuente de la versión v3.7.21 revisado para esta guía no admite la exportación HTML desde la aplicación de línea de comandos de Joplin.

Antes de exportar, deja que terminen la sincronización y las descargas de adjuntos. En la configuración de adjuntos, Joplin distingue entre Always (siempre), Auto (automática) y Manual: Auto descarga los adjuntos al abrir una nota y Manual espera a que solicites la descarga. El exportador HTML revisado omite los recursos gestionados que no se han descargado. El empaquetado no puede recrear los bytes que faltan en el origen.

Abre la carpeta de exportación en un gestor de archivos. Para seguir este procedimiento, directamente dentro de ella deben estar los directorios de las libretas y el directorio compartido _resources; puede haber carpetas pluginAssets dentro de los directorios de las libretas. Las libretas anidadas quedan en el paquete de su libreta principal de nivel superior. Conserva intacta esta exportación y guarda el resultado fuera de ella.

Antes de continuar, abre algunas notas HTML representativas del origen y sus adjuntos, incluida una nota situada varios niveles dentro de la estructura y un enlace a un PDF o a un documento. Si una nota ya apunta a un destino incorrecto, primero hay que corregir su exportación de origen. Los enlaces a rutas del sistema de archivos, el HTML personalizado poco habitual y el contenido generado por complementos pueden requerir un tratamiento aparte; este procedimiento está pensado para la estructura habitual de las exportaciones de Joplin.

1. Define cuatro valores e inicia el servidor local

Utiliza una terminal Bash en Linux con Python 3 y el programa de línea de comandos HTTrack instalados. La versión de HTTrack probada es la 3.50-5; obtén el programa en la página oficial de descargas del proyecto, https://www.httrack.com/page/2/en/index.html, y comprueba la versión de tu ejecutable antes de seguir el procedimiento. Los comandos siguientes utilizan sintaxis de Bash y no se han probado en el símbolo del sistema de Windows, PowerShell ni macOS.

En el siguiente comando, sustituye EXPORT por la ruta absoluta de la exportación íntegra y HTTRACK por la ruta absoluta del ejecutable. Define OUT como un directorio nuevo que aún no exista, situado fuera de la exportación y cuyo directorio superior sí exista. Tampoco debe existir la ruta que se obtiene al añadir -moved a OUT. Elige un puerto local libre; en el ejemplo se utiliza el 8765.

Ejecuta cada comando numerado como una sola línea física, en la misma sesión de Bash. Conserva las comillas rectas, las barras invertidas y los puntos y coma. El primer comando crea el directorio de salida e inicia un servidor que escucha únicamente en 127.0.0.1. No sube las notas a ningún sitio web.

EXPORT="/absolute/path/to/html-export"; OUT="/absolute/path/to/new-notebook-bundles"; PORT=8765; HTTRACK="/absolute/path/to/httrack"; mkdir "$OUT" && { python3 -m http.server "$PORT" --bind 127.0.0.1 --directory "$EXPORT" >"$OUT/server.log" 2>&1 & HTTRACK_SERVER_PID=$!; printf "%s\n" "$HTTRACK_SERVER_PID" >"$OUT/server.pid"; sleep 1; kill -0 "$HTTRACK_SERVER_PID"; }

Si este comando muestra un error, detente antes de ejecutar el procesamiento por lotes. Revisa OUT/server.log, corrige la ruta o el puerto y utiliza un directorio de salida nuevo. Mantén abierta la sesión de terminal: los comandos posteriores utilizan sus variables y el identificador de proceso del servidor que se ha registrado.

2. Crea un paquete separado para cada libreta de nivel superior

Este comando recorre cada libreta de forma recursiva y escribe un archivo .urls.txt que contiene la URL de cada nota HTML. Codifica los espacios y los caracteres no ASCII de esas URL iniciales. Excluye pluginAssets de la lista de notas y, después, ejecuta HTTrack una vez por libreta.

RESULT=0; for BOOK in "$EXPORT"/*/; do NAME=${BOOK%/}; NAME=${NAME##*/}; [ "$NAME" = "_resources" ] && continue; LIST="$OUT/$NAME.urls.txt"; python3 -c 'import pathlib,sys;from urllib.parse import quote;s=pathlib.Path(sys.argv[1]).resolve();b=pathlib.Path(sys.argv[2]).resolve();sys.stdout.write("".join("http://127.0.0.1:"+sys.argv[3]+"/"+quote(p.relative_to(s).as_posix(),safe="/")+"\n" for p in sorted(b.rglob("*.html")) if "pluginAssets" not in p.relative_to(b).parts))' "$EXPORT" "$BOOK" "$PORT" >"$LIST"; [ -s "$LIST" ] || continue; "$HTTRACK" --list "$LIST" -B -N0 -K0 -q "-*" "+127.0.0.1:$PORT/_resources/*" "+127.0.0.1:$PORT/*/pluginAssets/*" -O "$OUT/$NAME"; STATUS=$?; printf "%s: %s HTML seeds; HTTrack exit %s\n" "$NAME" "$(wc -l <"$LIST")" "$STATUS"; [ "$STATUS" -eq 0 ] || { RESULT=1; break; }; done; test "$RESULT" -eq 0

Los filtros impiden el rastreo general y permiten seguir las referencias a archivos de _resources y pluginAssets. El directorio compartido _resources nunca se utiliza como página inicial, por lo que el procesamiento por lotes no descarga deliberadamente todo su listado de archivos. No hace falta que las notas HTML estén enlazadas entre sí: todas se han incluido explícitamente en la lista de URL.

Deja que el comando termine y revisa el número de URL iniciales de cada libreta y el estado de salida de HTTrack. Detente si aparece un traceback de Python, un estado de salida distinto de cero o si falta inesperadamente una libreta en el resultado. Una salida normal y un registro con cero errores son comprobaciones útiles, pero ninguna demuestra que se hayan cubierto todas las dependencias necesarias para la lectura.

3. Detén el servidor, mueve el resultado e informa de los enlaces sin resolver

El siguiente comando detiene el servidor local de esta sesión y cambia el nombre del directorio de salida añadiendo -moved. A continuación, examina los archivos HTML de la copia y escribe link-report.json en la raíz de ese directorio de salida ya trasladado. El cambio de nombre no altera la exportación original.

kill "$HTTRACK_SERVER_PID" && mv "$OUT" "$OUT-moved" && python3 -c 'exec("import pathlib,sys,json\nfrom html.parser import HTMLParser\nfrom urllib.parse import urlsplit,unquote\nr=pathlib.Path(sys.argv[1]).resolve()\nrows=[]\nchecked=0\nfor m in sorted(r.glob(\"*/127.0.0.1*\")):\n for f in sorted(m.rglob(\"*.html\")):\n links=[]\n p=HTMLParser()\n p.handle_starttag=lambda tag,attrs: links.extend(v for k,v in attrs if k in (\"href\",\"src\") and v)\n p.feed(f.read_text(encoding=\"utf-8\",errors=\"replace\"))\n for v in links:\n u=urlsplit(v)\n if u.scheme==\"joplin\" or u.hostname==\"127.0.0.1\":\n rows.append({\"file\":str(f.relative_to(r)),\"kind\":\"joplin\" if u.scheme==\"joplin\" else \"local-http\",\"url\":v})\n elif not u.scheme and not u.netloc and u.path:\n checked+=1\n t=(f.parent/unquote(u.path)).resolve()\n if not t.is_file() or m.resolve() not in t.parents:\n rows.append({\"file\":str(f.relative_to(r)),\"kind\":\"missing-or-outside-local\",\"url\":v})\nresult={\"checked_local_html_references\":checked,\"review\":rows}\ntext=json.dumps(result,ensure_ascii=False,indent=2)\n(r/\"link-report.json\").write_text(text,encoding=\"utf-8\")\nprint(text)\n")' "$OUT-moved"

El informe indica el archivo HTML, el enlace y el motivo de cada elemento señalado. El número checked_local_html_references cuenta las referencias locales href/src inspeccionadas en el HTML, no las notas, los adjuntos ni todas las dependencias. Una lista review vacía es una señal útil, pero no equivale a una validación completa de todo el contenido archivado.

Si falla la detención del servidor o el traslado del resultado, no des por hecho que se ha ejecutado el análisis posterior. Resuelve primero ese fallo. No reutilices un destino anterior en una nueva ejecución: elige rutas OUT y OUT-moved nuevas para que una copia previa no oculte archivos que falten en el nuevo resultado.

Lee el informe antes de confiar en el paquete

Una entrada local-http sigue apuntando a 127.0.0.1. Puede ser un enlace a otra libreta que se ha dejado fuera del paquete de forma intencionada, o a un recurso que no se ha copiado. Abre la nota de origen indicada e inspecciona el destino. Si una imagen, una hoja de estilos o un adjunto necesario sigue dependiendo del servidor local, el paquete está incompleto.

Una entrada joplin es un enlace a la aplicación. Copiar la nota no lo convierte en un enlace HTML corriente y portátil. Una entrada missing-or-outside-local apunta a un archivo local que falta o que está fuera del directorio de la copia correspondiente a ese paquete. Investiga estas entradas antes de depender de la copia.

Si el enlace señalado solo sirve para navegar a otra libreta, decide si la copia para lectura sigue siendo útil con esa limitación documentada. Si necesitas que esos enlaces funcionen, conserva junta la exportación original completa. Este procedimiento no reescribe la navegación entre libretas para crear una nueva biblioteca conjunta ni repara los enlaces joplin:// existentes.

El análisis automático cubre los atributos href y src del HTML. No inspecciona las dependencias url() del CSS, las solicitudes generadas por scripts, los destinos de fragmentos, el comportamiento de aplicaciones incrustadas ni todos los demás atributos HTML. Comprueba también cómo se muestran realmente las notas y sus adjuntos.

El informe no señala las URL HTTP o HTTPS externas habituales, incluidas las imágenes o las hojas de estilos remotas a las que se hace referencia en href o src. Los filtros de rastreo dejan esos recursos remotos fuera del paquete. Si una nota depende de contenido remoto, inspecciona esas URL o abre la copia trasladada con la red desconectada antes de considerar que ese contenido está disponible sin conexión. Los enlaces normales a sitios web pueden seguir siendo útiles para visitarlos con conexión.

Ilustración editorial original que muestra las comprobaciones tras detener el servidor local y mover un paquete de libreta, con los enlaces entre libretas y los enlaces a la aplicación Joplin señalados para su revisión.
Ilustración editorial original: detén el servidor, mueve un paquete completo y verifica sus notas y adjuntos. Revisa los enlaces entre libretas y los enlaces joplin:// incluso cuando HTTrack indique cero errores. Watch at Ease

Verifica un paquete fuera de la carpeta del procesamiento por lotes

Elige la carpeta contenedora de una libreta dentro de OUT-moved y copia esa carpeta completa a otra ubicación, como una carpeta temporal en otra unidad. Dentro de ella, HTTrack crea un directorio cuyo nombre corresponde al servidor, por ejemplo 127.0.0.1_8765, que contiene la libreta y su propio directorio _resources. Mantén juntos ese directorio y todo su contenido.

Coteja la lista .urls.txt generada para la libreta con los archivos HTML de su árbol de directorios copiado. Comprueba los nombres de archivo y las rutas anidadas; no te limites a un total que podría incluir las páginas de índice del propio HTTrack. Debe existir cada nota prevista, incluidas aquellas a las que no apunta ningún enlace. Repite el inventario para cada paquete que quieras conservar.

Con el servidor local detenido, abre las notas desde la carpeta contenedora que has trasladado por separado. Abre un adjunto PDF o un documento, inspecciona una imagen y comprueba una nota anidada y cualquier formato que utilice recursos de complementos. Para los adjuntos binarios importantes, compara la suma de comprobación del archivo copiado con la del archivo correspondiente en el directorio _resources original; una página de error guardada con el nombre de un adjunto no cuenta como una copia correcta.

Un adjunto compartido debe existir dentro de cada paquete de libreta que haga referencia a él. Un archivo que solo utiliza otra libreta no debe aparecer simplemente porque ambas procedan de la misma exportación. Cuando hayas comprobado el inventario de notas, los adjuntos necesarios y las limitaciones de los enlaces de un paquete, tendrás una copia independiente para lectura. Conserva la exportación completa original y la copia de seguridad JEX.

Qué se probó y qué debes comprobar todavía

Probamos HTTrack 3.50-5 con Bash y Python 3 en Linux, utilizando un conjunto de archivos de prueba sintético basado en la estructura de directorios del exportador HTML de Joplin v3.7.21. No fue una prueba de principio a fin de la interfaz de escritorio de Joplin ni una prueba de todas las versiones de exportación y todos los complementos.

El procesamiento por lotes final incluía dos libretas de nivel superior; el nombre de una contenía un espacio y caracteres chinos. Se copiaron las cinco notas HTML previstas, incluidas las anidadas y aquellas a las que no apuntaba ningún enlace. El primer paquete contenía sus 10 recursos globales previstos y cuatro recursos de complementos; el segundo, sus cuatro recursos globales previstos y un recurso de complemento. Las copias de los PDF y documentos compartidos coincidían byte por byte con el origen, y los 24 archivos de origen permanecieron intactos.

Después de detener el servidor y mover el resultado, el verificador del conjunto de prueba encontró 21 referencias locales válidas de HTML y CSS. El comando destinado al lector que aparece más arriba comprobó por separado 18 referencias HTML href/src e identificó correctamente dos enlaces HTTP locales entre libretas y dos enlaces joplin://. Aun así, ambos registros de HTTrack indicaban cero errores.

Un filtro anterior que incluía el nombre codificado de la libreta dejó sin copiar una hoja de estilos de la libreta cuyo nombre contenía espacios y caracteres chinos. El procedimiento final sigue los directorios habituales de recursos y proporciona explícitamente todas las notas como puntos de partida. Por eso los filtros deben ir acompañados de las comprobaciones posteriores: la copia, su registro y la apertura correcta de una primera nota solo responden a una parte de la pregunta de si el paquete es portátil.