Categories
python software libre visor de imágenes xkcd

Visor de imágenes para xkcd

Una de mis tiras cómicas favoritas es xkcd, y desde ya hace tiempo quería descargarme todas las tiras para tenerlas en el disco duro. Si han leido xkcd seguro sabran de los textos adicionales que Randall Munroe pone en el atributo title de las imágenes, este texto es complementario a la tira y en muchas ocasiones mas gracioso que la tira misma.

Así que si descargaba las tiras tenia que hacerlo con todo y titulo. Tuve un tiempo libre esta navidad y me puse a recolectar información de como hacerlo, lo primero era descargar las imágenes y guardar el texto del tooltip en los metadatos de la imagen, para esto me fue de mucha ayuda este articulo donde se explica como hacerlo usando la libreria PIL.

Lo siguiente era crear un visor de imágenes que mostrara los tooltip, algo complicado y mas teniendo en cuenta que esta es la segunda interfaz gráfica “seria” que hago, pero encontré muy buenos recursos como este libro online sobre tkinter con muy buenos ejemplos, ademas de un script que implementa un tooltip que me cayo de perlas.

Luego de varias horas de pelearme acomodando los widget (con pack y grid), he aquí el visor de imágenes junto con todas las tiras hasta la fecha (1-995).

Si bajan el código fuente necesitaran instalar las siguientes librerías:
  • PIL (en Windows y Linux)
  • ImageTk (solo en Linux: python-imaging-tk)
  • Tkinter (solo en Linux)
Si tienen alguna sugerencia no duden en dejarla en los comentarios, siempre es bueno saber en que mejorar.
Categories
aplicación web blog django plantillas python tutorial

Creando un blog con django – parte 3

En la parte anterior dejamos la base de datos lista, es momento de crear las plantillas para visualizar estos datos.
Lo primero que haremos es configurar el directorio donde estaran guardas las plantillas. Creamos el directorio templates en la raíz del proyecto y editamos el archivo settings.py.

.....
import os

TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__) ,"templates"),
)
....

Así el script puede encontrar el directorio templates aun cuando cambiemos de ubicación la carpeta del proyecto. Ahora editamos el archivo urls.py para incluir la url a la pagina.

....
urlpatterns = patterns('',
(r'^$', 'blog.views.index'),
....
)

Con esto le decimos a django que toda petición hecha a la raíz del blog sera manejada por la función index ubicada en el archivo views, la cual luce así:

from django.shortcuts import render_to_response

def index(request):
return render_to_response("index.html")

Al visitar la raíz del sitio, django llamara la función index pasando como argumento un objeto request que contiene información sobre la solicitud (datos POST y GET entre otros). La función index realizar algún proceso y retornar un objeto response.

Si iniciamos el servidor de desarrollo y entramos a la dirección localhost:8000 veremos un mensaje de error como el de la imagen ya que la plantilla index.html aun no existe, así que manos a la obra.

<!DOCTYPE HTML>
<html lang="es-ES">
<head>
<title>Mi Blog</title>
</head>
<body>
<!-- hasta aquí siempre es igual -->
<h1>Hola Django</h1>
</body>

No muy útil, pero por el momento es todo lo que necesitamos. Imagine que creamos otras plantillas para post individuales, contacto, faq, quejas… debemos repetir la cabecera en cada una de ellas.

El sistema de plantillas de django permite crear plantillas base con bloques que luego pueden ser reemplazados por las plantillas que heredan de ésta; para tal efecto creamos la plantilla base.html:

<!DOCTYPE HTML>
<html lang="es-ES">
<head>
<title>Mi Blog</title>
</head>
<body>
{% block content %}
{% endblock %}
</body>

Y editamos la plantilla index.html para que extienda base.html:

{% extends "base.html" %}
{% block content %}
<h1>Hola Django</h1>
{% endblock %}

Ok, teniendo una idea general del sistema de plantillas, seguimos con la pagina inicial del blog empezando por editar el archivo views.py.

from django.shorcuts import render_to_response
from blog.models import Post

def index(request):
# recuperamos 5 primeras entradas
posts = Post.objects.filter()[:5]
return render_to_response("index.html", locals())

Cada vez que visitemos a la raíz del blog se consultaran los primeros 5 post y se pasaran a la plantilla index.

{# plantilla index.html #}
{% extends "base.html" %}

{% block content %}
{% for post in posts %}
<h1><a href="/{{ post.id }}">{{ post.title }}</a></h1>
<p>{{ post.pub_date}}</p>
{{ post.body }}
{# esto no es muy eficiente* #}
{% for tag in post.tags.filter %}
<a href="/tags/{{ tag.tag }}">{{ tag.tag }}</a>
{% endfor %}
{% endfor %}
{% endblock %}

* Extraer las etiquetas de esta forma no es eficiente ya que al llamar a filter (5 veces) se hace una nueva consulta a la base de datos, algunas soluciones se pueden encontrar aquí.

Con esto la pagina principal esta lista. Sigamos con la pagina individual, veremos que al trabajar con django se sigue mas o menos el mismo patrón:

# archivo urls.py
urlpatterns = patterns('',
(r'^$', 'blog.views.index'),
# expresión regular que captura el numero después de post/
(r'^post/(?P<id>d+)$', 'blog.views.single'),
)
# Archivo views.py
...
# la funcion recibe el numero capturado
def single(request, id=0):
# recuperar post según id
post = Post.objects.get(id=int(id))

return render_to_response("single.html", locals())
{# plantilla single.html #}
{% block content %}
<h1><a href="/{{ post.id }}">{{ post.title }}</a></h1>
<p>{{ post.pub_date}}</p>
{{ post.body }}
{# esto no es muy eficiente* #}
{% for tag in post.tags.filter %}
<a href="/tags/{{ tag.tag }}">{{ tag.tag }}</a>
{% endfor %}
{% endblock %}

Notan algo raro? el código de single.html e index.html luce muy similar; podemos eliminar el código repetido moviéndolo a otra plantilla (article.html) que luego incluimos en estas.

{# plantilla article.html #}
</div>
<h1><a href="/{{ post.id }}">{{ post.title }}</a></h1>
<p>{{ post.pub_date}}</p>
{{ post.body }}
{# esto no es muy eficiente* #}
{% for tag in post.tags.filter %}
<a href="/tags/{{ tag.tag }}">{{ tag.tag }}</a>
{% endfor %}
</div>

Ahora editamos las plantillas index.html y single.html para que utilicen article.html.

{# plantilla inde.html #}
{% extends 'base.html' %}

{% block main_content %}
{% for post in posts %}
{# pasamos la variable post como argumento #}
{% include 'include/article.html' with post=post %}
{% endfor %}

{% endblock %}
{# plantilla single.html #}
{% extends 'base.html' %}

{% block main_content %}
{% include 'include/article.html' %}
{% endblock %}

Con esto damos por terminado esta parte. No se olviden de comentar.

P.D.: Procurare tener la próxima parte mas rápido.

Categories
extraer gratis imagen powerpoint programa programación python

Extrae imágenes de archivos PowerPoint

Versión corta: pues que escribí una aplicación para extraer imágenes de archivos PowerPoint y la pueden descargar de aquí.

Versión larga:

Nuca he entendido esa manía de algunas personas de estar enviando PowerPoints a diestra y siniestra por lo que todo el que llega termina en la papelera sin leerlo XD.

Un conocido al que si le encantan me pidió un programa para extraerles las imágenes. Encontré dos pero ninguno funciono, así que escribí un script en python que pueden encontrar en github (advertencia: visualizar el código puede causar sangrado de ojos). Ya estando en ello le cree interfaz gráfica (la primera que hago). Eso sí, es algo…. feeeeaaaa, pero en el proceso puede recuperar imágenes porno aprender algo sobre threads, instaladores y otras cosas de las que escribiré mas adelante, por el momento he aquí el cuerpo del delito: PowerPoint Extractor.

Eso es todo. no olviden seguirme en twitter y/o suscribirse al feed del blog.

Actualización: En github pueden encontrar un modulo para dicho fin que funciona tanto en Windows como en Linux.

Categories
descargas megaupload mget python software libre wget

mget ahora para windows

Actualización: se incluyeron las dependencias del wget que faltaban, que pena u_u.

Un amigo me pidió que le pasara el programa con el que descargo de megaupload, pero en cuanto le dije que tenia que:

  1. Descargar e instalar python 2.6.
  2. Descargar e instalar wget para Windows.
  3. Poner los directorios de wget y python en el PATH de Windows.
En seguida se desanimo (no se por que XD), así que me pase toda una tarde mejorando un poco el programa e intentando convertirlo en un ejecutable usando pyinstaller y he aquí el resultado:
Basta con descomprimir los archivos en la carpeta windows y a descargar de megaupload. Lo probé en varias maquinas con Windows XP y funciono correctamente, pero si tienen algún problema no duden en dejarlo en los comentarios.
Su uso es muy sencillo, abren la consola de comandos y:
mget -c url-con-link-de-megaupload

mget -i archivo-con-links

mget link1 link2 link3 ...

Para una próxima explico como fue lo de convertir el script en ejecutable, algo muy util para compartir los programas que hagamos con amigos.

Pueden seguirme en twitter o agregarme en Google+

Categories
chorradas javascript programación python script Wingdings

Revertir guardado en Wingdings

El otro día me encontraba aburrido a mas no poder, cuando de pronto me llaman a hacerme la siguiente pregunta: Imaginen que tienen un documento y no quiere que nadie mas se entere de lo que contiene, nada mejor que guardar dicho documento con el tipo de letra Wingdings, el problema es revertir el proceso, aunque no lo crean es algo mas común de lo que párese, la única solución es ir reemplazando cada signo por el caracter original, un proceso algo tedioso si se decide hacer a mano, así que porque no crear un script (en python) que automatice el proceso.

Para empezar tenemos que saber la correspondencia entre caracteres y signos, así que procedemos a abrir word e introducir los caracteres mas utilizados (letras mayúsculas y minúsculas, números, signos de puntuación, espacio) en una tipo de letra normal, con estos creamos una variable que llamaremos decode en nuestro código fuente, luego nuevamente en word cambiamos el tipo de letra por Wingdings y creamos otra variable que llamaremos encode, estas variables tienen que ser string unicode ya que los símbolos usados por la letra Wingdings son de lo mas raros; luego es cuestión de en un bucle ir reemplazando las coincidencias del caracter de encode en la posicion i con el carracter de decode en la misma posición. El script completo seria algo así:

#!/usr/bin/python
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# Por: Jhonatan sneyder Salguero Villa (sney2002@gmail.com)

import codecs
from os.path import split, splitext

def translate(path=""):
"""" Convertir texto en Wingdings a caracteres normales ""

text2decode = codecs.open(path, 'r', 'utf-8').read()

decode = u"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!”?¿¡.,;():/*-+=&%$# @"
encode = u"”¿¡"

for i in range( len(decode) ):
text2decode = text2decode.replace( encode[i], decode[i] )

filename = splitext( split( path )[1] )[0]

file = codecs.open('resultado_%s.txt' % filename, 'wb', 'utf-8')

file.write( text2decode )

file.close()

if __name__ == "__main__":
import sys

try:
file = sys.argv[1]
translate( file )
except:
print "uso: translate /ruta/archivo"

Ahora solo hay que copiar en un editor de texto plano lo que desean convertir, guardarlo y ejecutar el script dándole la ruta al archivo. Si alguien se pregunta por que no utilice el método translate de string, la razón es que la función maketrans no acepta caracteres unicode.

El script tiene algunos defectos como el no manejar excepciones en caso que el archivo en path no exista, solo funciona con este tipo de letra y en cada iteración crear un nuevo string. Como siempre todas las criticas son bienvenidas.

Si no tienen instalado el interprete python, pueden usar este “codificador/decodificador” Wingdings XDDD, esta escrito en javascript así que si usan demasiado texto puede bloquearse.

Categories
descargas linux programación python script wallpaper

Fondo de escritorio cambiantes para ubuntu

El otro día convencí a un amigo para que se pasara a linux y entre las muchas preguntas que me empezaron a llegar por parte de él (todo sea por la causa), una era sobre como hacer un fondo de pantalla como esos que trae por defecto Ubuntu que cambian cada cierto tiempo, me dio mucha pena el no poder responder en el momento ya que no tenia ni idea de como funcionaba, así que me puse a la tarea y la verdad no era nada del otro mundo, solo un pequeño archivo xml que describe las transiciones de las imágenes; para ver como se estructura el archivo podemos ojear el que se encuentra en /usr/share/backgrounds/cosmos/background-1.xml.

Ahora que ya sabia como crear mis propios sliders, solo faltaba automatizar el proceso (flojo que soy), y como decidí hacer de python mi lenguaje por defecto XD, pues me puse a trabajar y esto fue lo que me salio, no es el súper programa pero intente hacerlo lo mas pythonista que pude, por favor si alguien lee esto y tiene mas conocimientos de python, se le agradecerán todos las criticas que me ayuden a mejorar u_u

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# Por: Jhonatan sneyder Salguero Villa (sney2002@gmail.com)
# Crear fondos de escritorio cambiantes
import sys, os

FORMAT = """
%(static_time).1f
%(current)s


%(transition_time).1f
%(current)s
%(next)s
"""


class BackgroundSlider():
EXTENSIONS = [".jpg", ".jpeg", ".png"]

def __init__(self, static_time = 1200):
self.xml_parts = [""]
self.static_time = static_time
self.path = os.getcwd()

def get_images(self, ext=EXTENSIONS):
""" Guardar archivos con extencion (jpg, jpeg, png) en self.images """
# Se puede especificar los archivos como argumentos
files = sys.argv[1:] or os.listdir(".")
# Filtrar imágenes
self.images = [os.path.join(os.getcwd(), img) for img in files if os.path.splitext(img)[1].lower() in ext]


def add_image(self, current, next, static_time, transition_time = 5):
""" Adicionar imagen al slider """
self.xml_parts.append( FORMAT % locals() )


def make_slider(self):
""" Crear archivo xml que define el slider """
images = self.images

# Todo termina donde empiesa U_U
images.append( images[0] )

for i in range( len(images)-1 ):
self.add_image(images[i], images[i+1], self.static_time)

self.xml_parts.append("
")


def save(self, filename = "background" ):
""" Guardar el slider """

xml = file(filename + ".xml", 'w')

try:
xml.write( "n".join(self.xml_parts) )

except IOError:
print "Error al Guardar el archivo. Intente de Nuevo"

finally:
xml.close()


if __name__ == "__main__":
slider = BackgroundSlider()

slider.get_images()

slider.make_slider()

slider.save()

Luego puse este archivo con los demás script de nautilus (~/.gnome2/nautilus-scripts) y ahora mi amigo cuando quiera un fondo de escritorio, solo selecciona las imágenes, click derecho crear wallpaper y listo. Si les interesa pueden bajar el script de este enlace:

Categories
captcha descargas gnu megaupload ocr programación python software libre

Saltándose los captchas de Megaupload con python

Como todo buen gorrón me gusta las cosas gratis y fáciles, sobre todo cuando se tiene una serie de 24 capítulos que se quiere descargar sin estar pendiente rellenando captchas, y aunque las cuentas premiun no son tan caras, la verdad no me apetece gastarme una platica en algo que voy a utilizar muy rara vez, así que hice lo que cualquier persona normal haría, juntar un montón de software libre y pegarlos con un poco de python y voila mi propio gestor de descarga con reconocimiento de captchas (solo megaupload), ya se que hay muchos programas que hacen lo mismo y ademas libres (Tucan por ejemplo), pero usarlos no seria tan divertido, así que me puse a recolectar los materiales para mi “manualidad”. Gestor de descargas ya tenia y no podía ser mejor que wget, solo faltaba el reconocimiento de caracteres, ocr que llaman; después de un poco de búsqueda apareció tesseract que sin lugar a dudas es el mejor programa de reconocimiento de caracteres que haya visto hasta el momento. Solo faltaban algunas librerías como pytesser para “comunicarse” con tesseract y  libxml2dom (requiere libxml2) para consultar el dom en documentos aun cuando estos estén mal formados.

Como ven, lo bonito del software libre es que con tan solo una búsqueda nos encontramos con programas maravillosos, los cuales podemos utilizar sin ninguna restricción (sí, ya se que esto no es completamente cierto). Ahora si, con ustedes el script:

import libxml2dom
import urllib2
import urllib
import pytesser
import Image

MAX_TRY = 5 # intentos antes de rendirse
WAIT_TIME = 45 # tiempo de espera en segundos
CAPTCHA_INPUT_NAME = "captcha"
TEMP_FILE_NAME = "tempImg.gif"
ID_DOWNLOAD_LINK = "downloadlink"

def urlopen(url, data={}):
"""Abrir un recurso remoto, si se pasa data se envía por POST"""
req = urllib2.Request(url, urllib.urlencode(data) if data else None)
try:
sock = urllib2.urlopen(req)
try:
data = sock.read()
finally:
sock.close()
except IOError:
print "el archivo no existe"
else:
return data

def html2dom(page):
"""Retornar representación DOM de un documento html"""
dom = libxml2dom.parseString(page, html=1)
return dom

def tag(elem, tag):
"""Encontrar descendientes de un elementos por su tag"""
elements = elem.getElementsByTagName(tag)
return elements[0] if len(elements) == 1 else elements

def id(elem, Id):
return elem.getElementById(Id)

def attr(elem, attr):
"""Retornar atributo de un elemento"""
return elem.getAttribute(attr)

def save_img(uri):
"""Guardar imagen en local"""
data = urlopen(uri)
temp = file(TEMP_FILE_NAME, 'wb')
temp.write(data)
temp.close()

def resolver_captcha():
"""Resolver captcha"""
data = Image.open(TEMP_FILE_NAME)
return pytesser.image_to_string(data)[:4]

def fill_form(page):
"""Recolectar datos de formulario"""
try:
form = tag(page, 'form')
img = tag(form, 'img')

save_img(attr(img, "src"))

# crear diccionario valores a enviar
data = dict([(attr(i, 'name'),attr(i, 'value')) for i in tag(form, 'input')])

# "rellenar" campo captcha
captcha = resolver_captcha()
data[CAPTCHA_INPUT_NAME] = captcha
except:
return None
else:
return (data, captcha)

# Donde la magia sucede XD
def get(url):
"""Descargar archivo"""
times = 1

# solo links de megaupload
if url.find('http://www.megaupload.com/') != 0:
print "%s no es un link de megaupload" % url
return 0

# Abrir pagina de formulario
page = html2dom( urlopen(url) )

while True:
# llenamos el formulario
data, captcha = fill_form(page)

if not data or times == MAX_TRY:
print "Error al abrir %s, puede que el link haya sido deshabilitado" % url
return 0

print "%s ==> intento %dncaptcha = %s" % (url, times, captcha)
times += 1

# Enviamos formulario por POST
page = html2dom( urlopen(url, data) )

# Si el captcha esta correcto obtenemos la página de descarga
download_page = id(page, ID_DOWNLOAD_LINK)

if download_page:
download_link = tag( download_page , 'a' )
import subprocess, time

# please wait.... XD
time.sleep(WAIT_TIME)

args = ['wget', '-c', attr(download_link, 'href')]

# empezamos a descargar ^_^
proc = subprocess.Popen(args)
retcode = proc.wait()
return 1

def get_from_file(file_path):
"""descargar múltiples archivos leyendo urls almacenadas en un archivo"""
try:
sock = file(file_path)
try:
lines = sock.readlines()
finally:
sock.close()
except IOError:
print "el archivo %s no existe" % file_path
else:
for line in lines:
url = line.strip()
if url:
get( url )

if __name__ == "__main__":
import sys

arg = sys.argv[1:]

if arg[0] == "-f":
get_from_file(arg[1])
elif "http" in arg[0]:
get(arg[0])
else:
print "uso:nmget link_descarganmget -f /ruta/archivo/links_descargan"

Claro que le hacen falta algunas funcionalidades, pero para lo que lo necesito me basta y me sobra, ademas como ya dije existe una gran variedad de programas que hacen lo mismo. Si lo desean pueden descargar los archivos desde el siguiente enlace:

P.D.: Se aceptan criticas, solo no sean tan duros XD