viernes, marzo 16, 2012

El historial de Safari: Uso de plist desde Python


Tenía la curiosidad por saber como el navegador de Apple - Safari - almacena el historial en la cuenta de cada usuario. Pensaba que iba a usar sqlite, como hace por ejemplo Firefox, pero tras mirar en ~/Library/Safari el fichero que contiene el historial es History.plist. Esta es un archivo en formato plist binario.

Para poder curiosear con él, lo primero que hay que hacer es pasarlo a formato de texto, que es un xml codificado con el formato utf-8. Para facilitar la conversión MacOS X tiene la herramienta en línea de comandos plutil. La conversión de salida está controlada por la opción -convert, así que si queremos pasar la plist binaria a una plist en XML, se puede
hacer con la siguiente orden:


swordcoast:~ terron$ plutil -convert xml1 -o history_xml.plist History.plist

La order anterior habrá creado el fichero history_xml.plist que se puede ver con cualquier editor de texto que soporte codificaciones utf-8 como vim

Como muchos sabréis, si se tiene el Xcode instalado, se puede abrir la lista en formato binario sin problemas. Con un simple open History.plist en la línea de comandos se puede ver el contenido de la misma y editarlo si se desea - suponiendo que el sistema tenga asociado la extensión .plist a Xcode -.

Me gusta bastante Python, y quería procesar el contenido de la lista - una vez convertida a formato XML - para ver las entradas que había ido visitando. No es necesario parsear el XML, puesto que Python tiene un módulo oficial, plistlib que nos permite leer y procesar los ficheros plist de MacOS X. Por ejemplo el siguiente script lee el historial en XML, escribe la URL y la fecha de la última visita.


#!/usr/bin/python
import plistlib
import sys
import time
import calendar

def dump_files (filepath):
    pl = plistlib.readPlist(filepath)
    history = pl['WebHistoryDates']
    for entry in history:
            url = entry['']
            lastdate = float(entry['lastVisitedDate'])
            toffset = calendar.timegm(time.strptime("01/01/2001", "%d/%m/%Y"))
            print "%s;'%s'" % (time.ctime(lastdate),url)+toffset
for f in sys.argv[1:]:
        dump_files(f)

Como puede verse, plist.readPlist() nos devuelve una lista donde cada una de las entradas es un diccionario. En este caso, cada entrada tiene una serie de claves que se puede obtener:

ClaveDescripción
vacíaLa URL del historial.
displayTitleTítulo de la página a la que se ha visitado.
lastVisitedDateFecha de la última visita
titleTítulo de la página tal como se ha obtenido del servicor
visitCountNúmero de visitas
lastVisitWasFailureBoleano que indica que la última visita ha fallado

Aparte, existe otros campos que son arrays como W y D que no se lo que son. Un detalle sobre el campo lastVisitedDate es que implica el número de segundos desde el 1 de enero del 2001, ya que corresponde con el tipo de datos CFAbsoluteTime que mide el tiempo desde el 1 de enero del 2001 GMT. Por eso el script suma toffset a la hora de convertir el tiempo para la referencia de Unix


Technorati Tags: ,

No hay comentarios: