Historia Digital

The programming historian 2

Un segundo tutorial para enseñarle a programar python a historiador*s y aledaños. La increíble potencia que paso tras paso revela el lenguaje contrasta con la remotas chances de usarlo en una investigación; pero eso sólo le importa a las mentes que todavían creen que primero está la creencia y después la hostia, no?
En definitiva, un muy buen recurso en busca de cursantes:
http://programminghistorian.org

the Programming Historian, parte IV

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 5.

Calculando frecuencias

Medidas usuales para textos

En la sección anterior, escribimos un programa en Python al que llamamos html-a-lista-1.py . Dicho programa sirve para bajar una página web a la que le quita el formateo HTML y los metadata, y luego nos devuelve una lista de “palabras”, como esta:

 ['Dictionary', 'of', 'Canadian', 'Biography', 'DOLLARD', 'DES', 
'ORMEAUX', '(called', 'Daulat', 'in', 'his', 'death', 'certificate', 
'and', 'Daulac', 'by', 'some', 'historians),', 'ADAM,', 'soldier,',
'\x93garrison', 'commander', 'of', 'the', 'fort', 'of', 
'Ville-Marie', '[Montreal]\x94;', 'b.', '1635,', 'killed', 'by', 
'the', 'Iroquois', 'at', 'the', 'Long', 'Sault', 'in', 
'May 1660.', '\xa0\xa0\xa0\xa0\xa0', 'Nothing', 'is', 'known', 
'of', 'Dollard\x92s', 'activities', 'prior', 'to', 'his', 'arrival', 
'in', 'Canada', 'except', 'that', '\x93he', 'had', 'held', 'some', 
'commands', 'in', 'the', 'armies', 'of', 'France.\x94', 'Having', 
'come', 'to', 'Montreal', 'as', 'a', 'volunteer,', 'very', 
'probably', 'in', '1658,', 'he', 'continued', 'his', 'military', 
'career', 'there.', 'In', '1659', 'and', '1660', 'he', 'was', 
'described', 'as', 'an', '\x93officer\x94', 'or', '\x93garrison', 
'commander', 'of', 'the', 'fort', 'of', 'Ville-Marie,\x94', 'a', 
'title', 'that', 'he', 'shared', 'with', 'Pierre', 'Picot\xe9', 
'de', 'Belestre.', 'We', 'do', 'not', 'however', 'know', 'what', 
'his', 'particular', 'responsibility', 'was.']

Debido a que ya sabemos leer, esa habilidad del programa, por sí misma, no es muy importante. Pero podemos usar el texto para hacer cosas que usualmente no son posibles sin un software especializado. Vamos a empezar calculando las frecuencias de palabras y de otras unidades lingüísticas.

Limpiando la lista

Está claro que nuestra lista necesitará un poco de limpieza antes de que podamos usarla para contar frecuencias. Antes que nada, no queremos saber las frecuencias atadas a mayúsculas o minúsculas: “Dollard” y “DOLLARD” deberían ser contadas como la misma palabra. Normalmente las palabras son clasificadas en minúsculas cuando contamos frecuencias, por lo que está bien utilizar el método de cadena lower.

print('Hola MUNDO'.lower())
-> hola mundo

Hay distintas marcas de puntuación que nos cambiarían el conteo de frecuencia si las incluiríamos en él. Queremos que “soldado:” sea contabilizada como “soldado” y “[Montreal]” como “Montreal”. Mirando en la impresión en el panel de salida del Komodo, encontramos también “&nbsp ;” que es el código HTML para el ampersand. Utilizando otro método de cadena, podemos reemplazar ese código con un espacio en blanco, de la siguiente manera:

print('hola mundo')
-> hola mundo
 
print('hola mundo'.replace(' ',' '))
-> hola mundo

Hay también un grupo de caracteres acentuados franceses que son representados con cadenas Unicode como “\xe9” (que indica “é”). Aprenderemos más acerca de trabajar con caracteres Unicode más tarde; por ahora vamos a dejarlos como están.
En este punto, podríamos mirar en otras entradas DCB [de ese diccionario se extrajo la página web del ejemplo] y en un rango más amplio de potenciales fuentes de documentos para asegurarnos que no haya otros caracteres especiales que nos traigan problemas más adelante. Podríamos también anticipar situaciones donde no queremos quitar la puntuación (por ejemplo, el signo que distingue un monto de dinero como en “$1629” de un año, o el que distingue el sentido de “1629-40” del otro en “1629 40”). Esto es lo que hace que los programadores profesionales cobren: tratar de pensar todo lo que puede estar mal por adelantado.

Vamos a encarar otra aproximación. Nuestro principal objetivo es desarrollar técnicas que un historiador o una historiadora puedan utilizar durante su investigación. Esto significa que siempre vamos a preferir la solución correcta que pueda desarrollarse rápidamente. Más que dedicar tiempo a hacer nuestro programa robusto frente a excepciones, simplemente vamos a descartar todo aquello que no sea una letra acentuada o sin acentuar o un número arábigo. La programación es normalmente un proceso de refinamiento por etapas. Comenzamos con un problema y con una solución parcial, y entonces procedemos a refinar nuestra solución hasta hacer algo que funcione mejor.

Nuestro primer uso de expresiones regulares.
A los efectos de eliminar caracteres especiales, vamos a hacer uso de un poderoso mecanismo llamado expresiones regulares. Las expresiones regulares son facilitadas por muchos lenguajes de programación de distintas maneras. Para hacer lo que queremos ahora, tenemos que importar la biblioteca de expresiones regulares de Python y compilar un patrón que encuentre cualquier cosa que no sea un carácter alfanumérico. Copie la siguiente función y péguela en el módulo dh.py.

# Dada una cadena de texto, remueva todos los caracteres alfanuméricos
# (utilizando la definición Unicode de alfanumérico).
 
def stripNonAlphaNum(texto):
    import re
    return re.compile(r'\W+', re.UNICODE).split(texto)

La expresión regular en el código de más arriba es \W+. La \W es la forma abreviada para significar la clase de caracteres alfanuméricos. En las expresiones regulares de Python, el signo más (+) encuentra una o más copias de un caracter determinado. El re.UNICODE le dice al intérprete que queremos incluir caracteres de otros idiomas en nuestra definición de alfanumérico, además de las series que van de la A a la Z, de la a a la z, y del / al 9 [N.T: el primer set de caracteres ASCII era etnocéntrico y no incluía signos como las vocales acentuadas o la cedilla; en el texto original las series enumeradas al final de la última oración son del inglés; y todo lo que queda fuera, parte de “los otros idiomas del mundo”]. Las expresiones regulares deben ser compiladas antes de ser usadas, que es lo que el resto de las órdenes del programa hace. No se preocupe por entender el resto de la compilación por ahora.
Al refinar nuestro programa html-a-lista, podemos dejarlo así:

# html-a-lista-2.py
 
import urllib2
import dh
 
url = 'http://niche.uwo.ca/programming-historian/dcb/dcb-34298.html'
 
response = urllib2.urlopen(url)
html = response.read()
texto = dh.stripTags(html).replace(' ', ' ')
wordlist = dh.stripNonAlphaNum(texto.lower())
print wordlist[0:500]

Cuando ejecute el programa y mire el panel de salida del Komodo, podrá ver que ha hecho un mejor trabajo. Como esperábamos, dejó los caracteres acentuados en forma de códigos (así, palabras como “Picoté” aparecen como “picot\xe9”). Dividió los términos con guiones, como “Ville-Marie” en dos palabras, y cambió el posesivo “s” en una palabra separada, dejando fuera el apóstrofo. Esta es una buena aproximación a lo que queríamos hacer, así que podemos avanzar a contar frecuencias antes de intentar hacer este programa mejor. (Si usted trabaja con fuentes en más de un idioma necesitará aprender más acerca del estándar Unicode y acerca del soporte de Python para ese estándar.

Diccionarios de Python

Tanto las cadenas como las listas están secuencialmente ordenadas, lo que quiere decir que podemos acceder a sus contenidos utilizando un index, un número que comienza con 0. Si tiene una lista que contiene cadenas, puede usar un par de índices para acceder, primero, a una cadena en particular, y luego a un caracter específico en esa cadena. Estudie el siguiente ejemplo:

s = 'hola mundo'
print s[0]
-> h
 
print s[1]
-> o
 
m = ['hola', 'mundo']
print m[0]
-> hola
 
print m[1]
-> mundo
 
print m[0][1]
-> o
 
print m[1][0]
-> m

Para llevar la cuenta de las frecuencias, necesitaremos otro tipo de objeto en Python, un diccionario. El diccionario es una colección desordenada de objetos. Esto significa que no podemos usar un índice para recuperar un elemento del mismo. Podemos hacerlo, de todos modos, utilizando una clave (key). Estudie el siguiente ejemplo:

d = {'mundo': 1, 'hola': 0}
print d['hola']
-> 0
 
print d['mundo']
-> 1
 
print d.keys()
-> ['mundo', 'hola']

Fíjese que usamos llaves para definir un diccionario pero corchetes para acceder a las cosas que hay en él. Las operaciones con claves devuelven una lista de claves que están definidas en el diccionario.

Conteo de frecuencia de palabras

Ahora vamos a contar la frecuencia de cada palabra en nuestra lista. Ya vimos que esto es fácil procesar una lista utilizando un bucle for. Pruebe guardando y ejecutando este ejemplo:

# contar-lista-items-1.py
 
wordstring = 'quien mal anda mal acaba '
wordstring += 'dime con quien andas y te dire quien eres'
 
wordlist = wordstring.split()
 
wordfreq = []
for word in wordlist:
    wordfreq.append(wordlist.count(word))
 
print "Cadena\n" + wordstring +"\n"
print "Lista\n" + str(wordlist) + "\n"
print "Frecuencia\n" + str(wordfreq) + "\n"
print "Pares\n" + str(zip(wordlist, wordfreq))

Obtendrá algo como esto:

Cadena
quien mal anda mal acaba dime con quien andas y te dire quien eres
Lista
['quien', 'mal', 'anda', 'mal', 'acaba', 'dime', 'con', 'quien', 'andas', 'y', 'te', 'dire', 'quien', 'eres']
Frecuencia
[3, 2, 1, 2, 1, 1, 1, 3, 1, 1, 1, 1, 3, 1]
Pares
[('quien', 3), ('mal', 2), ('anda', 1), ('mal', 2), ('acaba', 1), ('dime', 1), ('con', 1), ('quien', 3), ('andas', 1), ('y', 1), ('te', 1), ('dire', 1), ('quien', 3), ('eres', 1)]

En ese programa, empezamos con una cadena y la dividimos en una lista, como ya lo habíamos hecho antes. Entonces recorrimos cada palabra de esa lista y contamos las veces que esa palabra aparece en toda la lista. Luego agregamos el resultado a una lista de frecuencias de palabras. Usando el comando zip podemos comparar la primera palabra de la lista de palabras con el primer número de la lista de frecuencias, la segunda palabra con la segunda frecuencia y así sucesivamente. Finalizamos obteniendo una lista de pares (palabras y frecuencias). La declaración str convierte cualquier objeto a una cadena, para poder imprimirlo.
Python incluye una herramienta muy conveniente llamada lista comprensiva (list comprehension), que podemos usar para hacer lo mismo que con el bucle loop pero más económicamente.

# contar-lista-items-2.py
wordstring = 'quien mal anda mal acaba '
wordstring += 'dime con quien andas y te dire quien eres'
wordlist = wordstring.split()
wordfreq = [wordlist.count(w) for w in wordlist]
print "Cadena\n" + wordstring +"\n"
print "Lista\n" + str(wordlist) + "\n"
print "Frecuencias\n" + str(wordfreq) + "\n"
print "Pares\n" + str(zip(wordlist, wordfreq))

En este punto tenemos una lista de pares, donde cada par contiene una palabra y su frecuencia. Note que esta lista podría ser redundante. Si el artículo “el” se repitiera 500 veces, la lista contendría quinientas copias de ese par (‘el’, 500). La lista está, además, ordenada por el orden de las palabras en el texto inicial. Podemos resolver ambos problemas convirtiéndola en un diccionario. Entonces todo lo que tenemos que hacer es imprimir el diccionario en orden, desde los ítems más frecuentes a los menos frecuentes.

De HTML a un diccionario de pares palabra-frecuencia.

A partir de lo que tenemos hasta ahora, queremos una función que pueda convertir una lista de palabras en un diccionario de pares de palabra-frecuencia. La única declaración nueva que necesitamos conocer es dict, que hacer un diccionario a partir de una lista de pares. Agregue el siguiente código al módulo dh.py.

# Dada una lista de palabras, devuelva un diccionario de
# pares de palabra-frecuencia.
 
def wordListToFreqDict(wordlist):
    wordfreq = [wordlist.count(p) for p in wordlist]
    return dict(zip(wordlist,wordfreq))

Vamos a querer además un función que pueda ordenar un diccionario de pares de palabra-frecuencia por frecuencias, de modo descendiente. Copie también esto al módulo dh.py:

# Ordenar un diccionario de pares de palabra-frecuencia por
# frecuencias de modo descendiente
 
def sortFreqDict(freqdict):
    aux = [(freqdict[key], key) for key in freqdict]
    aux.sort()
    aux.reverse()
    return aux

Podemos ahora escribir un programa que tome una URL y devuelva pares de palabras-frecuencia para la página web, ordenados de acuerdo a la frecuencia de cada palabra, desde la que más tiene a la que menos tiene. Copie el siguiente programa en el Komodo, guarde como html-to-freq.py y ejecútelo. Estudie cuidadosamente el programa y lo que se imprime en el panel de salida, antes de continuar.

# html-a-freq.py
 
import urllib2
import dh
 
url = 'http://niche.uwo.ca/programming-historian/dcb/dcb-34298.html'
 
response = urllib2.urlopen(url)
html = response.read()
text = dh.stripTags(html).replace(' ', ' ')
wordlist = dh.stripNonAlphaNum(text.lower())
dictionary = dh.wordListToFreqDict(wordlist)
sorteddict = dh.sortFreqDict(dictionary)
for s in sorteddict: print str(s)

Removiendo las stop words

Cuando miramos la salida de nuestro programa html-a-freq.py, vemos que las mayores frecuencias son para palabras como “the”, “of”, “and”.

(647, 'the')
(310, 'of')
(273, 'to')
(202, 'and')
(171, 'in')
(134, 'a')
(118, 'that')
(91, 'dollard')
(78, 'was')
(78, 'their')
(75, 'were')
(72, 'they')
(71, 'his')

Esas palabras son las más usuales en cualquier texto en inglés, y no nos dicen mucho sobre la biografía de Dollard. En general, estamos más interesados en encontrar las palabras que nos permitan distinguir este texto de otros con diferentes temas. Por lo que vamos a filtrar, a quitar, las palabras más comunes. Las palabras que son ignoradas, como esas, se conocen como stop words. Vamos a usar una lista, adaptada de un post de unos cientistas de Glasgow. Copie lo siguiente en el comienzo de la biblioteca dh.py.

stopwords = ['a', 'about', 'above', 'across', 'after', 'afterwards']
stopwords += ['again', 'against', 'all', 'almost', 'alone', 'along']
stopwords += ['already', 'also', 'although', 'always', 'am', 'among']
stopwords += ['amongst', 'amoungst', 'amount', 'an', 'and', 'another']
stopwords += ['any', 'anyhow', 'anyone', 'anything', 'anyway', 'anywhere']
stopwords += ['are', 'around', 'as', 'at', 'back', 'be', 'became']
stopwords += ['because', 'become', 'becomes', 'becoming', 'been']
stopwords += ['before', 'beforehand', 'behind', 'being', 'below']
stopwords += ['beside', 'besides', 'between', 'beyond', 'bill', 'both']
stopwords += ['bottom', 'but', 'by', 'call', 'can', 'cannot', 'cant']
stopwords += ['co', 'computer', 'con', 'could', 'couldnt', 'cry', 'de']
stopwords += ['describe', 'detail', 'did', 'do', 'done', 'down', 'due']
stopwords += ['during', 'each', 'eg', 'eight', 'either', 'eleven', 'else']
stopwords += ['elsewhere', 'empty', 'enough', 'etc', 'even', 'ever']
stopwords += ['every', 'everyone', 'everything', 'everywhere', 'except']
stopwords += ['few', 'fifteen', 'fifty', 'fill', 'find', 'fire', 'first']
stopwords += ['five', 'for', 'former', 'formerly', 'forty', 'found']
stopwords += ['four', 'from', 'front', 'full', 'further', 'get', 'give']
stopwords += ['go', 'had', 'has', 'hasnt', 'have', 'he', 'hence', 'her']
stopwords += ['here', 'hereafter', 'hereby', 'herein', 'hereupon', 'hers']
stopwords += ['herself', 'him', 'himself', 'his', 'how', 'however']
stopwords += ['hundred', 'i', 'ie', 'if', 'in', 'inc', 'indeed']
stopwords += ['interest', 'into', 'is', 'it', 'its', 'itself', 'keep']
stopwords += ['last', 'latter', 'latterly', 'least', 'less', 'ltd', 'made']
stopwords += ['many', 'may', 'me', 'meanwhile', 'might', 'mill', 'mine']
stopwords += ['more', 'moreover', 'most', 'mostly', 'move', 'much']
stopwords += ['must', 'my', 'myself', 'name', 'namely', 'neither', 'never']
stopwords += ['nevertheless', 'next', 'nine', 'no', 'nobody', 'none']
stopwords += ['noone', 'nor', 'not', 'nothing', 'now', 'nowhere', 'of']
stopwords += ['off', 'often', 'on','once', 'one', 'only', 'onto', 'or']
stopwords += ['other', 'others', 'otherwise', 'our', 'ours', 'ourselves']
stopwords += ['out', 'over', 'own', 'part', 'per', 'perhaps', 'please']
stopwords += ['put', 'rather', 're', 's', 'same', 'see', 'seem', 'seemed']
stopwords += ['seeming', 'seems', 'serious', 'several', 'she', 'should']
stopwords += ['show', 'side', 'since', 'sincere', 'six', 'sixty', 'so']
stopwords += ['some', 'somehow', 'someone', 'something', 'sometime']
stopwords += ['sometimes', 'somewhere', 'still', 'such', 'system', 'take']
stopwords += ['ten', 'than', 'that', 'the', 'their', 'them', 'themselves']
stopwords += ['then', 'thence', 'there', 'thereafter', 'thereby']
stopwords += ['therefore', 'therein', 'thereupon', 'these', 'they']
stopwords += ['thick', 'thin', 'third', 'this', 'those', 'though', 'three']
stopwords += ['three', 'through', 'throughout', 'thru', 'thus', 'to']
stopwords += ['together', 'too', 'top', 'toward', 'towards', 'twelve']
stopwords += ['twenty', 'two', 'un', 'under', 'until', 'up', 'upon']
stopwords += ['us', 'very', 'via', 'was', 'we', 'well', 'were', 'what']
stopwords += ['whatever', 'when', 'whence', 'whenever', 'where']
stopwords += ['whereafter', 'whereas', 'whereby', 'wherein', 'whereupon']
stopwords += ['wherever', 'whether', 'which', 'while', 'whither', 'who']
stopwords += ['whoever', 'whole', 'whom', 'whose', 'why', 'will', 'with']
stopwords += ['within', 'without', 'would', 'yet', 'you', 'your']
stopwords += ['yours', 'yourself', 'yourselves']

Ahora que pusimos esas palabras en una lista es fácil utilizarlas. Copie esta función también en el módulo dh.py.

# Dada una lista de palabras remueva cualquiera 
# que figure en la lista de stop words.
 
def removeStopwords(wordlist, stopwords):
    return [w for w in wordlist if w not in stopwords]
[Para ampliar este tema ver la solapa discussion en el wiki]

Poniendo todo junto

Ahora tenemos todo lo que necesitamos para determinar las frecuencias de palabras en páginas web. Copie lo siguiente en el Komodo, guárdelo como html-a-freq-2.py y ejecútelo.

# html-to-freq-2.py
 
import urllib2
import dh
 
url = 'http://niche.uwo.ca/programming-historian/dcb/dcb-34298.html'
 
response = urllib2.urlopen(url)
html = response.read()
text = dh.stripTags(html).replace(' ', ' ')
fullwordlist = dh.stripNonAlphaNum(text.lower())
wordlist = dh.removeStopwords(fullwordlist, dh.stopwords)
dictionary = dh.wordListToFreqDict(wordlist)
sorteddict = dh.sortFreqDict(dictionary)
for s in sorteddict: print str(s)

Si todo va bien, la salida debería mostrar algo así:

(91, 'dollard')
(64, 'iroquois')
(33, 'long')
(27, 'sault')
(24, 'enemy')
(24, '1660′)
(20, 'time')
(20, 'seventeen')
(20, 'french')
(19, 'new')
(19, 'montreal')
(19, 'army')
(18, 'hurons')
(18, 'fort')
(17, 'france')
(15, 'men')
(14, 'marie')
(14, 'companions')

the Programming Historian, parte II

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 4.

Haciendo uso de sus capacidades para una lectura atenta

Desde ahora, vamos a ver más y más ejemplos de código. Trate de crearse el hábito de leer cada uno muy bien, de mismo modo en que lee una importante fuente primaria. Si hay algo en el código que nunca vio antes o no comprende, trate de hacer una hipótesis explícita acerca de cómo debe funcionar. A veces, su hipótesis será correcta y otras no, pero es mucho más fácil hacer progresos si es consciente de sus conjeturas. Ese es también el modo que deberá asumir cuando comience a corregir errores (debug) de programas que no funcionan. Una de las ventajas que tienen los historiadores tienen cuando se ponen a programar es que ya están habituados a la interrogación de fuentes en lugar de tomarlas en sentido literal.

Enviando información a archivos de texto

En las secciones previas, vimos cómo enviar información al panel “Command Output” (panel de salida) del editor Komodo, al utilizar el comando de Python print.

print 'hola mundo'

El lenguaje de programación Python es orientado a objetos. Esto quiere decir que está construido alrededor de un tipo especial de entidad, un objeto, que contiene tanto datos como un número de métodos para acceder y procesar esos datos. En el ejemplo de arriba, vemos un tipo de objeto, la cadena (string) hola mundo. Un objeto cadena es una secuencia de caracteres; aprenderemos más sobre métodos de cadenas pronto. Print es un comando que imprime objetos de modo textual.
Usará print en los casos donde quiera crear información que necesita de inmediato. A veces, de todos modos, usted creará información que quiera guardar, enviar a alguien más, o usar como “input” para ulteriores procesamientos por otros programas o grupos de programas. En esos casos usted querrá enviar información a archivos en su disco duro en lugar de hacerlo al panel “Command Output”. Ingrese el siguiente programa en la ventana principal del Komodo y guárdelo como arch-salida.py

# arch-salida.py
f = open('holamundo.txt','w')
f.write('hola mundo')
f.close()

En ese programa f es un objeto archivo, y open, write y close son métodos de archivos. En el método open, holamundo.txt es el nombre del archivo que usted está creando, y el parámetro w dice que usted está abriendo ese archivo en modo escritura (write). Note que tanto el nombre del archivo como el parámetro son cadenas en este caso. Su programa escribe el mensaje (otra cadena) en el archivo y luego lo cierra. (Para más información sobre estas órdenes, ver la sección File Objects en la Librería de Referencia Python.)
Haga doble click en el botón “Run Python” para ejecutar el programa. Aunque nada se imprima en el panel “Command Output”, puede ver un mensaje de estado que dice [en Windows] 'C:\Python25\Python.exe arch-salida.py' returned 0. Esto significa que su programa fue ejecutado con éxito. Si usa File->Open->File en el editor Komodo, puede abrir el archivo holamundo.txt. Este deberá contener su mensaje de una línea:

hola mundo

Puesto que los archivos de texto incluyen un mínimo monto de información de formato, ellos tienden a ser pequeños, fáciles de intercambiar entre plataformas diferentes (i.e, desde Windows a Linux o Mac o viceversa), y fáciles de enviar de un software a otro. Además, pueden ser usualmente leídos por quienes tengan un editor de texto como el Komodo.

Obteniendo información desde archivos de texto

Python tiene además comandos que le permiten obtener información desde archivos. Tipee el siguiente programa en el Komodo y guárdelo como arch-entrada.py. Cuando lo ejecute haciendo doble click en “Run Python”, abrirá el archivo de texto, leerá el mensaje de una línea e imprimirá el mismo mensaje en el panel “Command Output”.

# arch-salida.py
f = open('holamundo.txt','r')
mensaje = f.read()
print mensaje
f.close()

En este caso, el parámetro r es usado para indicar que estamos abriendo un archivo para leerlo (read). Read es otro método de archivo. El contenido del archivo (el mensaje de una sola línea) es copiado en mensaje, que es una cadena (string), y luego el comando print es utilizado para enviar el contenido de mensaje al panel de salida de Komodo.

Dividiendo código en módulos y funciones

A menudo querrá utilizar nuevamente un grupo de commandos, generalmente porque tiene una tarea que debe realizar una y otra vez. Supongamos, por ejemplo, que usted tiene que mantener todas sus referencias bibliográficas en Zotero y tiene una etiqueta que le indica cuáles necesita en su próximo viaje a la biblioteca. Resultaría muy útil tener un programa que seleccione sólo aquellos ítems etiquetados y los ordene por número topográfico.
Dado que eso forma parte de sus actividades de investigación, usted querrá tener disponible el programa para reutilizar en cada visita a la biblioteca. Un programa, en otras palabras, es un mecanismo para empaquetar una colección de comandos para facilitar su reutilización. Zotero mismo es un paquete de comandos útiles, como también lo es Firefox.
Cuando los programas son pequeños se guardan, generalmente, en un archivo único. Cuando quiere correr uno de esos programas, simplemente envía ese archivo al intérprete. Cuando los programas se hacen muy largos, tiene sentido dividirlos en archivos separados conocidos como módulos. Básicamente, la modularización permite a los programadores reutilizar código para tareas que realizan muchas veces. Más abajo, por ejemplo, puede ver que los comandos para trabajar con páginas web han sido puestos en un módulo de Python aparte. Python posee un comando especial, import que permite que un programa acceda a los contenidos de otro archivo de programa. (Como tendrá que trabajar con los ejemplos de más abajo, asegúrese de haber comprendido la diferencia entre cargar un archivo de datos (loading) e importar un archivo de programa (import).)
Hilando fino se puede decir que los programas están compuestos por rutinas que son potencialmente reutilizables. Estas son conocidas como funciones, y Python posee mecanismos que permiten definir nuevas funciones. Vamos a trabajar con un ejemplo muy simple de función y módulo. Supongamos que queremos crear una función con el propósito general de saludar personas. Copie la siguiente definición de función en el Komodo y guárdela como saludo.py. Ese archivo es su módulo.

# saludo.py
def saludogral (x):
    print "hola " + x

Advierta que la indentación es muy importante en Python. Los espacios en blanco antes del comando print le dicen al intérprete que eso es parte de una función que está siendo definida. Usted podrá aprender más sobre esto a medidas que avancemos. Por ahora, asegúrese de mantener la indentación tal como se lo mostramos.
Ahora puede crear otro programa que importe código desde su módulo y haga uso de él. Copie este código en el Komodo y guárdelo como usando-saludo.py. Este archivo es su programa.

# usando-saludo.py
import saludo
saludo.saludogral("a todos")
saludo.saludogral("programming historian")

Puede corer su usando-saludo.py con el commando Run Python que usted creó en el Komodo. Note que no puede correr su módulo…sólo puedo llamarlo desde su programa. (Como habrá podido advertir en este ejemplo y en los previos, las cadenas en Python pueden delimitarse con comillas simples o dobles. Es verdad.) Si todo va bien, usted verá:

hola a todos
hola programming historian

en el panel de salida del Komodo Edit.

Podemos pensar acerca de la “granularidad” del código de dos modos:
. De arriba hacia abajo. Si usted piensa en todas las cosas para las que quiere usar la computadora, puede descomponer el problema en recurrentes subproblemas. Necesita trabajar con archivos (sistema operativo), documentos (procesador de textos), números (planillas de cálculo), imágenes (programa de procesamiento de imágenes), páginas web (browser) y así sucesivamente. Cualquier programa deberá poder abrir, manipular y guardar archivos. Usted puede querer tener la capacidad para chequear la ortografía, puede querer requerir algún tipo de diccionario y la capacidad para buscar cada palabra en él. Buscar palabras implica estar en condiciones de comparar palabras letra por letra. Cada tarea puede ser dividida en otras más pequeñas.
. De abajo hacia arriba. Supongamos que usted comienza con una tarea simple, como sumar dos números entre sí (a+b). En cuanto aprenda a hacerlo, será posible generalizar su habilidad para sumar números entre sí (a+b)+c=(a+b+c). De la suma usted puede llegar a la multiplicación (a*3)=(a+a+a). Una vez que pudo convertir la suma de números en una útil función, puede recurrirse a esta constantemente. Su sistema operativo necesita de la adición para determinar cuánto espacio disponible existe en su disco rígido. Su procesador de texto necesita de la suma para mantener el conteo de las palabras y de las páginas, su planilla de cálculo necesitará mucho de la suma. Útiles “ladrillos” como los de la suma pueden ser combinados y recombinados a cualquier nivel de complejidad.

Acerca de las URLs

Una página web es un archivo que está guardado en otra computadora, una máquina conocida como servidor web. Cuando usted ‘entra’ a una página lo que en verdad sucede es que su computadora, el cliente, envía una petición al servidor que se encuentra en la red, y el servidor responde enviando una copia de la página solicitada a su máquina. Una manera de acceder a una página web con su browser es siguiendo un link de algún sitio. También puede, claro, pegar o tipear una Uniform Resource Locator (URL). La URL le dice a su browser dónde encontrar un recurso online especificándole el servidor, el directorio y el nombre del archivo que quiere recuperar, así como también el tipo de protocolo que el servidor y su browser podrán usar para intercambiar información (como HTTP, “Hypertext Transfer Protocol”). La estructura básica de una URL es

protocolo: //servidor : puerto /ruta ?consulta

Miremos algunos ejemplos.

http://niche.uwo.ca

El tipo más básico de URL simplemente especifica el protocolo y el servidor. Si le da esa URL a su browser, este le devolverá la página principal de sitio NiCHE. Lo que se asume es que la página principal de un determinado directorio se denomina index, a menudo index.html. El sitio NiCHE está escrito en un lenguaje distinto a HTML, pero de todos modos, el nombre de la página principal es index.php (PHP es otro lenguaje de programación web. Si le interesa conocer más sobre el mismo, hay un W3 Schools tutorial).
La URL también puede incluir un número de puerto. Sin entrar en demasiados detalles en este punto, el protocolo de red que soporta el intercambio de información en internet permite que las computadoras se conecten de distintas maneras. Generalmente, el puerto por defecto para HTTP es 80. La siguiente URL es equivalente a la primera:

http://niche.uwo.ca:80

Como sabemos, generalmente hay muchas páginas en un determinado sitio web. Ellas están guardadas en directorios del servidor, y usted puede especificar la ruta de una página en particular. La tabla de contenidos de este libro sigue la siguiente URL (note que no necesitamos mencionar el nombre de archivo ya que también en este caso es index.php.

http://niche.uwo.ca/programming-historian/

Finalmente, algunas páginas web permiten que ingresemos consultas. El sitio web NiCHE, por ejemplo, está dispuesto de tal manera que permite que solicitemos una página en particular usando una cadena de consulta. La siguiente URL nos lleva a la página principal de la infraestructura digital de NiCHE.

http://niche.uwo.ca/?q=node/12

Abriendo URLs con Python

Con el fin de cosechar y procesar automáticamente páginas web, necesitaremos poder abrir URLs con nuestros propios programas. El lenguaje Python incluye varios procedimientos para hacerlo.
Para dar un ejemplo, vamos a trabajar con un tipo de archivo que podemos encontrar cuando hacemos una investigación histórica. Digamos que usted está interesado en [N.T.: Este ejemplo lo ponemos nosotros porque el original tuvo problemas de acceso] Álvar Núñez Cabeza de Vaca, el inefable explorador y tremendo escritor. Con Google podemos localizar una entrada sobre Cabeza de Vaca en The Handbook of Texas Online.

Cabeza de Vaca



La URL para esa entrada es:

http://www.tshaonline.org/handbook/online/articles/CC/fca6.html

Mirando la página nos enteramos que hay una versión para imprimir de esa entrada:

Cabeza de Vaca



La URL es:

http://www.tshaonline.org/handbook/online/articles/CC/fca6_print.html

Cuando procesamos recursos de la web automáticamente a menudo resulta una buena idea trabajar con versiones para imprimir, ya que estas tienden a estar menos formateadas.
Ahora vamos a probar abrir la versión para imprimir de esa entrada. Copiamos el siguiente programa en el Komodo y lo guardamos con abrir-html.py. Cuando lo ejecutemos, el programa abrirá el archivo biográfico, leerá su contenido y lo guardará en una cadena de Python llamada por nosotros html y luego imprimirá los primeros trescientos caracteres de la cadena en el panel “Command Output” del Komodo. Use el comando View -> Page Source en Firefox para verificar que el código fuente HTML de la página es el mismo que el código que su programa recuperó. (Para conocer más sobre la librería urllib2, ver la biblioteca de referencia Python en esta sección.)

# abrir-html.py
import urllib2
url = ' http://www.tshaonline.org/handbook/online/articles/CC/fca6_print.html '
respuesta = urllib2.urlopen(url)
html = respuesta.read()
print html[0:300]

Guardando una copia local de una página web

Ya que usted sabe cómo escribir archivos, es fácil modificar el programa de arriba para que escriba el contenido de la cadena html en un archivo local en lugar de hacerlo en el panel “Command Output” del Komodo. Copie el siguiente programa en el Komodo, guárdelo como guardar-html.py y ejecútelo. Usando el comando File -> Open File en el Firefox, abra el archivo local que fue creado (‘fca6.html’) para confirmar que su copia es la misma que la copia online.

# guardar-html.py
import urllib2
url = ' http://www.tshaonline.org/handbook/online/articles/CC/fca6_print.html '
respuesta = urllib2.urlopen(url)
html = respuesta.read()
f = open('fca6.html', 'w')
f.write(html)
f.close

Entonces, si ya puede guardar un archivo tan fácilmente, ¿puede escribir un programa para bajar un montón de archivos? Puede aumentar las letras y los números del nombre de las páginas del Handbook, por ejemplo, y hacer sus propias copias de un montón de ellas. Sí. Ya lo veremos.

***

the Programming Historian, parte I

Algo habíamos mencionado aquí en Tapera, hace algún tiempo, pero sin prestarle la atención debida. Bill Turkell detuvo "Digital History Hacks" -uno de los blogs más importantes en historia digital- pero casi al mismo tiempo comenzó a publicar un libro en formato wiki: The Programming Historian. (Los autores son William J. Turkel, Adam Crymble y Alan MacEachern. El libro se publica bajo el auspicio del departmento de historia de la University of Western Ontario y NiCHE: Network in Canadian History & Environment). El libro es una especie de tutorial políglota (utilizada distintos lenguajes, diferentes programas) para aprender a programar. Aunque por ahora su fuerte es Python. Python es un tremendo lenguaje de programación orientado a objetos, bastante intuitivo para, por ejemplo, trabajar con textos, pero también abierto y gratuito, y, además, poblado de librerías con funciones para distintas especialidades.
No sé qué tan útil resulta conocer cierto lenguajes de programación a los historiadores o a los cientistas sociales; supongo que mucho en la medida en que las bibliotecas son cada vez más digitales. Supongo que en el terreno de la docencia el conocimiento de estas lenguas posee un altísimo potencial. Lo cierto es que, en la actualidad, vendrían bien tutoriales sobre base de datos: muchísimas investigaciones encajan en ese género o trabajan con esa metodología, sin embargo mucho menos del 1% de esos trabajos nos dice cómo hicieron para procesar sus datos. Y esto no se debe al arte marcial de la economía narrativa; se debe a que sencillamente sus autores no lo saben. Pero sigamos con el Programming Historian, que está muy bueno.
La traducción que hacemos aquí es por pedazos y por cierto bastante precaria. Ojalá aprenda algún día.
Hay un índice, el punto 1 ("Acerca de este libro"),el punto 2 ("¿Es necesario aprender a programar?"). Nosotros vamos directo al punto 3,

Empezando

A fin de estudiar los métodos en este libro, necesitará bajar e instalar software de acceso libre. Tanto como se pueda, trataremos de hacer todo compatible con máquinas con Linux, Mac o Windows. Suponemos que la mayoría de nuestros lectores probablemente utilizan Windows, por lo que primero trataremos de que funcione bajo Windows XP, luego en Mac y finalmente bajo Linux. Estaremos complacidos en incluir instrucciones para plataformas específicas, especialmente si nos las envían. También incluiremos críticas y comentarios de pares en la página de discusión de secciones específicas. Pueden leerse esos comentarios clickeando la solapa discussion en el borde superior de esta y otras páginas wiki. Si tiene problemas con nuestras instrucciones o encuentra que algo no funciona en su plataforma, por favor avísenos.

Dado que es un trabajo muy en progreso, ocasionalmente haremos comentarios e indicaremos algunas cosas que son provisionales en color púrpura

.

Instrucciones para Windows XP [en el original hay instrucciones para Linux y Mac] * Haga un back up de su PC.
* Si aún no lo está usando, instale el browser Firefox.
* Instale las siguientes extensiones del Firefox
*Web developer toolbar
* Extension Developer’s Extension

Si está usando Firefox 3 no podrá instalar esta extensión por razones de seguridad. Saltee este ítem por ahora. Hay más información en la página de discusión

.
* Si todavía no lo usa, instale Zotero.
* Vaya al sitio de Python, baje la última versión estable del lenguaje de programación Python (versión 2.5.2 de abril de 2008) e instálela.
* Instale las siguientes librerías de Pyhton:
*Baje la última versión de Beatiful Soup y cópiela en el directorio de librerías de Python (usualmente C:\Python25\Lib).
* Instale Komodo Edit.
* Ejecute Komodo Edit. Verá algo así.



* Si no ve el panel Toolbox en el costado derecho, elija View –> Tabs –> Toolbox. No importa si el panel Project está abierto o no. Toma algo de tiempo familiarizarse con el diseño del editor Komodo. El archivo de Ayuda es bastante bueno.
* Ahora necesita configurar el editor para que pueda correr programas en Python.
* Elija Edit –> Preferences. Esto abrirá una nueva ventana de diálogo.
* Seleccione la categoría Python y establezca el 'Default Python Interpreter' (este suele ser C:\Python25\Python.exe).
* Si todo se ve como esto, haga un click en OK.



* Luego elija Toolbox –> Add –> New Command. Esto abrirá una nueva ventana de diálogo. Renombre su comando a “Run Python”. Bajo “Command”, use el menú de cascada para seleccionar

% (python) %f

Y bajo “Start in”, ingrese

% D

* Nota: Si olvida el %f en el primer commando, Python se colgará misteriosamente porque no recibirá un programa como entrada.
* Si todo se ve así, clickee en OK.



* Su nuevo comando aparecerá en el panel Toolbox.
Nota: Algunas personas han reportado que tuvieron que resetear la máquina antes de que Python pueda trabajar con Komodo.

'Hola mundo' en Python

Es tradición comenzar la programación en un nuevo entorno tratando de crear un programa que diga “hola mundo” y finalice. Para mantener nuestro acercamiento políglota a la programación, haremos eso de diferentes maneras, utilizando distintos lenguajes de progamación [N.T.: nosotros no lo haremos, esos desarrollos pueden seguirse en la versión original] Los lenguajes que utilizaremos son todos interpretados. Esto significa que hay un programa especial (conocido como intérprete) que sabe cómo seguir las instrucciones escritas en tal lenguaje. Una manera de usar el intérprete es guardar todas las instrucciones en un archivo y luego ejecutar al intérprete sobre ese archivo. Un archivo que contiene instrucciones de un lenguaje de programación es conocido como un programa. El intérprete ejecutará cada una de esas instrucciones que usted escribió en su programa y luego parará. Vamos a probar esto.
En Komodo, cree un nuevo archivo, ingrese las siguientes dos líneas de programación y guárdelas como hola-mundo.py

# hola-mundo.py
print 'hola mundo'

Entonces podrá hacer doble click en el botón “Run Python” -que usted creó en los pasos previos- para ejecutar su programa. Si toda va bien, podrá ver algo así:



Advierta que el resultado de su programa fue impreso en el panel “Command Output”.
Otro modo de interactuar con un intérprete es usarlo como lo que se conoce por Shell (interfase). Puede tipear una orden y presionar luego la tecla Enter, y el intérprete responderá a su comando. Usar una interfase es una buena manera de testear órdenes para asegurarse de que ellas hagan lo que usted piensa que harán.
Puede acceder a la interfase de Python haciendo doble click en C:\Python25\python.exe. Una nueva ventana se abrirá en su pantalla.
En la ventana de la interfase tipee:

print 'hola mundo'

y presione Enter . La computadora responderá con

hola mundo

Cuando representemos una interacción con la interfase, usaremos -> para indicar que la interfase respondió a su comando, como se muestra abajo:

print 'hola mundo'
-> hola mundo

En su pantalla esto se verá más o menos así:



La razón por la que nosotros usamos Python para muchas de nuestras tareas de programación es que Python es un lenguaje de muy alto nivel. Permite, en otras palabaras, escribir programas cortos y efectivos. Cuanto más corto el programa, más probable que este quepa en una pantalla, y de ese modo es más fácil hacer el seguimiento de la rutina.

***

Le siguen otras secciones que no traducimos: [haga copia de su trabajo][manténgase en contacto][otros recursos] y [lecturas recomendadas] La próxima sección es "Trabajando con archivos y páginas webs". Veremos cuándo está lista su traducción.