Mais um blog inútil.

Janeiro 28, 2010

Cantina da FCT UNL no Google Calendar (com SMS)

Filed under: 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 regex 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 [/sourcecode] 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

13 comentários a “Cantina da FCT UNL no Google Calendar (com SMS)”

  1. rippe diz:

    alta pesquisa falso!
    Bom trabalho.

    Essa merda faz mesmo efeito!!!!! lulz

  2. madinfo diz:

    Só e pena eu comer em casa todos os dias... acho que vou pedir a minha mãe para começar a por a ementa online...

  3. mirage diz:

    Excelente trabalho, mas não há bela sem senão: ser em python...

    Vou mandar uma posta de pescada aleatória e dizer que se fosse eu faria em ruby com estas libs:

    http://rdoc.info/projects/hpricot/hpricot
    http://rubyforge.org/projects/googlecalendar

  4. sadik diz:

    ganda tesão de anus!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!és!!!!!!!!!!!!!!!!!!!!!o!!!!!!!!!!!!!!!!!!!!!!!maior!!!!!!!!!!!!!!!!!!!!!!!!!!

  5. Jasus diz:

    Mas és estudante oh falso?

  6. Gimbras diz:

    AMEI, é o post mais útil de sempre do blol. És o maior vencedor que alguma vez vi, parabéns para sempre.

  7. Olá

    Parabéns pelo bom trabalho. Quando o David me disse que tinhas um parser para a página antiga, ainda pensei em ter algo que te simplificasse a vida, como um feed de RSS. O resto do trabalho é não me permitiu fazer isso, sinto muito. Mas também não foi preciso :) .

    Quanto ao python, é sem dúvida nenhuma uma excelente linguagem.

    José Santos
    (um dos tipos que fez o site do SAS)

  8. Jasus diz:

    Python é manifesta e assumidamente, sem dúvida nenhuma, Gay. Resta aferir se o Python é uma excelente linguagem pelo facto de ser Gay, ou não.

  9. [...] revi o post do falso sobre as ementas das cantinas da UNL, fiquei aborrecido com o entusiasmo do falso em relação ao [...]

  10. João diz:

    Boas, andei a tentar adaptar este codigo para outra faculdade da nova, mas estou um pouco á nora, onde hei-de implementar o código, já procurei no Google API e não consigo andar com isto.
    Agradeço resposta
    Obrigado

  11. [...] que fiz o post sobre a Cantina da FCT/UNL no Google Calendar já tive alguns pedidos para fazer o mesmo para outras escolas da UNL, então hoje decidi por mãos [...]

Comentar

widgeon
widgeon
widgeon
widgeon