Seguimos con la traducción de algunos capítulos del libro The Programming Historian, de William J. Turkel, Adam Crymble y Alan MacEachern.
Ahora vamos con el capítulo 6.

Salida en HTML

Poniendo la nueva información donde pueda usarse.

Ya aprendimos a usar Python para bajar documentos online y extraer información de ellos de modo automático. Recuerde que nuestro último objetivo es incorporar discretamente la programación en nuestra práctica histórica. Puesto que ya utiliza Firefox y Zotero para hallar y mantener sus recursos sería lógico que usara dichos programas para mantener la nueva información que obtengamos. La forma más fácil de hacerlo es hacer que sus programas en Python graben páginas web en su computadora, que puedan ser leídas en Firefox e indexadas y anotadas con Zotero. Vamos a hacer eso ahora, comenzando con una discusión sobre algunas cosas más que podemos hacer con cadenas en Python.

Formateando cadenas en Python

Python incluye un operador especial de formateo que le permite interpolar una cadena en otra. Está representado por el signo de porcentaje. Abra una sesión de Python y pruebe los siguientes ejemplos:

frame = 'Esto es un %s'
print frame
-> Esto es un %s
 
print frame % 'gato'
-> Esto es un gato
 
print frame % 'perro'
-> Esto es un perro

También hay un modo para interpolar una lista de cadenas en otra cadena:

frame2 = 'Estos son %s y %s'
print frame2
-> Estos son %s y %s
 
print frame2 % ('gatos', 'perros')
-> Estos son gatos y perros

En estos ejemplos, un %s en una cadena indica que otra cadena deberá incrustarse en ese lugar. Hay otros códigos de formateo de cadenas que nos permiten insertar números en cadenas en distintos formatos, como %i para enteros, %f para decimales de punto flotante, y así. Después seguiremos con ese tema.

Creando HTML

Una de las más poderosas ideas en informática es que algo que es código desde una perspectiva puede ser visto como dato desde otra. Esto es posible, en otras palabras, al escribir programas para manipular otros programas. El intérprete Python es un ejemplo. Lo que vamos a hacer ahora es combinar archivos de Python, cadenas de varios renglones, y simples etiquetas HTML para crear un programa en Python que cree archivos HTML de salida. Observe que escribimos un archivo con extensión .html en lugar de .txt.

# escribir-html.py
 
f = open('holamundo.html','w')
 
mensaje = """<html>
<head></head>
<body>Hola Mundo!</body>
</html>"""
 
f.write(mensaje)
f.close()

Guarde este programa como escribir-html.py y ejecútelo. Use File->Open->File en el Komodo para abrir holamundo.html y verificar que su programa haya creado el archivo. Esto se verá así:

pythont
"Hola Mundo" HTML generado por un programa en Python

Ahora vaya al browser Firefox y elija File->New Tab, vaya a la solapa y elija File->Abrir archivo. Seleccione holamundo.html. Ahora puede ver el mensaje en el browser.

Enviando HTML al Firefox

Creamos automáticamente un archive HTML pero tenemos que salir del Komodo e ir al Firefox para abrir el archivo en una nueva solapa. ¿No sería bueno que nuestro programa en Python incluyera este último paso? Ingrese el siguiente código y guárdelo como escribir-hmtl-2.py. Cuando lo ejecute, creará su archivo HMTL y luego automáticamente lo abrirá en una nueva solapa del Firefox.

# escribir-hmtl-2.py 
 
import webbrowser
 
f = open('holamundo.html','w')
 
mensaje = """<html>
<head></head>
<body>Hola Mundo!</body>
</html>"""
 
f.write(mensaje)
f.close()
 
webbrowser.open_new_tab('holamundo.html')
[Algunas personas no pudieron ejecutar el programa: más sobre el tema en la solapa discussion del wiki.]

Autodocumentar archivos de datos

La distinción entre data y metadata es crucial para las ciencias de la información. Metadatos son datos sobre datos. El concepto puede ser muy familiar para Ud., aún si nunca escuchó antes el término. Considere un libro tradicional. Si tomamos el texto del libro como data, hay varias características que están asociadas a ese texto pero que pueden o no estar explícitamente impresas en el libro. El título del trabajo, el autor, la editorial y el lugar y la fecha de la publicación son metadatos que generalmente están impresos en el libro. El lugar y fecha de la escritura, el nombre del editor, la ubicación del libro en el catálogo de la Biblioteca del Congreso, y el nombre de la fuente usada en el diseño a veces se incluyen en libro. La persona que compró un libro, puede o no escribir su nombre en las primeras páginas. Si el libro pertenece a la colección de una biblioteca, dicha biblioteca puede agregar metadatos adicionales, y sólo algunos de estos pueden estar físicamente ligados al libro. El registro de préstamo, por ejemplo, usualmente se lleva en una base de datos de algún tipo y se relaciona con el libro a través de un identificador único. Bibliotecas, archivos y museos mantienen, todos ellos, sistemas automáticos para generar y mantener esos metadatos.
Si usted trabaja con datos digitales, es una buena idea incorporar metadatos en sus archivos cuando sea posible. En secciones posteriores trabajaremos con el Extensible Markup Language (XML), que es ideal para ese propósito. Por ahora, no obstante, necesitaremos desarrollar unas pocas estrategias para autodocumentar nuestos archivos de datos.

Comentarios en Python

Ya vimos un ejemplo de esto. En Python, cualquier línea que comience con una almohadilla (#) es reconocida como comentario y es ignorada por el intérprete Python. Los comentarios se hacen con la intención de permitir a los programadores comunicarse entre sí. En buena medida, los programas mismos están escritos y formateados de manera que permita la comunicación entre programadores. Los códigos que están cerca de los requerimientos de una máquina son conocidos como lenguajes de bajo nivel y los que están cerca del lenguaje natural son conocidos como de alto nivel. Uno de los beneficios de usar un lenguaje como Python es que es de muy alto nivel, lo que hace muy fácil la comunicación entre nosotros y usted (con su respectivo costo en términos de eficiencia computacional).

Construyendo un “wrapper” para HTML

Ya aprendimos cómo incrustar un mensaje como “Hola mundo” en etiquetas HTML, escribir el resultar en un archivo y abrirlo automáticamente en el browser. Un programa que pone código de formato en un texto utilizado por otro programa es un wrapper. Lo que vamos a hacer ahora es desarrollar un wrapper para HTML, para la salida de nuestro código que computa las frecuencias de palabras.
Juntemos parte de los códigos que ya escribimos en algunas funciones. Una de ellas, a partir de una URL, retornaba una cadena de texto en minúsculas desde una página web. Copie esto en el módulo dh.py.

# Dada una URL, retorne una cadena en minúsculas desde la página.
 
def webPageToText(url):
    import urllib2
    response = urllib2.urlopen(url)
    html = response.read()
    texto = stripTags(html).replace('&nbsp;', ' ')
    return texto.lower()

También queremos una función que tome una cadena de cualquier clase y la ponga en el cuerpo de un archivo HTML, el cual será visualizado en Firefox inmediatamente. Este función puede incluir algunos metadatos básicos, como la hora y la fecha en que fue creado el archivo, así como el nombre del programa que lo creó. Estudie atentamente el siguiente código, luego cópielo en el módulo dh.py.

# Dados un nombre de programa desde el cual se llama a la función, una # URL y una cadena para wrapear,
# genera una cadena en el cuerpo de un archivo HTML con metadatos 
# básicos, y la abre en una ventana de Firefox.
 
def wrapStringInHTML(programa, url, body):
    import datetime
    from webbrowser import open_new_tab
    ahora = datetime.datetime.today().strftime("%Y%m%d-%H%M%S")
    filename = programa + '.html'
    f = open(filename,'w')
    wrapper = """<html>
        <head>
        <title>%s output - %s</title>
        </head>
        <body><p>URL: <a href=\"%s\">%s</a></p><p>%s</p></body>
        </html>"""
    whole = wrapper % (programa, ahora, url, url, body)
    f.write(whole)
    f.close()   
    open_new_tab(filename)

Observe que esta función hace uso de un operador de formato de cadena que ya mencionamos. Es ese operador el que llama a la biblioteca Python denominada datetime para determinar la fecha y hora actual. Este metadato, junto con el nombre del programa que llama a la función, es guardado en la etiqueta título (title) del HTML. El archivo HTML que es creado tiene el mismo nombre que el programa Python que lo crea pero con una extensión .html en lugar de una .py.

Poniendo todo junto

Ahora vamos a crear otra versión de nuestro programa para computar frecuencias. En lugar de enviar los resultados al panel de salido del Komodo, los enviaremos a un archivo HTML que será abierto en una nueva pestaña del Firefox. Desde ahí, los resultados pueden ser agregados fácilmente a Zotero. Copie el siguiente código en el Komodo, guárdelo como html-to-freq-3.py y ejecútelo para confirmar que el programa trabaja como esperamos.

# html-to-freq-3.py
 
import dh
 
# crea un diccionario ordenado de pares de palabra-frecuencia.
url = 'http://niche.uwo.ca/programming-historian/dcb/dcb-34298.html'
texto = dh.webPageToText(url)
fullwordlist = dh.stripNonAlphaNum(texto)
wordlist = dh.removeStopwords(fullwordlist, dh.stopwords)
dictionary = dh.wordListToFreqDict(wordlist)
sorteddict = dh.sortFreqDict(dictionary)
 
# compila el diccionario en una cadena y le agrega los 
# metadatos de HTML.
 
outstring = ""
for s in sorteddict:
    outstring += str(s)
    outstring += "<br />"
dh.wrapStringInHTML("html-to-freq-3", url, outstring)

Fíjese que entremezclamos nuestros pares de palabra-frecuencia con la etiqueta HTML llamada break, la que genera una nueva línea. Si todo va bien, usted podrá ver las mismas frecuencias de palabras que computamos en la última sección.

Utilizando frecuencias de palabras para refinar una búsqueda en Google

Agreguemos un giro más de sofisticación. Comenzamos con una búsqueda en Google de “dollard” y contamos el número de “hits” en las primeras cinco páginas que actualmente refieren a Adam Dollard Des Ormeaux. Cuando nosotros [los autores] probamos esto era 7/01/2008, y terminamos con 3 de 50 o 6% del total.
Ahora vamos a hacer una búsqueda de "dollard iroquois long sault enemy" y contamos el número de “hits” que refieren a Adam Dollard Des Ormeaux. Cuando probamos esto el 7 de enero de 2008, tuvimos 50 sobre 50 o 100%. Estas últimas palabras que usamos son características del texto, y podemos fácilmente hallar otras como ellas. ¿No sería bueno hacerlo automáticamente?
Observe la URL de la búsqueda de Google que hicimos. Comienza con algo así:

http://www.google.com/search?q=dollard+iroquois+long+sault+enemy

Supongamos que queremos hacer un número pequeño de estas consultas. Si tomamos los n términos más altos en nuestra lista de frecuencias de palabras, podemos construir una consulta como esa automáticamente y hacer un link para cada página formateada con los resultados.
La forma básica del hyperlink en HTML es

<a href="URL">NombreDelLink</a>

Queremos hacer automáticamente la URL para la búsqueda de Google y debemos incrustrar esa URL en una etiqueta a de HTML como la de arriba. Estudie con atención la siguiente función y agréguela en el módulo dh.py.

# Dada una lista palabras y un nombre de link, devuelve
# un link a un archive HTML con una búsqueda de Google para la lista.
 
def keywordListToGoogleSearchLink(keywords, linkname):
    gsearch = '<a style=\"text-decoration:none\" '
    gsearch += 'href=\"http://www.google.com/search?q='
    gsearch += '+'.join(keywords)
    gsearch += '\">'
    gsearch += linkname
    gsearch += '</a>'
    return gsearch

Fíjese que agregamos algunas líneas de CSS a la etiqueta a del HTML para prevenir que el browser subraye automáticamente el hyperlink. Aprenderemos más sobre CSS (Cascading Style Sheets) más tarde; por ahora sólo haremos las salidas de los próximos programas que escribamos resulten más legibles.

(hay una cosa en este código que es contraintuitiva. Para crear una cadena desde la lista, llamamos al método join para utilizar el delimitador que queremos entre los elementos de la lista. El delimitador es un signo más (+) en nuestro caso ya que estamos construyendo una cadena de consulta de una URL. Mucha gente da por sentado que join es un método de listas pero no es así.)
Puede probar la function en una sesión del intérprete Python si quiere. Cópiela y péguela en Python y ejecútela. Luego, puede hacer lo siguiente:

testwords = ('this', 'is', 'a', 'test')
print keywordListToGoogleSearchLink(testwords, "Do Google Search")
-> <a style="text-decoration:none" 
      href="http://www.google.com/search?q=this+is+a+test">Do Google Search</a>

Ahora puede revisar nuestro código para incluir nuestro búsqueda automática y creador de links. Copie el siguiente código en el Komodo, guárdelo como html-to-freq-4.py y ejecútelo.

# html-to-freq-4.py
 
import dh
 
# crea un diccionario ordenado de pares de frecuencia-palabras
 
url = 'http://niche.uwo.ca/programming-historian/dcb/dcb-34298.html'
texto = dh.webPageToText(url)
fullwordlist = dh.stripNonAlphaNum(texto)
wordlist = dh.removeStopwords(fullwordlist, dh.stopwords)
dictionary = dh.wordListToFreqDict(wordlist)
sorteddict = dh.sortFreqDict(dictionary)
 
# crea el link de búsqueda en Google.
keywords = []
for k in sorteddict[0:5]:
    keywords.append(str(k[1]))
gsearch = dh.keywordListToGoogleSearchLink(keywords, 'Google Search n=5')
 
# compila el diccionario en una cadena y en un HTML con datos.
outstring = gsearch + "<br /><br />"
for s in sorteddict:
    outstring += str(s)
    outstring += "<br />"
dh.wrapStringInHTML("html-to-freq-4", url, outstring)

Cuando pruebe este programa, verá que hay un hyperlink en la salida que puede clickear para enviar la búsqueda refinada a Google. Como un ejercicio, trate de modificar su script para procesar la biografía del explorador Pierre-Esprit Radisson (1640-1710). Podrá ver que las búsquedas generadas automáticamente harán más fácil hallar contenido relevante para su trabajo.