Mais um blog inútil.

Python

Janeiro 28, 2010

Cantina da FCT UNL no Google Calendar (com SMS)

Arquivado em: coding, serious-business — falso @ 21:54

Ora Viva amigos!
Hoje venho aqui blogar não sobre uma coisa inútil como é habitual, mas sobre algo deveras útil!

Como devem saber (se não sabem, deviam!!!) eu há uns tempos tinha feito um parser à pagina das ementas no site dos Serviços de Acção Social da Universidade Nova de Lisboa que cria um RSS Feed onde se pode ver no Google Reader (ou outro) todos os dias a ementa do dia.

Mas já há uns tempos me tinham dito que na Universidade do Minho[ 1] há um marmanjo que importa as ementas lá do sitio para o Google Calendar. E vocês perguntam qual a razão para isso né? A beleza da cena é que no Google Calendar existe uma feature que permite enviar avisos de eventos por SMS, já viram onde isto nos leva né ;-)

Então decidi por mãos à obra e comecei a programar, decidi usar Python pois as APIs dos Serviços do Google parecem ser mais viradas para essa linguagem.

O primeiro problema era fazer parse da pagina da SAS, então descobri no Google um parser de HTML lindo chamado BeautifulSoup que até tem um *slogan* todo jeitoso - You didn’t write that awful page. You’re just trying to get some data out of it. Right now, you don’t really care what HTML is supposed to look like. Neither does this parser.
Em muito pouco tempo, sem usar uma única rege x lá consegui fazer parse ao site e sacar de la todos os dados que precisava.

Depois andei a cuscar o Google Data API Developer’s Guide: Python, e com a ajuda dos exemplos rapidamente fiz uma rotina que importava o que eu precisava para o Google Calendar.

Aqui se segue o código caso alguém queira implementar o mesmo para outras faculdades da UNL.

#!/usr/bin/env python
# this script can never fail
# -*- coding: utf-8 -*-

# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.

# urle de exemplo
# http://sas.unl.pt/cantina?year_menu:int=2010&month_menu:int=1&day_menu:int=25

import urllib
from BeautifulSoup import BeautifulSoup

try:
  from xml.etree import ElementTree # for Python 2.5 users
except ImportError:
  from elementtree import ElementTree
import gdata.calendar.service
import gdata.service
import atom.service
import gdata.calendar
import atom
import getopt
import sys
import string
import time

import datetime

# ids dos calendarios. almoco - almoco dieta - jantar - jantar dieta
cal_ids = ['/calendar/feeds/XXXXXXXXXXXXXXXXXXXXXXXXXX%40group.calendar.google.com/private/full',
          '/calendar/feeds/XXXXXXXXXXXXXXXXXXXXXXXXXX%40group.calendar.google.com/private/full',
          '/calendar/feeds/XXXXXXXXXXXXXXXXXXXXXXXXXX%40group.calendar.google.com/private/full',
          '/calendar/feeds/XXXXXXXXXXXXXXXXXXXXXXXXXX%40group.calendar.google.com/private/full']

# logar-se ao google
calendar_service = gdata.calendar.service.CalendarService()
calendar_service.email = 'XXXXXXXX@gmail.com'
calendar_service.password = 'XXXXXXXX'
calendar_service.source = 'Google-Calendar'
calendar_service.ProgrammaticLogin()

def ParsaSite(ano, mes, dia):
  params = urllib.urlencode({'year_menu:int': ano, 'month_menu:int': mes, 'day_menu:int': dia})
  f = urllib.urlopen("http://sas.unl.pt/cantina?%s" % params)
  soup = BeautifulSoup(f.read())

  # todas as cantinas
  cantinas = soup.findAll(attrs={'class' : 'cantina'})
  for cantina in cantinas:
    # verifica se o conteudo da class title e da FCT
    titletag = cantina.find(attrs={'class' : 'title'})
    if titletag.renderContents().count('ncias e Tecnologia'):
      # apanha o almoco
      almoco = titletag.nextSibling.nextSibling
      # percorre todos os pratos
      almoco_p = almoco.findAll('li')
      al = {}
      for prato in almoco_p:
        key = prato.next.renderContents()
        value = prato.next.next.next.next.next.renderContents()
        al[key] = value

      jantar = almoco.nextSibling.nextSibling
      jantar_p = jantar.findAll('li')
      ja = {}
      for prato in jantar_p:
        key =  prato.next.renderContents()
        value = prato.next.next.next.next.next.renderContents()
        ja[key] = value
      return (al, ja)

def InsereEvento(calendario_id, _data, refeicao, prato):
  evento = gdata.calendar.CalendarEventEntry()
  evento.title = atom.Title(text=prato)
  #evento.where.append(gdata.calendar.Where(value_string='Cantina FCT UNL - Monte de Caparica'))

  dt = datetime.datetime(_data.year, _data.month, _data.day)

  if refeicao == 1:
    inicio = dt + datetime.timedelta(hours=11,minutes=30)
    fim = dt + datetime.timedelta(hours=14,minutes=30)
  if refeicao == 2:
    inicio = dt + datetime.timedelta(hours=18,minutes=30)
    fim = dt + datetime.timedelta(hours=20,minutes=30)

  evento.when.append(gdata.calendar.When(start_time=inicio.isoformat(), end_time=fim.isoformat()))
  calendar_service.InsertEvent(evento, calendario_id)

dt = datetime.date.today()
while dt.weekday() < 5:
  (al, ja) = ParsaSite(dt.year, dt.month, dt.day)

  i = 0

  for k, v in al.iteritems():
    if k == 'Prato':
      InsereEvento(cal_ids[i], dt, 1, v)
    if k == 'Dieta':
      InsereEvento(cal_ids[i], dt, 1, v)
    i+=1

  i = 2

  for k, v in ja.iteritems():
    if k == 'Prato':
      InsereEvento(cal_ids[i], dt, 2, v)
    if k == 'Dieta':
      InsereEvento(cal_ids[i], dt, 2, v)
    i+=1

  # incrementa a data
  dt += datetime.timedelta(days=1)

# acabou boy

O script vai ser corrido todas as segundas durante a madrugada no cron.
Sei que o código não interessa a ninguém, e o que querem é os links para adicionar os calendários ao Google Calendar, portanto aqui vão.

Props pro webmaster do site da SAS por feito um HTML bem estruturadinho.

1 - Se alguém sofrer de algum problema de atraso mental e não souber activar as SMS no Google Calendar, no link para a Universidade do Minho está um documento a explicar como se faz

Janeiro 29, 2008

Gerador de Galeria de imagens HTML (Python)

Arquivado em: coding, work — amg @ 18:28

É um script que fiz em Python para gerar uma galeria de fotos em html a partir de um directório com fotos, pois precisava de o fazer porque tinha um directório com várias fotos e “colocar” uma foto de cada vez em código html é trabalhoso, por isso aproveitei uma biblioteca de Python e pus mãos à obra.

A minha primeira dificuldade foi certamente criar uma thumbnail da imagem em questão, por isso dei uma visita ao Google (http://www.google.pt) e rapidamente encontrei o que queria: Python Imaging Library (http://www.pythonware.com/products/pil/). É óbvio que não sabia como trabalhar com este, então disse a mim mesmo: RTFM, fi-lo e em questão de minutos já sabia minimamente o que queria.

Primeiro de tudo tive que indicar que imagem abrir, para isto atribuí a uma variável o resultado de

Image.open(imagem)

Em que imagem será uma variável com o caminho da foto/ficheiro.

Também declarei outra variável: THUMBSIZE, em que atribuí a esta a largura e altura da thumbnail (230x153), mais propriamente o valor 230,153. Após isto utilizei a função

Thumbnail

da biblioteca PIL (Python Imaging Library) para a criar, que tem a seguinte sintaxe:

Img (esta foi uma variável criada por mim em que terá como valor o resultado de image.open(imagem) –

img.thumbnail(THUMBSIZE)

OK. Já tenho a thumbnail da imagem, agora tenho que a salvar… mas há um problema: Imaginemos que o utilizador do script já o correu anteriormente, mas agora acrescentou mais imagens, só que as thumbnails das imagens já existentes encontram-se no directório… como fazer para não criar uma thumbnail de uma thumbnail?

É simples, basta utilizar um if para verificar se as primeiras 5 letras da variável imagem são constituídas pela palavra thumb

If imagem[0:5] != “thumb”:

Após esta verificação, caso o resultado seja Verdadeiro e não Falso, o script vai executar o que vem a seguir a esta condição:

Img.save(’thumb.’ + str(imagem), “JPEG”)

Ou seja, o ficheiro ficará: thumb.Foto1.JPG note-se aqui o uso da função str() para converter o valor de imagem para uma string (cadeia de caracteres alfanuméricos). Basicamente a função save do PIL é para salvar num ficheiro as alterações feitas à imagem.

E pronto, temos o problema de criar as thumbnails resolvido.

Aqui abaixo segue-se o código completo do script.

galeria.txt

Tive que o colocar num ficheiro porque não sei mandar o wordpress ignorar tags html.

Nota: As tags html do código não estão terminadas porque fiz isto um pouco à pressa.