Ir al contenido principal

Cómo importar artículos de un blog viejo a uno nuevo de Blogger

Hace tiempo tomé la nefasta decisión de abandonar mi antiguo dominio y blog "mhyst.es". En realidad había empezado un blog anterior en 2004 que por problemas con el hosting también se perdió. Sólo algunos de los posts de aquel primer blog acabaron engrosando los archivos del nuevo. Y ahora tengo este. En un principio mi idea era mudar todos los artículos de "mhyst.es" aquí. Pero me encontré con que no había una forma directa y sencilla de hacerlo. Si "mhyst.es" hubiese estado basado en wordpress hubiese sido muy fácil, pero no, yo tenía que hacerlo con b2evolution, un antepasado de wordpress. Por supuesto, no queriendo resignarme por completo a perderlo todo, hice una copia de seguridad de la base de datos que ha estado acumulando polvo estos meses. Este blog mismo ha estado abandonado también. El hecho de que apenas tuviese unos pocos artículos lo hacía parecer poco valioso ante mis ojos. Y no es que mis artículos hayan sido nunca algo realmente bueno.

El caso es que esta semana he estado reforzando vínculos entre todas mis cosas en Internet. Principalmente entre el canal de youtube, este blog y mis dos podcasts. De alguna manera era buena idea invertir algo de tiempo en rescatar algunos de los posts antiguos y como la tarea no ha sido del todo infructuosa, he pensado en compartirlo contigo, querido lector.

Punto de partida


Para hacer lo que me proponía contaba con una copia de los archivos del blog y un archivo con la base de datos en formato SQL. Mi primera acción consistió en evaluar el archivo de la base de datos y localizar los datos de los posts. La tabla que más prometía era 'evo_items__item'. Ahí estaban todos los artículos. Contaba con la consulta de creación de la tabla así como los "inserts" propiamente dichos. El problema es que esta tabla tenía más de 30 columnas. La consulta estaba en formato mysql, pero yo quería usar sqlite3 para no tener que montar un servidor y tener fácil acceso desde un script de bash, que era lo que tenía en mente hacer. Había cosas en la creación que eran incompatibles con sqlite3 y tenía que editar columna por columna. Era mucho mejor tirar de una tabla con menos columnas. Así fue como di con la tabla 'evo_items__version'.

CREATE TABLE IF NOT EXISTS `evo_items__version` (
`iver_ID` int(10) unsigned NOT NULL,
`iver_itm_ID` int(10) unsigned NOT NULL,
`iver_edit_user_ID` int(10) unsigned DEFAULT NULL,
`iver_edit_datetime` datetime NOT NULL,
`iver_status` enum('published','community','deprecated','protected','private','review','draft','redirected') DEFAULT NULL,
`iver_title` text,
`iver_content` mediumtext,
KEY `iver_ID_itm_ID` (`iver_ID`,`iver_itm_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Una vez eliminadas las partes incompatibles y retiradas las constraints, que al fin y al cabo no necesitaba, se quedó así.
CREATE TABLE `evo_items__version` (
`iver_ID` int(10) NOT NULL,
`iver_itm_ID` int(10) NOT NULL,
`iver_edit_user_ID` int(10) DEFAULT NULL,
`iver_edit_datetime` datetime NOT NULL,
`iver_status` DEFAULT NULL,
`iver_title` text,
`iver_content` mediumtext
);
Creé la base de datos e introduje la consulta. Funcionó sin problemas. Después hice un copia y pega del primer insert y vi que funcionaba sin necesidad de cambiar nada. Así que copié y pequé el resto de inserts y esperé a que terminaran de ejecutarse. Con este proceso ya tenía la tabla con los artículos. Yo realmente sólo necesitaba 'iver_title' e 'iver_content' que contenían respectivamente el título y el contenido de cada post.

El siguiente problema que me encontré fue que obviamente esta tabla contenía un histórico de versiones de cada artículo. Necesitaba seleccionar la última versión de cada post. Eso lo solucioné con la siguiente consulta:
select iver_title, iver_content
from evo_items__version as a
where a.iver_edit_datetime = (select max(iver_edit_datetime) from evo_items__version as b where b.iver_itm_ID = a.iver_itm_ID)
order by a.iver_edit_datetime
Esta consulta permite escoger la versión de fecha mayor, teniendo el inconveniente de que si hay dos versiones con misma fecha y hora salen las dos. Pero no era problema, porque una vez subidos todos podría eliminar los repetidos en blogger escogiendo la mejor versión. Ya tenía el tema de la base de datos resuelto.

Planteamiento de la importación


La idea era hacer un script que hiciera la consulta de arriba a la base de datos y que recorriera los resultados. Por cada post enviaría un email a blogger. Antes de nada tenía que configurarlo. Así que me fui a blogger y entré en configuración. Allí hay un apartado llamado "correo electrónico". En él nos ofrece una dirección de correo electrónico mediante la cual podemos publicar. Nos ofrece una parte fija y una variable en la cual tenemos que introducir una palabra secreta. Una vez guardado tendremos que enviar los posts a la dirección completa. En mi caso marqué la opción de guardar correos electrónicos como entradas de borrador. También te da la opción de publicar nada más llegue el correo. Como iba a hacer varias pruebas, era mejor que se quedasen como borrador.

El script de bash

El script tiene dos ficheros. El principal "blogger", y "database" que contiene las funciones de acceso a la base de datos. El motivo de la separación es doble. Por un lado, ya tenía escrita la parte de la base de datos para otros scripts y por otro, para no complicar demasiado el script principal. Al principio del script, se carga "database" y se define un array llamado "ARTICULO". Este array contendrá las distintas columnas de la base de datos. Después hay una función cuyo cometido es convertir lo que devuelve la consulta, que no es más que tres columnas de la tabla separadas por el caracter "|". Esta función separa cada columna en una celda del array "ARTICULO" de forma que luego pueda extraerse en formato diccionario.

Entonces se hace la consulta a la base de datos y se carga en la variable "datos". Esta variable después se cargará en un array "datosa" para facilitar su acceso. Este array se recorre luego en el bucle principal.

Y cada resultado es procesado para meterlo en "ARTICULO" de forma que se pueda acceder mediante "ARTICULO[title]" al título y mediante "ARTICULO[content]" al contenido del post en sí. Una vez hecho esto, se realizan algunas modificaciones al contenido. Básicamente convierten "&gt;" en ">" y "&lt;" en "<" de forma que cuando se convierta el html en texto no haya fallos. El resultado se mete en un archivo que después se le pasa al programa "w3m" que es el que realiza la conversión de html a texto. Hago esto porque al mandar el post en html salía el html como si fuese texto y algunas etiquetas las convertía por protección en caracteres html, lo que hacía muy complicado trasladarlo. Así que decidí enviarlo en texto sin formato.

El envío se hace con mutt de una forma rápida. Pero al llegar daba errores de buzón lleno o de que estaban llegando demasiados correos, por lo que estuve experimentando con diferentes retardos y al final opté por dejar 45 segundos entre post y post. Con ese retardo ya no aparecieron errores y llegaron los 50 posts que envié. Eso hizo que le tomara algo más de media hora enviar todo. Quizá parezca mucho, pero en ese tiempo puedes ver una serie o hacer otras cosas. Al final es un proceso por lotes en el que casi todo el proceso es espera.

A continuación os pongo el script.
#!/bin/bash
#Subir articulos antiguos de la base de datos a blogger
source /home/mhyst/bin/scripts/blogger/database
declare -A ARTICULO
#@ film.parse datos (Formato: (id|titulo|fichero|torrent|esserie|esvisto|esdescargado))
function parse() {
local datos="$1"
#echo "$datos" > /dev/tty
IFS='|' read -a datosa <<< "$datos"; IFS=" "
#ARTICULO[ver]="${datosa[1]}"
ARTICULO[id]="${datosa[0]}"
#ARTICULO[user]="${datosa[3]}"
#ARTICULO[date]="${datosa[4]}"
#ARTICULO[status]="${datosa[5]}"
ARTICULO[title]="${datosa[1]}"
ARTICULO[content]="${datosa[2]}"
# echo "-----------------------------"
# echo "Campos: ${#datosa[@]}/${#ARTICULO[@]}"
# echo "ver_id> ${ARTICULO[ver]}"
# echo "item_id> ${ARTICULO[id]}"
# echo "user_id> ${ARTICULO[user]}"
# echo "date> ${ARTICULO[date]}"
# echo "status> ${ARTICULO[status]}"
# echo "title> ${ARTICULO[title]}"
# echo "content> ${ARTICULO[content]}"
# echo "-----------------------------"
}
datos=$(db.executeQuery "select distinct iver_itm_ID, iver_title, iver_content from evo_items__version as a where a.iver_edit_datetime = (select max(iver_edit_datetime) from evo_items__version as b where b.iver_itm_ID = a.iver_itm_ID) order by a.iver_edit_datetime")
if [[ "$datos" == "" ]]; then
echo "No hay artículos" > /dev/tty
exit
fi
readarray -t datosa <<< "$datos"
echo "Artículos encontrados: ${#datosa[@]}" > /dev/tty
if [[ ${#datosa[@]} == 0 ]]; then
echo "No hay artículos" > /dev/tty
exit
fi
let i=0
for post in "${datosa[@]}"; do
parse "$post"
texto=$(sed 's/\&gt;/>/g' <<< "${ARTICULO[content]}")
texto=$(sed 's/\&lt;/</g' <<< "$texto")
echo "$texto" > /tmp/blogger.html
texto=$(w3m -dump /tmp/blogger.html)
#texto="${ARTICULO[content]}"
echo
echo "-----------------------------------------"
echo "$texto"
echo "-----------------------------------------"
echo
echo "$i - ${ARTICULO[title]}" > /dev/tty
echo "$texto" | mutt -s "${ARTICULO[title]}" mhyst_el_otro.zenzen@blogger.com
sleep 45s
(( i++ ))
done
echo "$i artículos enviados"
view raw blogger.sh hosted with ❤ by GitHub
#!/bin/bash
#Módulo para trabajar con la base de datos
#Localización de la base de datos. Debe incluir el nombre del fichero
database_DB="/home/mhyst/bin/scripts/blogger/blogger.db"
#Si la base de datos no existe, la creamos
if ! [ -f "$database_DB" ]; then
echo "La base de datos no existe"
init
fi
#En adelante esta variable se usará para ejecutar sqlite3 con nuestra base de datos
database_SQLITE="sqlite3 $database_DB"
#Si ĺa última operación fue un insert, ROWID contendrá el id del registro insertado.
#Si este valor es -1 debe entenderse que su contenido no sirve o que ha habido un error.
ROWID=-1
#Hacer consultas a la base de datos
#Nótese que he utilizado transacciones para evitar que la base de datos quede bloqueada
function db.executeQuery() {
sql="$1"
$DEBUG && echo "SQL: $sql" >> /tmp/blogger.txt
local res=`$database_SQLITE "BEGIN; $sql; END TRANSACTION"`
if [ $? != 0 ]; then
echo "SQL ERROR: $sql" >> /tmp/blogger.txt
fi
echo "$res"
}
#Inserciones y actualizaciones de la base de datos
#Igual que en la función anterior, se han usado transacciones
#Si la operación es un insert, una vez insertado se obtendrá el ROWID
#Esto sucederá también con los updates, pero no haremos caso a ese dato.
function db.executeUpdate() {
sql="$1"
$DEBUG && echo "SQL: $sql" >> /tmp/blogger.txt
if [[ "${sql,,}" == "insert"* ]]; then
local res=`$database_SQLITE "BEGIN; $sql; select last_insert_rowid(); END TRANSACTION"`
ROWID=$res
else
local res=`$database_SQLITE "BEGIN; $sql; END TRANSACTION"`
ROWID=-1
fi
if [ $? != 0 ]; then
echo "SQL ERROR: $sql" >> /tmp/blogger.txt
fi
view raw database hosted with ❤ by GitHub

Últimos retoques


Me tomó solo un par de horas entre idear este método y llevarlo a cabo, incluyendo la creación de la base de datos y la importación, el diseño de la consulta, escribir el código, etc. Conseguir que se subiera todo bien me costó algo más tiempo y no fue hasta el día siguiente de escribir el script que lo dejé todo subido. Después tuve que editar los borradores, porque presentaban un problema. El texto no tenía cohesión, había nuevas líneas y "<br>" por todas partes. Podía haber retirado los "<br>" de forma simple con un sencillo comando:

sed 's/<br>//g' archivo

Pero como ya tenía todo subido y no quería esperar otra media hora, decidí hacer esos retoques a mano. Lo que hice fue abrir las propiedades de todos los borradores que quería publicar, copiar el texto a "sublime text", con reemplazar quité los "<br>"s, y añadí etiquetas "<p align='justify'></p>" y otras donde fue necesario mediante copiar y pegar. Después volví a copiar el texto en blogger. Creo que fueron doce artículos y me llevó menos de un minuto (utilizando atajos de teclado como control+a, control+c y control+v) por cada uno. En unos 10 minutos tenía todo hecho.

Está claro que para hacer algo similar a lo que he descrito se necesitará algo de planificación. La tabla a usar puede no ser la misma y la consulta puede que no necesite ser tan larga. Si no usas mutt, habrá que buscar otra manera de enviar los correos a blogger.  Hay muchas formas de hacer eso. Está claro que no bastará con repetir lo que yo he hecho. Pero este tipo de soluciones abren muchos caminos para hacer multitud de cosas. Más que nada por eso quería compartirlo contigo.

Si has llegado hasta aquí, ¡enhorabuena! Un saludo y gracias por leerlo.

Comentarios

Entradas populares de este blog

¿Es España una Democracia?

Introducción Muy buenas. Hace ya algunos días que publiqué un audio sobre este tema titulado "Las Reglas del Juego", haciendo referencia al juego político, y últimamente había tomado por costumbre escribir una entrada en el blog para cada episodio de Reality Cracking , aunque en esta ocasión me limité a copiar la descripción. Y tenía pendiente un tratamiento más serio del tema. Porque uno de los defectos de mis audios es que suelo improvisarlos partiendo de una idea que tengo en la cabeza. A veces hago una lista con las cosas que preveo mencionar en el audio, pero eso es todo. Acepto que queda muy bien en la radio cuando la locución es perfecta y las ideas se presentan prístinas ante nuestros oídos, pero a mi no me gusta nada leerle al micrófono lo que dice en un papel. Quizá se deba a que, dado lo mal comunicador que soy, las veces que he hecho experimentos de ese tipo ha quedado muy poco natural. En resumen, por unas cosas o por otras, suelo improvisar. La...

La realidad del discurso único

Llevaba bastantes años sin ver la tele. Pero lo que se dice sin ver la tele nada de nada, salvo momentos puntuales, cuando por algún motivo entraba en una habitación donde algún familiar estaba viendo la tele y podía dedicar esas escasos miradas a la pantalla durante mi paso por la habitación. Fácilmente esta situación de servidor sin ver la tele sucede desde 2005. Quizá incluso desde antes.  Vivía yo muy feliz de esta guisa, sin preocuparme de las estupideces que se vertieran en la tele. Y sobre todo sin tragar anuncios. Pero, hete aquí que cae uno enfermo de un virus intestinal que lo deja para el arrastre durante varias semanas y no tiene uno ganas de hacer nada y para colmo hace tanto calor que no apetece exponerse al calor adicional de encender el ordenador. Es entonces cuando empiezas a ver de nuevo la tele y aceptas sin demasiadas reticencias debido a la situación, de nuevo ver anuncios y programas con continuas interrupciones absurdas con anuncios repetitivos. E...

Crisis y vuelta

A ver cómo digo esto sin que suene muy cursi ni que parezca que me ha sobrevenido una especie de epifanía. Creo que iré directo al grano. Es lo mejor. A principios de junio de este 2024 tuve una grave crisis de salud. Sufrí una hiponatrenia, que es un desequilibrio de electrolitos, concretamente del sodio, que me puso literalmente al borde de la muerte. Al parecer cuando te baja el nivel del sodio a ciertos niveles, se da un proceso destructivo por el que, en tu cerebro, el sodio se va sustituyendo por agua, lo que produce una dañina inflamación. Con una cantidad de sodio en sangre por debajo de 135 moles por litro corres el riesgo de tener convulsiones y después la muerte. Lo que me salvó la vida fue que me hicieron un análisis de sangre y alguien estuvo atento. Mi nivel de sodio estuvo en 125, lo que es 10 unidades menos del límite. Pasé unos días hospitalizado. Tuve un más que evidente deterioro cognitivo, con pérdida de memoria y de facultades. Incluso el habla se me vio afe...