Archives de catégorie : Python

[Python] : quelques minutes avec Tkinter (GUI)

Tkinter est un module graphique pour python, un GUI (Graphical User Interface). Bien sûr, cet article intéressera les débutants car il s’agit de découvrir le module le plus simplement possible mais avec un exemple « concret ». Je dis concret en double quotes car en fait ce n’est pas si utile que cela mais il faut bien avoir un but pour développer et écrire quelques lignes de codes.

Pour apprendre, je vous propose de réaliser un petit soft qui va avoir deux boutons (un pour quitter, l’autre pour lancer une action). L’action consistera à réaliser la liste des répertoires de ma home « ~ ». Et on affiche tout cela dans une fenêtre spécifique. Comme ceci :

file_manager

Nous utiliserons deux modules :

  • tkinter pour l’interface graphique
  • os : pour lister les répertoires au niveau de notre système
#!/usr/bin/python
#coding: UTF-8
import os
from Tkinter import *

def affichageRepertoires():
    path = os.path.expanduser("~/")
    for f in os.listdir(path):
        cadre2.insert(END, f + "\n")

if __name__ == '__main__':
    principale = Tk()
    cadre1 = LabelFrame(principale, text="FILE MANAGER", font="Arial 14")
    cadre1.grid(row=0, columnspan=2, sticky='E')

    Button(cadre1, text="Afficher répertoire", font="Arial 8", command=affichageRepertoires).grid(row=1, column=1)
    Button(cadre1, text="Quitter", font="Arial 8", command=principale.quit).grid(row=1, column=2)

    cadre2 = Text(master=principale)
    cadre2.grid(row=2, column=1, sticky=NW)
    
    cadre3 = Scrollbar(principale, orient=VERTICAL, command=cadre2.yview)
    cadre3.grid(row=2, column=2, rowspan=15, columnspan=1, sticky=NS)
    cadre2.config(yscrollcommand=cadre3.set, font=('Arial 8'))

    root.mainloop()

Les différentes lignes de codes permettent :

  1. codage en UTF8 (pour ne pas avoir de problème avec les accents)
  2. import des deux modules
  3. création d’une fonction  affichageRepertoires() :
    1. utilisation de os.path : pour récupérer les chemins
    2. parcourir la liste obtenue
    3. afficher les éléments dans le cadre 2 avec un renvoi à la ligne à chaque fois
  4. le bloc principal :
    1. création de la fenêtre principale
    2. définition du premier cadre de type Label (avec titre intégré)
    3. placement du cadre 1 aligné à droite dans la fenêtre et sur la première ligne d’une grille « imaginaire »
    4. ajout des deux boutons dans le cadre 1 avec le texte qui correspond et surtout la commande qui va avec. Pour le premier la commande lance notre fonction affichageRepertoires() pour le second elle quitte la fenêtre « principale ». Attention l’alignement se fait toujours sur notre grille mais en ligne n°1 et colonne 1 puis 2 en fonction du bouton.
    5. création du cadre 2 dans la fenêtre « principale ». Ce cadre sera alimenté par la fonction affichageRepertoires().
    6. la grille nous permet une fois de plus de placer notre cadre en ligne n°2/colonne n°1 et aligné en haut à gauche (NW : nord ouest)
    7. le cadre 3 consiste à ajouter la barre de défilement dans la fenêtre « principale » en se basant sur la fenêtre cadre 2 (command)
    8. Positionnement de cadre 3
    9. Configuration du cadre 2 avec la barre de défilement de cadre3

Tkinter pour python fait partie des modules très bien documentés. Vous pouvez consulter cette page en français et pour être plus complet cette page en anglais.

 

[Sécurité] : scapy – scanner les réseaux wifi (SSID) et leur adresse MAC

Scapy, un mot qui peut faire peur car fait référence à certaines pratiques obscures en matière de sécurité. Effectivement, scapy fait partie des outils de base des hackers… peu importe leur couleur. Retrouvez la documentation en ligne ici et mes autres post python ici.

IMG-3211

Scapy permet notamment de faire de nombreuses opérations sur les réseaux comme sniffer, envoyer des paquets, scanner…

Ne vous inquiétez pas je ne suis pas obscure. Il s’agit simplement de l’envie de découvrir cet outil dont on entend si souvent parler. Aujourd’hui j’ai voulu découvrir comment scanner les réseaux wifi autour de moi (à priori rien d’illégale là-dedans… après cela dépend de ce que l’on fait avec le scan).

Première chose à faire installer scapy :

pip install scapy

C’est donc un simple module que je peux ajouter à python.

Je me reporte ensuite à cet article qui propose de scanner les réseaux wifi. Il me faut donc installer aircrack-ng pour avoir accès à la comande airmon-ng. Aircrack est un binaire qui permet de réaliser de nombreux opérations de pénétrations de réseaux wifi (cracjing de clé…).

└─ $ ▶ sudo apt-get install aircrack-ng

Airmon-ng va nous permettre de devenir observateur du réseau (sans action dessus). Je lance donc airmon sur mon interface wifi :

sudo airmon-ng start wlp3s0

Voilà pour la première étape donc. Maintenant il faut créer un fichier python qui va utiliser le module scapy (je me reporte à la page citée précédemment… on vera pour faire notre propre script plus tard).

Je créé un fichier scapy_scan.py avec ceci :

from scapy.a:qll import *
ap_list = []
def packetRecup (pkt) :
    if pkt.haslayer (Dot11) :
        if pkt.type == 0 and pkt.subtype == 8 :
            if pkt.addr2 not in ap_list :
                ap_list.append(pkt.addr2)
                return "Réseau SSID: %s et MAC address: %s " %(pkt.info, pkt.addr2)
sniff(iface = "mon0" , prn = packetRecup)

Que contient ce script ?

Conclusion : scapy est un outil qui à l’air simple à utiliser et à apprendre. Bien sûr il faut connaitre python avant toute chose et faire attention de ne pas partir sur des tentatives plus obscures dans l’utilisation de cet outil. Je pense que je me ferais encore quelques tests sur  mon réseau local notamment tenter de sniffer des paquets et de faire des envois car c’est un peu la base de l’outil.

Et vous vous utilisez scapy ?

[Python] : Comment mettre en place un padding (retrait) sur votre sortie standard ?

Padding, je ne suis pas sûr que le terme soit tout à fait adapter. Mais en même temps je ne sais pas comment expliquer ce que je veux vous montrer.

Concrètement je dirais comment centrer un texte en l’entourant de caractères particuliers (spéciaux souvent) ? voici ce que nous cherchons à obtenir :

#####Bonjour#####

Ce genre d’affichage peut être sympa sur la sortie standard lorsque vous exécutez vos scripts. Ainsi vous pouvez faire des blocs et faire des mises en forme plus sympas.

Alors comment faire avec python ?

>>> text="bonjour"
>>> "{:#^20}".format(text)
'######bonjour#######'

Une autre ligne de commande fonctionne également :

>>>format(text, '*^20')

Le padding centré est incrémenté par le caractère « ^ ».

Pour réaliser un simple padding à gauche (un retrait à gauche), vous devriez passer la commande suivante :

>>>format(text, '>20')

Et le retrait à droite pour la forme :

>>>format(text, '<20')

Pour en savoir un peu plus sur ce sujet, consultez la doc officielle python des spécifications des formats sur cette page.

[Python] : comment simplifier vos switch case avec la fonction lambda ?

Lambda, un mot qui peut faire peur pour les débutants en python. Pourtant les fonctions anonymes lambda permettent de simplifier le code et de le rendre plus compact. Certe leur lecture nécessite un peu de pratique mais elles réduisent la longueur de vos scripts.

En voici encore un exemple avec le classique switch/case. Python n’est pas équipé d’outils spécifique comme bash, php ou autres… Du coup il faut passer par le classique « If … elseif … else ». C’est dommage et je dirais que c’est presque moche non ?

C’est là que labda le vengeur masqué intervient et va nous réduire et embellir tout cela.

Voyons le cas classique dans un premier temps

def sans_lambda(op, a, b):
    if op == 'addition':
        return a + b
    elif op == 'soustraction':
        return a - b
    elif op == 'multiplication':
        return a * b
    elif op == 'division':
        return a / b
    else:
        return None

Et maintenant avec lambda :

def avec_lambda(op, c, d):
    return {
        'addition': lambda: c + d,
        'soustraction': lambda: c - d,
        'multiplication': lambda: c * d,
        'division': lambda: c / d,
    }.get(op, lambda: None)()

Vous le voyez avec lambda c’est mieux. Une lambda pour chaque cas. On intègre directement cela dans le return.

[Python] : comment requêter une base mysql avec mysql.connector ?

Mysql Connector est le module le plus répandu pour utiliser une base de données mysql à partir de python. Il est relativement facile à utiliser. Nous aurons l’occasion de voir dans d’autres articles des manipulations plus complexes mais il faut bien commencer par… le commencement.

Comment réaliser un simple SELECT et afficher son résultat en Python ? voici comment faire si vous êtes débutant.

import mysql.connector

madatabase = mysql.connector.connect(
  host="localhost",
  user="nom_utilisateur",
  passwd="mon_password",
  database="mabase"
)

session = madatabase.cursor()
sql = "SELECT * FROM matable;"
session.execute(sql)

resultat = session.fetchall()

for x in resultat:
  print(x)

session.close()


Donc quelles commandes avons nous passé ?

  • import du module
  • création d’une instance madatabase avec les paramètres de connexion. C’est tout à fait classique on retrouve cela avec de nombreux modules de moteurs de bases de données
  • ouverture d’une connexionavec l’instanciation de la classe cursor
  • la variable sql contient la requête à passer
  • on lance la requête avec notre variable
  • on récupère tous les résultats (sous forme de liste)
  • il ne reste plus qu’à parcourir la liste
  • et on oublie pas de dire au revoir et merci au serveur en fermant la session

Vous pouvez d’ores et déjà retrouver plus d’infos en ligne sur le site mysql et sa rubrique dédiée à ce module Python.

[Python] : comment charger des datas en base de données mysql avec mysql.connector ?

Revenons à nos pythons. Objectif du jour faire découvrir comment charger des données dans une base mysql à partir du module mysql.connector ?

Extrêmement facile. Vous me direz c’est normal car c’est le but des modules de python.

Premier cas on va chercher une ligne simple :

# import du module
import mysql.connector

# paramètres de connexion à la base
mabase = mysql.connector.connect(
  host="localhost",
  user="monutilisateurdb",
  passwd="motdepassedb",
  database="madatabase"
)

cursor = mabase.cursor()

sql = "INSERT INTO matable (id, valeur) VALUES (%s, %s)"
data = [("1", "Xavki"),("2", "Pierre"),("3", "Jacques"),("4", "Paul")]
cursor.executemany(sql, data)

mabase.commit()

Donc là on vient d’inséré une ligne. Mais bon on veut en insérer plusieur voir mieux insérer une liste. Alors il faut utiliser « executemany » :

# import du module
import mysql.connector

# paramètres de connexion à la base
mabase = mysql.connector.connect(
  host="localhost",
  user="monutilisateurdb",
  passwd="motdepassedb",
  database="madatabase"
)

cursor = mabase.cursor()

sql = "INSERT INTO matable (id, valeur) VALUES (%s, %s)"
data = ("1", "Xavki")
cursor.execute(sql, data)

mabase.commit()
print(cursor.rowcount, " insérées") 

[Python] : comment inverser un string ou une phrase (ou une liste plus généralement) ?

C’est bref mais efficace avec python : comment inverser une liste ? ou une phrase ? Il suffit de savoir manipuler les listes et parcourir cette liste à l’envers. C’est quelque chose que doivent savoir faire les débutants.

Il existe toutefois 2 méthodes.

La première c’est d’utiliser les plage d’index et de partir par la fin comme ceci :

>>> text="Salut tout le monde"
>>> text[::-1]
'ednom el tuot tulaS'

Terriblement efficace.

Sinon il y a la méthode par les méthodes lol avec reversed qui s’applique aux listes.

>>> text="Salut tout le monde"
>>> "".join(reversed(text))
'ednom el tuot tulaS'

N’hésitez pas à partager en commentaires vos astuces !

[Ansible] : lister les variables de rôles non documentées dans le README.md

Les rôles de ansible sont plus ou moins faciles à utiliser. Un des principaux facteurs limitants, c’est la documentation du README. Du coup j’ai créé un petit script pour lister les variables de vos rôles et ensuite vérifier si ces variables sont bien documentées dans le README.md (si vous avez d’autres idées n’hésitez pas).

#!/usr/bin/python3


# coding: utf8



import re
import os

def list_variables (pattern, dir):
    
  variables=[]
    
  r = re.compile(pattern)
    
  for parent, dnames, fnames in os.walk(dir):
 
       for fname in fnames:

            filename = os.path.join(parent, fname)

            if os.path.isfile(filename):

                with open(filename,encoding="latin-1") as f:

                    for line in f:

                        if r.search(line):

                          reg=r"pattern"

                          for item in re.findall(r''+pattern+'',line):

                            if item not in variables:

                              variables.append(item)

  return variables



# lister les roles

def list_roles (dir):

        roles=[]

        regexp = re.compile(r'.*\/roles\/[a-z0-1_-]+$')

        for dirname, dirnames, filenames in os.walk('.'):

                for subdirname in dirnames:

                        rep=os.path.join(dirname, subdirname)

                        if regexp.search(rep):

                                roles.append(rep)

        return roles



# avec la fonction grep on liste toutes les variables contenant un _


for role in list_roles("."):

    r = re.compile('[.]?roles/(.*)')

    match = r.search(role)

    print("")

    print("#################################################################")

    print("         Analyse du role : "+ match.group(1))

    print("#################################################################")
    compteur=0

    list_var=list_variables("\{\{\s?([a-z]+[_]+[a-z_]+)\s?\}\}",role)

    for variable in list_var:

        compteur+=1

        with open(roles+"/README.md",encoding="latin-1") as f:

            concaten=""

            for line in f:

                concaten+=line

            if not re.search(variable,concaten):

                print("Variable à éditer :"+variable)

    print(" = "+str(compteur)+" variable(s) analysé(es)")

Explications :

  •  une fonction qui liste les variables ansible :
    • on parcourt les directories (à l’aide du module OS de python)
    • et avec une regex on applique un pattern pour retrouver ce qui ressemble à une variable ({{ variable }}
    • enfin on met tout cela dans un tableau bien propre
  • une fonction qui liste les rôles :
    • idem on parcourt les directories et on cherche les répertoires contenus dans « roles »
    • à l’aide d’une regex on nettoie le nom du rôle
  • Pour finir on orchestre tout cela :
    • on boucle sur la liste des variables
    • on ouvre le README.md que l’on place dans une variable simple(on concatène les lignes)
    • et on y cherche la variable
    • si elle n’est pas dedans on affiche qu’elle est à éditer
    • et pour finir on affiche à la fin de chaque rôle le nombre de variables analysées.

Si vous voyez d’autres scripts de ce genre qui pourrait être utiles indiquez le en commentaire j’y jeterez un coup d’oeil.

[Python] : un mot sur les listes ? boucles for…

Les listes en python permettent de laisser place à toute votre imagination. De nombreuses astuces permettent d’alimenter une liste ou encore de la parcourir avec les slices, les ranges ou autres.

Je n’ai pas le niveau pour prétendre faire le tour de la question mais j’ai envie de partager mon expérience à ce sujet. En effet, un peu d’expérience dans ce domaine permet de gagner du temps, de simplifier son code et tout simplement de progresser.

Création d’une liste le plus simplement du monde

Définir et alimenter une liste en premier lieu c’est :

>>> liste=['B','o','n','j','o','u','r']

Ensuite lorsque l’on débute on réalise ce genre d’opération :

>>> texte="Bonjour Xavki"
>>> liste=[]
>>> for i in texte:liste.append(i)
>>> print(liste)
['B', 'o', 'n', 'j', 'o', 'u', 'r', ' ', 'X', 'a', 'v', 'k', 'i']

Avec la fonction append, on a ajouté chaque caractère à la liste. En outre, la variable texte fait aussi office de liste et est utilisable comme telle.

Liste  créée et définie en une ligne avec for intégré

>>> print(texte)
Bonjour Xavki
>>> a = [i for i in texte]
>>> print(a)
['B', 'o', 'n', 'j', 'o', 'u', 'r', ' ', 'X', 'a', 'v', 'k', 'i']

Là c’est déjà plus sympa.

Et puis on peut aller plus loin si nécessaire et y placer des conditions avec « if ».

>>> a = [i for i in texte if i == "o"]
>>> print(a)
['o', 'o']

Faire d’une liste de liste… une unique liste

Ce cas se présente souvent, vous avez une liste de liste et vous souhaitez n’en faire qu’une simple liste. Faire cette opération peut se révéler un peu fastidieux car il faut faire deux boucle for et ajouter les éléments avec un append dans notre  liste finale.

Bref voici comment se simplifier la vie et mieux comprendre ce principe d’alimentation des listes. Et avec ça vous aller devenir de vraies oneliners (la frime lol).

>>> texte = [['B','o','n'], ['j','o','u','r']]
>>> print(texte)
[['B', 'o', 'n'], ['j', 'o', 'u', 'r']]
>>> liste=[txt for tmp in texte for txt in tmp]
>>> print(liste)
['B', 'o', 'n', 'j', 'o', 'u', 'r']

Vous me direz cela n’empêche pas de faire deux boucles mais tout cela prend peu de lignes.

Et donc si vous avez compris les « for » empilés voici la même chose avec un niveau supplémentaire.

>>> texte = [['B','o','n'], ['j','o','u','r'],[' ',['X','a','v','k','i']]]
>>> liste=[i for tmp in texte for txt in tmp for i in txt]
>>> print(liste)
['B', 'o', 'n', 'j', 'o', 'u', 'r', ' ', 'X', 'a', 'v', 'k', 'i']

 

[Python] : comment lire les lignes d’un fichier tout simplement ? read et readline

Python pour les débutants, c’est avant tout de savoir lire un fichier ligne à ligne. Évident pour certains mais lorsque l’on commence, il faut bien apprendre.

Pour nous aider python possède deux fonctions ultra-utilisées : read et readline. Je pense que les deux sont inséparables.

Pour faire lire des lignes ou même en écrire de manière simple, vous pouvez aussi vous reporter à cet article précédent sur le module PATHLIB.

Read c’est l’équivalent de readline mais aux caractères. Ainsi, il permet d’afficher caractère par caractère le contenu d’une variable. Par exemple :

#notre fichier contient

première ligne

deuxième ligne

troisième ligne



>>> fichier = open("texte.txt")

>>> fichier.close()

>>> print(fichier.read(1))

p
>>> print(fichier.read(1))

r
>>> print(fichier.read())

première ligne

deuxième ligne

troisième ligne

On affiche donc le premier caractère de la première ligne. Read fonctionne donc par caractère et au fur et à mesure le curseur avance d’un caractère. Le paramètre pris par read est aussi le pas d’avancement du curseur. Si aucun paramètre n’est passé c’est tout l’élément qui est affiché. On peut donc afficher un fichier en faisant un simple read().

Readline c’est la même chose mais non pas en caractère mais en ligne comme son nom l’indique.

>> print(fichier.readlines())
[
'première ligne\n',
'deuxième ligne\n',
'troisième ligne\n'
]

Readlines produit donc une liste consultable comme tout autre liste… en la parcourant.

>>> fichier = open("texte.txt")
>>> for ligne in fichier.readlines():
...     print(ligne)
première ligne
deuxième ligne
troisième ligne

Kool non ? donc deux méthodes pour récupérer le contenu d’un fichier mais on n’en fera pas la même chose :

  • read() : pour afficher tout le fichier ou le récupérer dans une seule variable
  • readlines() : pour l’utiliser ligne à ligne ou dans un tableau.

 

[Python] : comment logger dans vos scripts avec logging ?

Python est bien équipé en matière de modules. Une fois de plus, il nous met à disposition le nécessaire pour faire simplement les choses. Logguer est une nécessité pour savoir si vos scripts et vos applications se portent bien, pour suivre les résultats et superviser.

Avec logging, vous pourrez logger en mettant en forme vos logs en les paramétrant de différentes manières pour vous faciliter la vie. Logging permet de structurer, hierarchiser, écrire vos logs.

Voici ce que j’utilise de mon côté :

import logging
import sys

# create logger
logging.basicConfig(filename='/var/log/script.log',format='%(asctime)s - %(name)s - %(levelname)s >>>> %(message)s',level=logging.DEBUG)
logger = logging.getLogger('script python xavki')
logger.addHandler(logging.StreamHandler(sys.stdout))

if __name__ == "__main__":
  try:
     logger.info('Action 1 [OK]')
  except:
     logger.warning('Action 1 [KO]')

Alors voici ce que nous avons fait :

  • import des modules logging et sys
  • instanciation du logger
    • le fichier de log et sa localisation
    • le format (date / nom / niveau de log / message)
    • ajout d’un handler qui permet de logger également sur stdout (on log donc dans un fichier et à l’écran)
  • dans le try (cas de réussite) : lancement du script et log pour dire [OK]
  • dans le except (cas d’erreur) : log pour dire [KO]

Et le résultat :

2018-08-19 22:10:26,620 - script python xavki - INFO - Action 1 [OK]
2018-08-19 22:10:26,695 - script python xavki - WARNING - Action 1 [KO]

A vous ensuite d’organiser la hiérarchie de vos log :

  • info
  • warning
  • debug
  • error
  • critical

Si votre configuration vous semble un peu complexe et pour homogénéiser plus facilement votre conf logging, utilisez un fichier de conf (format ini ou yaml).

logging.config.fileConfig('logging.conf')

Vous pouvez consulter la page de doc python pour en savoir plus. Sachez qu’il est aussi possible de logger par mail en smtp.

[Python][Bash] : comment piper (combiner) du bash dans du python -c en une ligne ? façon oneliner

Peut-être un peu pour la frime et d’autres pour tester certainement. Nombreux sommes nous à vouloir faire un truc bizare en combinant, comme le fait si bien perl, du bash et du python. Mais python n’est pas un animal facile. Vous allez le voir il faut faire preuve d’imagination.

Voici par exemple comment faire un cat et le reprendre dans python pour extraire.

cat /var/log/syslog | python -c "import sys;
import re;
reg=re.compile('(21:.*)');
[ligne for ligne in sys.stdin if sys.stdout.write(reg.search(ligne).group(1))+'\n']"

C’est chaud un peu non ?

Expliquons ce « oneline », un peu tiré par les cheveux :

  • le cat on revient pas dessus avec un pipe pour passer les données à la commande suivante
  • python -c : -c pour passer des commandes (on est pas dans un fichier de script)
  • import sys : pour le module système
  • import re : pour les regex
  • re.compile pour compiler le pattern de la regex
  • ensuite on récupère ligne par ligne sys.stdin (la sortie stdin correspond au pipe du cat)
  • puis on écrit dans stdout le résultat de la regex (group 1)

On peut faire un peu plus simple par exemple pour reprendre un cat :

ps aux | python -c "import sys; print sys.stdin.read()"

Alors est-ce que vous êtes toujours chaud pour faire du one line avec Python ? un peu moins ? Perso je préfère largement perl pour faire ce genre d’action si nécessaire. Awk est aussi pas mal dans son genre.

## en perl :
cat /var/log/syslog |
perl -nle 'm{(21.*)} and print $1'

## en awk
cat /var/log/syslog |
awk 'match($0, /(21.*)/){print substr($0, RSTART, RLENGTH)}'

Il faut savoir qu’il existe aussi des scripts python qui permettent de simplifier le travail mais bon c’est pas classe intellectuellement lol.

et vous vous pratiquez ce genre de commande ? partagez vos oneline