Contenu | Rechercher | Menus

Annonce

Si vous rencontrez des soucis à rester connecté sur le forum (ou si vous avez perdu votre mot de passe) déconnectez-vous et reconnectez-vous depuis cette page, en cochant la case "Me connecter automatiquement lors de mes prochaines visites".

#1 Le 28/04/2010, à 23:13

sputnick

[JEU] #! /challenge/bash #8

1269554555.png

[informations sur le jeu]

<<    challenge bash #8

Le challenge est ouvert à tous les langages de scripting ! scripteurs bash, python, perl, ruby… à vos claviers !

Robot web pour récupérer les nouveaux fils des sous-forums Ubuntu de son choix.
L'objectif est de réaliser un script qui va parser le forum afin d'y récupérer l'information requise ( 2 fils minimum ).
Les nouveaux fils devront apparaitre dans une boite de dialogue graphique passive et cliquable.

Pour les plus motivés, il y a un challenge bonus, c'est de récupérer les nouveaux messages d'un fil en particulier.

La propreté sera prise en compte, l'originalité pourquoi pas, la concision surement.


A vos éditeurs !


bashfr.org(random);
<arciks1994> dou tu connai qel age j'ai ?

Hors ligne

#2 Le 28/04/2010, à 23:14

sputnick

Re : [JEU] #! /challenge/bash #8

jde3 vainqueur pour la partie python et teg pour le bash

Dernière modification par sputnick (Le 18/06/2010, à 05:26)


bashfr.org(random);
<arciks1994> dou tu connai qel age j'ai ?

Hors ligne

#3 Le 29/04/2010, à 10:49

jde3

Re : [JEU] #! /challenge/bash #8

Bon, celui-là semble plus abordable que le précédent... Je me lance (en python), même si je ne suis pas sûr de faire l'interface graphique (qui ne me passionne pas...)

Dernière modification par jde3 (Le 29/04/2010, à 10:50)

Hors ligne

#4 Le 29/04/2010, à 13:19

sputnick

Re : [JEU] #! /challenge/bash #8

Oui, ca peux très bien se faire en 10 lignes de code ^^


bashfr.org(random);
<arciks1994> dou tu connai qel age j'ai ?

Hors ligne

#5 Le 29/04/2010, à 15:15

jde3

Re : [JEU] #! /challenge/bash #8

Le mien ne sera pas en 10 lignes de code, mais ça peut motiver les suivants pour faire mieux : l'archive est à télécharger ici.

Pour exécuter ce code, il faut :
- avoir python d'installé (a priori toujours OK sur Ubuntu)
- taper

./parse_ubuntufr.py -h

dans un terminal pour avoir l'usage

PS : Merci à sputnick pour ton conseil.

PPS : je colle quand même le code pour les curieux...

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

import getopt, sys
from parser import *

def usage ():
	print "usage: " + sys.argv[0] + " [OPTIONS]"
	print "OPTIONS:"
	print "\t-h\t--help\t\tprint this help"
	print "\t-f n\t--forum=n\tprint details for forum_id n (default will print list of forums)"
	print "\t-m n\t--max-items=n\tonly print n most recent topics of a given forum (ignored if forum_id is not specified)"

def main():
	try:
		opts, args = getopt.getopt(sys.argv[1:], "hf:m:", ["help", "forum=", "max-items="])
	except getopt.GetoptError, err:
		# print help information and exit:
		print str(err) # will print something like "option -a not recognized"
		usage()
		sys.exit(2)
	forum_id = None
	max_items = None
	for o, a in opts:
		if o in ("-h", "--help"):
			usage()
			sys.exit()
		elif o in ("-f", "--forum"):
			forum_id = int (a)
		elif o in ("-m", "--max-items"):
			max_items = int (a)
		else:
			assert False, "unhandled option"

	if (forum_id == None):
		print UbuntufrHomeParser ()
	else:
		print UbuntufrForumParser (forum_id, max_items)

if __name__ == "__main__":
	main()
#! /usr/bin/python
# -*- coding: utf-8 -*-

import urllib, re, os
from item import *

class UbuntufrParser:
	def __init__ (self, url, mask, item_class, max_items = None):
		self.url = url
		self.mask = mask
		self.item_class = item_class
		self.max_items = max_items

		self.lines = urllib.urlopen (self.url).readlines ()
		self.items = []
		self.parse ()
		
	def __str__ (self):
		s = self.url + "\n"
		if (len (self.items) == 0):
			s = s + "\tRien de neuf par ici\n"
		else:
			for i in self.items:
				s = s + "\t" + str (i) + "\n"
		return s[:-1]

	def parse (self):
		in_an_important_div = False
		for l in self.lines:
			if (not (in_an_important_div) and (l.strip () == "<div class=\"tclcon\">")):
				in_an_important_div = True
				flines = []
			elif (in_an_important_div):
				if (l.strip () == "</div>"):
					in_an_important_div = False
					self.add_item (flines)
					if (self.max_items != None and len (self.items) >= self.max_items):
						break
				else:
					flines.append (l.strip ())
		
	def add_item (self, flines):
		l = flines.pop (0)
		re_forum = re.match (self.mask, l)
		if (re_forum):
			(id, text) = re_forum.group (1, 2)
			self.items.append (self.item_class (id, text))

class UbuntufrHomeParser (UbuntufrParser):
	def __init__ (self):
		UbuntufrParser.__init__ (self, "http://forum.ubuntu-fr.org/", "^<h3><a href=\"viewforum.php\?id=([0-9]+)\">(.*?)</a></h3>", Forum)

class UbuntufrForumParser (UbuntufrParser):
	def __init__ (self, id, max_items = None):
		UbuntufrParser.__init__ (self, "http://forum.ubuntu-fr.org/viewforum.php?id=" + str (id), "^<a href=\"viewtopic.php\?id=([0-9]+)\">(.*?)</a>", Topic, max_items)
#! /usr/bin/python
# -*- coding: utf-8 -*-

class Item:
	def __init__ (self, id, title):
		self.id = id
		self.title = title
		self.url = ""
	
	def __str__ (self):
		return "[" + str(self.url) + "] " + self.title

class Forum (Item):
	def __init__ (self, id, title):
		Item.__init__ (self, id, title)
		self.url = "http://forum.ubuntu-fr.org/viewforum.php?id=" + str (self.id)

class Topic (Item):
	def __init__ (self, id, title):
		Item.__init__ (self, id, title)
		self.url = "http://forum.ubuntu-fr.org/viewtopic.php?id=" + str (self.id)

if __name__ == "__main__":
	print Item (10, "Installation d'Ubuntu")

Dernière modification par jde3 (Le 30/04/2010, à 15:48)

Hors ligne

#6 Le 29/04/2010, à 15:45

sputnick

Re : [JEU] #! /challenge/bash #8

Même si ça te semble évident, si tu pouvais ajouter une brève explication de quoi faire avec tes 3 scripts, ça serais mieux pour les gens qui ne connaissent pas python.
Voir même en faire une archive à télécharger.


bashfr.org(random);
<arciks1994> dou tu connai qel age j'ai ?

Hors ligne

#7 Le 30/04/2010, à 09:25

nesthib

Re : [JEU] #! /challenge/bash #8

(abonnement)


GUL Bordeaux : GirollServices libres : TdCT.org
Hide in your shell, scripts & astuces :  applications dans un tunnelsmart wgettrouver des pdfinstall. auto de paquetssauvegarde auto♥ awk
  ⃛ɹǝsn xnuᴉꞁ uʍop-ǝpᴉsdnGMT-4

En ligne

#8 Le 30/04/2010, à 14:46

sputnick

Re : [JEU] #! /challenge/bash #8

@jde3, ton site d'upload, ça fait peur ! J'ai lâché l'affaire tellement les pubs sont invasives et les liens cachés.

Je te conseille http://dl.free.fr/

Dernière modification par sputnick (Le 30/04/2010, à 14:47)


bashfr.org(random);
<arciks1994> dou tu connai qel age j'ai ?

Hors ligne

#9 Le 30/04/2010, à 15:49

jde3

Re : [JEU] #! /challenge/bash #8

sputnick a écrit :

@jde3, ton site d'upload, ça fait peur ! J'ai lâché l'affaire tellement les pubs sont invasives et les liens cachés.

Je te conseille http://dl.free.fr/

C'est arrangé.

Hors ligne

#10 Le 04/05/2010, à 23:51

sputnick

Re : [JEU] #! /challenge/bash #8

On dirait que personne n'est capable de faire ça en bash tongue


bashfr.org(random);
<arciks1994> dou tu connai qel age j'ai ?

Hors ligne

#11 Le 21/05/2010, à 18:14

teg

Re : [JEU] #! /challenge/bash #8

sputnick a écrit :

Les nouveaux fils devront apparaitre dans une boite de dialogue graphique passive et cliquable.

sputnick a écrit :

On dirait que personne n'est capable de faire ça en bash tongue

Forcément ça complique la tâche.. j'ai zappé l'interface.

#!/bin/bash

URL_INDEX="http://forum.ubuntu-fr.org/index.php"
URL_SSF="http://forum.ubuntu-fr.org/viewforum.php?id="
PROXY=""

FICHIER_TMP=/tmp/ubuntu-fr

if [ $PROXY ]
then
        export http_proxy=$PROXY
fi

# Affichage du message d'usage du script et de la liste des forums disponibles :
liste_forums (){
        echo ""
        echo "Usage : $0 1 2 3"
        echo "        1, 2 et 3 sont les numéros des forums à suivre"
        echo ""
        echo "Liste des forums consultables :"

        # Téléchargement et affichage de la liste des forums :
        rm -f $FICHIER_TMP
        wget $URL_INDEX -O $FICHIER_TMP &> /dev/null
        grep $(echo $URL_SSF | cut -d / -f 4) $FICHIER_TMP | cut -d "=" -f 3 | cut -d "<" -f 1 | sort -n | sed "s|\">|\t|"
        rm -f $FICHIER_TMP
}

# Affichage des messages des sous-forums sélectionnés :
liste_messages (){
        rm -f $FICHIER_TMP*

        for i in $@
        do
                wget ${URL_SSF}${i} -O ${FICHIER_TMP}${i} &> /dev/null
        done

        grep viewtopic.php $FICHIER_TMP* | grep -v '#p' | cut -d ">" -f 2 | cut -d "<" -f 1 | grep -v Epingl > ${FICHIER_TMP}_msg

        if [ $(which html2text) ]
        then
                while read ligne
                do
                        echo $ligne | html2text
                done < ${FICHIER_TMP}_msg
        else
                cat ${FICHIER_TMP}_msg
        fi

        rm -f $FICHIER_TMP*
}

if [[ $# = 0 ]]
then
        liste_forums
else
        liste_messages $@
fi

Pour l'usage et la liste des forums consultables :

./teg_ubuntu-fr_robot.bash

Pour l'utilisation :

./teg_ubuntu-fr_robot.bash 9 28 ...

Peut-être que j'essayerais d'améliorer ça encore. C'est sûr il n'y a rien d'exceptionnel mais j'avais besoin d'exercice !

A noter : possibilité de paramétrer un proxy dans le script et bonus pour ceux qui ont html2text d'installé.

Hors ligne

#12 Le 21/05/2010, à 19:31

sputnick

Re : [JEU] #! /challenge/bash #8

Salut teg,

ce que je voit dans les choses qui me chiffonnent :

- tu pourrais traiter le flux à la volée sans utiliser de fichier temporaire
- les cuts à la chaine ça fait un peu peur
- for i in $@ peux s'écrire simplement for i, bash se débrouille tout seul.
- if [ $(which html2text) ] peux être simplifié et on peux utiliser un builtin bash : if type &>/dev/null html2text
- "USE MORE QUOTES!" Learn the difference between " and ' and `. See <http://wiki.bash-hackers.org/syntax/words> and <http://mywiki.wooledge.org/Quotes>.


Bien vu les deux modes de fonctionnement et bravo pour la présentation des ids avec le thème du sous forum.

Par contre, il semblerais plus logique de donner une url à la fin plutôt que le résumé.
Avec zenity ou notify-send on peux faire les deux en même temps.


bashfr.org(random);
<arciks1994> dou tu connai qel age j'ai ?

Hors ligne

#13 Le 21/05/2010, à 19:37

sputnick

Re : [JEU] #! /challenge/bash #8

@frafra, fini le avant de le montrer, nan ?
Merci d'indenter, ça donne pas envie de relire derrière, encore moins après ta présentation tongue

@tous : pour récupérer les liens d'une page, je vous conseille fortement mech-dump qui est "livré" avec le module perl www-mechanize ( paquet libwww-mechanize-perl pour debian/ubuntu ). Cela s'utilise en l'appelant en ligne de commande. Voir :

mech-dump --help

bashfr.org(random);
<arciks1994> dou tu connai qel age j'ai ?

Hors ligne

#14 Le 22/05/2010, à 05:59

cacalex

Re : [JEU] #! /challenge/bash #8

Je suis peut-être vieux jeu, mais pourquoi ne pas passer par links/elinks au lieu de wget ?
ex: "links  -dump"

Hors ligne

#15 Le 22/05/2010, à 09:54

nesthib

Re : [JEU] #! /challenge/bash #8

ou par curl ? tongue

perso j'utilise wget quand je dois récupérer les données dans un fichier et curl pour les avoir en sortie standard (même si tous deux savent faire ces deux opérations)

d'ailleurs si quelqu'un connait les différences principales entre wget et curl (faudrait que je fasse un post là dessus…)


GUL Bordeaux : GirollServices libres : TdCT.org
Hide in your shell, scripts & astuces :  applications dans un tunnelsmart wgettrouver des pdfinstall. auto de paquetssauvegarde auto♥ awk
  ⃛ɹǝsn xnuᴉꞁ uʍop-ǝpᴉsdnGMT-4

En ligne

#16 Le 18/06/2010, à 04:57

sputnick

Re : [JEU] #! /challenge/bash #8

Hé !
Je déclare jde3 vainqueur pour la partie python et teg pour le bash smile
Oui je sais ->[*]

Bon, j'ai pas eu le temps plus tot, mais j'ai une solution avec une partie bash assez courte pour récupérer  les nouveaux items et une partie system+php+javascript pour l'interface de visualisation. C'est ce qui m'a semblé le plus adapté et le plus efficace.

Voici le code que je met sur un serveur en cron toutes les minutes :
forums-grabber.bash

#!/bin/bash
# affiche les nouveaux sujets surveilles ou les ouvrent dans firefox

. /etc/profile

# IDs à surveiller :
ids="35 78 23"

namesids[35]='Développement et programmation' namesids[78]='Console et terminal' namesids[23]='Trucs, astuces et scripts utiles'

for i in $ids; do
        url="http://forum.kubuntu-fr.org/viewtopic.php?id=$(mech-dump 2>/dev/null --agent-alias='Linux Mozilla' --links --absolute "http://forum.kubuntu-fr.org/viewforum.php?id=$i" | \
                pcregrep -o '^http://forum.kubuntu-fr.org/viewtopic.php\?id=\K\d+$' | sort -n | tail -1)"

        if ! grep &>/dev/null "$url" ~/.ubuntuForumLog; then
            d=$(date +"%A %d %B %H:%M")
            {       echo "$(curl -s $url | awk -F '</?title>' '/<title>/{print $2}')%$url%${namesids[i]}%$d"
                    cat /home/www/sputnick-area.net/wordpress/forums.lst
            } | sort -t% -k3 > /tmp/forums.lst__ && mv /tmp/forums.lst__ /home/www/sputnick-area.net/wordpress/forums.lst && echo "$url" >> ~/.ubuntuForumLog
        fi
done

Il génère donc une sortie type csv dans forums.lst que mon code php va parser ensuite, voici mon interface :

http://www.sputnick-area.net/forums.php ( vous risquez de vous faire insulter )

outhl.png

et son code :

<?php session_start(); ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="./styles.css" />
<link rel="icon" type="image/gif" href="./favicon-forums.ico" />
<script src="./JS/favicon.js" type="text/javascript"></script>
<script type="text/javascript">
        setTimeout('location.reload(true)',1000*30); // refresh every 30 sec
        function changeTitle(title) { document.title = title; }
</script>
<!--
        written in 2010 by sputnick <gilles DOT quenot AT gmail DOT com>
-->
</head>
<body>
<?php
// on recupere la liste des sujets à consulter
// depuis un fichier systeme, avec sur chaque ligne
// cette syntaxe : "comment%url%sous-forum"
$filename = './forums.lst';
$fp = fopen( $filename, 'r' );
$file_contents = @fread( $fp, filesize( $filename ) );
fclose( $fp );
$lines = explode("\n", $file_contents);
$numlines = count($lines);

if ($numlines == 1) {
        echo '<script type="text/javascript">
  favicon.change("./favicon-white.ico"); 
</script>
<h2><div class="center">Pas de messages non lus</div></h2>' . "\n";
}
else {
        echo '<script type="text/javascript">
  favicon.change("./favicon-forums.ico");
</script>
<div class="center"><h2>Forum Ubuntu<i>:&nbsp;Les nouveaux fils...</i></h2></div>' . "\n";
}

// puis on traite chaque ligne pour l'afficher
for ($i = 0; $i < $numlines-1; $i++) {
  $comment = explode("%", $lines[$i]);
  $id = explode("=", $comment[1]);
  $v = $i+1;

  $new_entry[$i] = '&nbsp;' . $comment[3] . '&nbsp;<a href="forums-del.php?entry=' . $v . '&amp;id=' . $id[1] . '">' . $comment[0] . '</a>';

  if ($_SESSION['sfr'] != $comment[2]) {
          echo "<h3>$comment[2]</h3>";
  }
  $_SESSION['sfr'] = $comment[2];
  echo '
  <form action="forums-del.php?entry=' . $v . '" method="post">' . '
    <input type="submit" value="Delete" />&nbsp;' . $new_entry[$i] . '
  </form>';
}
?>
<br/><br/><br/><br/>
<div class="center">
  <form action="forums-del.php?entry=all&id=true" method="post">
    <input type="submit" value="BrowseAllLinks" />
  <form action="forums-del.php?entry=all" method="post">
    <input type="submit" value="DeleteAllStuff" />
        </form>
  </form>
</div>
<br/>
<br/>
<br/>
<div class="center">
  <img alt="w3c xhtml valid" src="http://www.sputnick-area.net/bus-cars-camtars/web_badges/valid_xhtml_blue.png" />
  <img alt="vim powered" src="http://www.sputnick-area.net/bus-cars-camtars/web_badges/vim_edited_blue.jpg" />
</div>
<?php
// alert via boite de dialogue JS si on a de nouveaux messages
if ($i != 0 && $i != $_SESSION['last']) {
  echo '<script type="text/javascript">
  alert("Check me bastard, right NOW !");
</script>';
  $_SESSION['last'] = $i;
}

// changement du titre en fonction du nombre de messages à consulter
echo '<script type="text/javascript">
  changeTitle("' . $i . ' items");
</script>';
echo "\n";
?>
</body>
</html>

Les features :
- boite de dialogue JS pour tous nouveau message ( on peut pas la rater )
- le favicon change de couleur si il y a des fils actifs
- le nombre d'items est indique dans l'onglet
- gere les sessions pour pouvoir échanger des variables entre les différents scripts php et savoir où on en est par session

quand on clique sur "delete", ca efface l'entrée via un sed dans le csv. Quand on clique sur un lien du forum, on passe sans le savoir ( ou faut etre rapide ) par http://www.sputnick-area.net/forums-del.php?entry=N&id=xxxx et ca efface ensuite aussi l'item.
"entry" étant le numéro de la ligne a effacer et "id", l'id du post sur le forum. Voici son code :

<?php session_start(); ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="icon" type="image/gif" href="./facicon.ico">
<title>Forum Ubuntu delete item</title>
</head>
<body>
<?php
// si c'est pas moi, on ne modifie rien :
$ip = $_SERVER['REMOTE_ADDR'];
if ($ip != 'xx.xx.xxx.xx') {
        echo '<script type="text/javascript">
                        alert("Usage reserve ' . $ip . ', hop charter direction /dev/null tudjuuu !");
                        window.location = "http://www.sputnick-area.net/forums.php"
        </script>';
}
else {
        $_SESSION['last']--;

        if (isset($_GET['entry'])) {
                if ($_GET['entry'] == "all") {
                        $cmd = ":> ./forums.lst";
                        system($cmd);
                }
                else {
                        // persistence des données simple et minimaliste ;)
                        // on va quand même pas sortir une BDD pour si peu ?! :D
                        $cmd = '/bin/sed -i "' . $_GET['entry'] . 'd" ./forums.lst';
                        system($cmd); // on te dit de le faire, tu le fais, point-barre !
                        // ( à la ligne )

                        if (isset($_GET['id'])) {
                                // on redirige vers le forum ad-hoc si on a cliqué sur ce lien
                                // dans la page précédente.
                                echo '<script type="text/javascript">
                                window.open("http://forum.kubuntu-fr.org/viewtopic.php?id=' . $_GET['id'] . '");
                                </script>';
                        }
                }
        }
        // on redirige vers la page principale
        echo "<meta http-equiv='refresh' content='0;http://www.sputnick-area.net/forums.php'>";
}
?>
</body>
</html>

Walla smile


bashfr.org(random);
<arciks1994> dou tu connai qel age j'ai ?

Hors ligne

#17 Le 24/08/2010, à 18:38

sputnick

Re : [JEU] #! /challenge/bash #8

Nouvelle version "tout en un" : http://www.sputnick-area.net/scripts/forums.php.html

Si ya des pros du php et que vous avez des commentaires sur mon code, je suis tout ouïe wink

Dernière modification par sputnick (Le 24/08/2010, à 18:39)


bashfr.org(random);
<arciks1994> dou tu connai qel age j'ai ?

Hors ligne

#18 Le 02/09/2010, à 21:43

sputnick

Re : [JEU] #! /challenge/bash #8

Bon voici un lien pour ce projet qui a pris un peu d'ampleur wink ./viewtopic.php?pid=3703928#p3703928


bashfr.org(random);
<arciks1994> dou tu connai qel age j'ai ?

Hors ligne

Haut de page ↑