#!/usr/bin/python
# Getmynews.py
# Copyright (c) 2001 Florian Hatat
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, write to the Free Software
# Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
"""Getmynews.py
Crée un arbre à partir des fichiers XML passés sur la ligne de commande
à l'aide du module xmllib (Python 1.5.2).
"""
################## Quelques paramètres configurables ##################
# Mettre à zéro pour désactiver
# Options de génération de la section "Quoi d'neuf ?"
MAX_NEWS_AGE = 7 # Ne pas afficher les nouvelles plus vieilles de 7 jours
MAX_NEWS_DISPLAY = 10 # Nombre maximum de nouvelles à afficher
# Options pour les sorties "HTML" et "XML"
DATE_RANGE_MAX = 0 # Ces deux options permettent de sélectionner les
DATE_RANGE_MIN = 0 # nouvelles dans un intervalle donné
################################# Fin #################################
PROGRAM_USAGE = """Ce script est libre, voir la source pour plus d'informations
Usage: getmynews [options] fichier1 fichier2 ...
Options:
--xml | --html | --neuf format des données générées par le script
-v, --debug mode "debug", le script est plus bavard
-h, --help affiche ce message
Options du format "Neuf" :
-a age, --max-news-age=age définit l'âge maximal des nouvelles à afficher
-d num, --max-news-display=num nombre maximum de nouvelles à afficher
Options des formats "XML" et "HTML" :
-s date, --depuis=date sélectionne les nouvelles plus récente que
la date "date"
-j date, --jusque=date sélectionne les nouvelles plus anciennces que
la date "date"
utilisez ces options en même temps pour
définir un intervalle de temps
"""
import xmllib
import string
import sys
import random
import time
import getopt
class XMLNews (xmllib.XMLParser):
def __init__(self):
xmllib.XMLParser.__init__(self)
self.mon_arbre = {"children": []}
self.actuel, self.pile = self.mon_arbre, []
def handle_xml(self, encoding, standalone):
self.mon_arbre["encoding"] = encoding
self.mon_arbre["standalone"] = standalone
def unknown_starttag(self, tag, attributes):
n_element = {"tag" : tag, "attributes" : attributes,
"children" : []}
self.actuel["children"].append(n_element)
self.pile.append(self.actuel)
self.actuel = n_element
def unknown_endtag(self, tag):
self.actuel = self.pile.pop()
def handle_data(self, data):
if string.lstrip(data) != '':
self.actuel["children"].append({"tag" : None,
"data" : data})
def output_tag(element, output_my_tag = 0, output_children_tags = 1):
"""output_tag(elem, output_my_tag = 0, output_children_tags = 1)
Retourne la chaîne représentant l'élément "element" passé en argument."""
sortie = ''
if element["tag"] == None:
return element["data"]
if output_my_tag:
sortie = "<" + element["tag"]
for attribute in element["attributes"].keys():
sortie = sortie + " " + attribute + '="' + \
element["attributes"][attribute] + '"'
sortie = sortie + ">"
for child in element["children"]:
sortie = sortie + output_tag(child, output_children_tags, \
output_children_tags)
if output_my_tag:
sortie = sortie + "" + element["tag"] + ">"
return sortie
NewsList, NewsListFormattee = [], {}
options = {}
try:
optlist, filelist = getopt.getopt(sys.argv[1:], "d:a:vhj:s:",
["max-news-display=", "max-news-age=",
"jusque=", "depuis=",
"help", "debug", "xml", "html", "neuf"])
for option in optlist:
options[option[0]] = option[1]
if options.has_key("--help") or options.has_key("-h"):
print PROGRAM_USAGE
sys.exit(0)
if (options.has_key("--xml") + options.has_key("--neuf") +
options.has_key("--html")) != 1:
raise getopt.error, "précisez un et un seul format de sortie"
if options.has_key("--debug") or options.has_key("-v"):
def debug_message(message):
# sys.stderr.write(message)
return
else:
def debug_message(message):
return
OUTPUT_FORMAT = options.has_key("--xml") + \
2 * options.has_key("--html") + \
3 * options.has_key("--neuf")
if options.has_key("-d"):
MAX_NEWS_DISPLAY = string.atoi(options["-d"])
if options.has_key("--max-news-display"):
MAX_NEWS_DISPLAY = string.atoi(options["--max-news-display"])
if options.has_key("-a"):
MAX_NEWS_AGE = string.atoi(options["-a"])
if options.has_key("--max-news-age"):
MAX_NEWS_AGE = string.atoi(options["--max-news-age"])
if options.has_key("-j"):
DATE_RANGE_MAX = string.atoi(options["-j"])
if options.has_key("--jusque"):
DATE_RANGE_MAX = string.atoi(options["--jusque"])
if options.has_key("-s"):
DATE_RANGE_MIN = string.atoi(options["-s"])
if options.has_key("--depuis"):
DATE_RANGE_MIN = string.atoi(options["--depuis"])
except getopt.error, message:
# sys.stderr.write(sys.argv[0] + ": " + message + "\n" + PROGRAM_USAGE)
sys.exit(1)
except ValueError, message:
# sys.stderr.write(sys.argv[0] + ": " + message + "\n" + PROGRAM_USAGE)
sys.exit(1)
debug_message("Lecture des fichiers\n")
for fichier in filelist:
debug_message(fichier + ": ouverture ")
try:
a, f = XMLNews(), open(fichier, "r")
debug_message("(ok), analyse ")
a.feed(f.read())
debug_message("(ok), fermeture ")
f.close()
debug_message("(ok)\n")
NewsList = NewsList + a.mon_arbre["children"][0]["children"]
except RuntimeError, message:
debug_message("(erreur), fichier ignoré\n")
# sys.stderr.write(sys.argv[0] + ": " + fichier + ": " + \
# "caprice à l'analyse\n")
except IOError:
debug_message("(erreur), fichier ignoré\n")
# sys.stderr.write(sys.argv[0] + ": " + fichier + ": " \
# "caprice à l'ouverture\n")
debug_message("Tri des nouvelles\n")
t = time.localtime(time.time())
today = t[0] * 10000 + t[1] * 100 + t[2]
if MAX_NEWS_AGE:
maxold = today - MAX_NEWS_AGE
else:
maxold = 0
if not DATE_RANGE_MAX:
DATE_RANGE_MAX = today
for nouvelle in NewsList:
# Plusieurs nouvelles peuvent être postées le même jour
# Éviter les conflits en ajoutant un suffixe aléatoire
# à la date
# Passage par string.atoi() pour n'ajouter que la partie
# décimale du nombre aléatoire, pour ne pas augmenter la date
# ce qui fausserait les comparaisons plus bas
if not nouvelle["attributes"].has_key("date"):
# sys.stderr.write('Aïe ! nouvelle sans attribut "date" :\n')
# sys.stderr.write('"' + string.strip(output_tag(nouvelle)) +
# '"\n')
continue
date_nouvelle = string.atoi(nouvelle["attributes"]["date"])
if date_nouvelle > today:
# sys.stderr.write("Aïe ! date future :\n")
# sys.stderr.write('"' + string.strip(output_tag(nouvelle)) +
# '"\n')
continue
if NewsListFormattee.has_key(nouvelle["attributes"]["date"]):
cle = `date_nouvelle + random.random()`
while(NewsListFormattee.has_key(cle)):
cle = `date_nouvelle + random.random()`
else:
cle = nouvelle["attributes"]["date"]
# Il peut arriver que des espaces indésirables pour l'esthétique
# du document se glissent
NewsListFormattee[cle] = string.strip(output_tag(nouvelle))
L = NewsListFormattee.keys()
L.sort(); L.reverse()
if OUTPUT_FORMAT == 1:
# XML
debug_message('Génération au format "XML"\n')
TXT_HEAD = '\n
Généré le """ +`t[2]`+"/"+`t[1]`+"/"+`t[0]`+ """
Date |
Nouvelle |
%s