Automatiser des actions avec selenium, pyautogui et xvfb

Rédigé par Fred - - Aucun commentaire

On a parfois besoin de faire des tâches répétitives nécessitant de remplir toujours les mêmes champs, cliquer toujours aux mêmes endroits… Pour automatiser ces actions dans un navigateur, il existe selenium. On peut ainsi naviguer vers une page, récupérer des éléments via xpath, id, nom… puis agir dessus : envoyer des touches, appuyer sur des boutons, etc.

De plus, on peut lancer les scripts dans des serveurs X virtuels comme Xvfb : l’affichage n’est vas visible à l’écran et on peut ainsi utiliser crontab pour lancer les scripts même lorsque notre session est fermée.

Ça ne marche par contre pas quand il y a du des applets java, voire flash, ou pour bouger la souris. Pour cela il faut utiliser d’autres outils, comme sikuli, ou encore plus simple, pyautogui. Par contre il va falloir dire à pyautogui que l’affichage n’est pas celui de notre session, mais celui de xvfb. Pour cela, voir cette réponse sur stackoverflow qui tient en une ligne :

pyautogui._pyautogui_x11._display = Xlib.display.Display(
                os.environ['DISPLAY']
            )

Voici un exemple (pour m’en souvenir) de tout cela combiné :

import pyautogui
import os
import Xlib.display
from time import sleep

from selenium import webdriver
from pyvirtualdisplay.smartdisplay import SmartDisplay

# pour visible=1, installer xserver-xephyr
# sinon, xfvb prend le dessus
display = SmartDisplay(visible=0, size=(800, 600))
display.start()

browser = webdriver.Firefox()
browser.get('https://duckduckgo.com/')
browser.save_screenshot('nrst.png')
print browser.title

search = browser.find_element_by_id('search_form_input_homepage')
search.send_keys("auie")

# la souris se déplace dans le SmartDisplay
pyautogui._pyautogui_x11._display = Xlib.display.Display(
    os.environ['DISPLAY'])
try:
    x, y = pyautogui.locateCenterOnScreen('loupe.png')
    pyautogui.moveTo(x, y, 0.5, pyautogui.easeOutQuad)
    pyautogui.click()
except:
    print "pas trouvé de loupe!"

sleep(3)
browser.save_screenshot('auie.png')
browser.quit()

display.stop()

Emacs en vrac - 1

Rédigé par Fred - - Aucun commentaire

buffer-flip, une sorte de alt-tab pour buffer

Un mode mineur qui permet de faire passer les buffers à la manière d'un Alt+Tab : https://github.com/killdash9/buffer-flip.el

Ça utilise key-chord.

(Via http://rubikitch.com/2015/11/19/buffer-flip/)

Python profiling

Julien Danjou explique comment mesurer et analyser le temps d’exécution d’un programme python grâce à cProfile et KCacheGrind.

https://julien.danjou.info/blog/2015/guide-to-python-profiling-cprofile-concrete-case-carbonara

Prendre des notes avec PDF-tools

PDF Tools permet de voir des PDF dans un buffer, de faire des recherches, suivre un lien, mettre des annotations, et plein d’autres choses. Matt Price en parle dans son blog, et montre comment exporter les annotations pour org-mode.

Via http://irreal.org/blog/?p=4727

Changer de fenêtres, de façon visuelle

Une alternative à ace-jump, pour passer d’une fenêtre à l’autre quand on fait un C-x o : switch-window

Changer les caractères utilisés pour l’ellipse par org-mode

Artur Malabarba explique que le ... à la fin des headlines est personnalisable grâce à la variable org-ellipsis. J'ai donc changé ... par

http://endlessparentheses.com/changing-the-org-mode-ellipsis.html

autotetris-mode

Emacs permet de jouer à tetris avec M-x tetris. autotetris-mode permet de faire jouer une IA.

Indiquer la fin du buffer

La variable toggle-indicate-empty-lines permet de mettre dans la marge un symbole pour indiquer la fin du fichier. Voir aussi Fringe-Bitmaps (emacs lisp manual)

Faire des GIFs à partir de vidéos en python

Rédigé par Fred - - Aucun commentaire

Pour cela, Zulko utilise MoviePy (github) — en même temps, c’est de lui :þ. Il montre comment faire convertir des bouts de vidéos, recadrer, figer une partie de l’image, ajouter du texte… Tontof en avait déjà subrepticement parlé ; il va falloir que je regarde ça de plus près. http://zulko.github.io/blog/2014/01/23/making-animated-gifs-from-video-files-with-python/

Besoin de se dégourdir les doigts ?

Rédigé par Fred - - 3 commentaires

Parfois on a (j’ai) envie de coder (ou faire coder des étudiants) et on ne sait pas quoi faire — ou alors on veut s’entrainer, tester de nouvelles choses. Voici une liste non-exhaustive de sites web — non testés pour la plupart — qui proposent des exercices pour apprendre à programmer, des défis pour faire s’affronter des programmes, voire pour gagner de l’argent (mais ce n’est pas le sujet).

Lire la suite de Besoin de se dégourdir les doigts ?

Python Module of the Week

Rédigé par Fred - - Aucun commentaire

Note pour moi-même.

Les modules des « module python de la semaine » : https://pymotw.com/2/contents.html

Par ordre alphabétique : https://pymotw.com/2/py-modindex.html

Pour info, pymotw est/était la présentation par Doug Hellmann d’un module python avec des exemples de codes. Les sources sont disponibles sur bitbucket.

Pour python 3 : https://pymotw.com/3/

Récupérer les images d’une galerie en python

Rédigé par Fred - - Aucun commentaire

Quand je veux récupérer plusieurs pages, je le fais souvent avec wget. L’utilisation des options --load-cookies, --save-cookies et --keep-session-cookies avec --post-data étant plus que pratique. Pour parser, ensuite, c’est souvent pénible, même si awk est là pour aider.

man wget donne :

# Log in to the server.  This can be done only once.
 wget --save-cookies cookies.txt \
      --post-data 'user=foo&password=bar' \
      http://server.com/auth.php

 # Now grab the page or pages we care about.
 wget --load-cookies cookies.txt \
      -p http://server.com/interesting/article.php

Pour parser, j’aime bien python ; je trouve ça plus lisible. Par contre, ce que j’utilisais jusqu’à présent pour me logguer sur une page était moins glop :

import urllib, urllib2, cookielib

username = 'foo'
password = 'bar'

cj = cookielib.CookieJar()
handle = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
login_data = urllib.urlencode({'username' : username, 'pwd' : password})
handle.open('http://www.example.com/login.php', login_data)
res = handle.open('http://www.example.com/my_account.php')
print res.read()

Mais ça, c’était avant. Depuis, j’ai découvert Requests. Pour faire un POST, c’est aussi simple que :

import requests

url= 'http://www.example.com/login.php'
login_data = {username = 'myuser', password = 'mypassword'}

req = requests.post(url, login_data)
page = req.content

Si on a besoin de gérer les cookies, on peut passer par une Session :

import requests

url= 'http://www.example.com'
login_data = {username = 'myuser', password = 'mypassword'}

s = requests.Session()
req = s.post(url + '/login.php', login_data)
req = s.get(url + '/my_account.php')

C’est quand même plus lisible, non ?

En fait, récemment, je voulais parcourir les images de la galerie d’un site. Mais cette galerie contenait 10 images seulement par page, pour 40 pages. J’ai donc fait un script pour mettre toutes les images sur une seule page.

Les images sont encapsulées par une balise a class="foo" et donc j’utilise BeautifulSoup pour toutes les lister (soup.findAll("a","foo")).

Comme j’ai « besoin » de consulter les images plusieurs fois, j’ai préféré enregistrer les images en local plutôt que de laisser un lien sur le site. Pour ça j’ai utilisé stream=True de la méthode .get (cf ce lien sur SO).

J’ai pas fait très propre puisque j’affiche la page sur stdout que je pipe avec tee pour mettre dans un fichier. Mais au moins, je vois si ça marche :þ

# -*- coding: utf-8 -*-
from BeautifulSoup import BeautifulSoup
from requests import session

login_data = { 'login': 'fredtantini', 
               'password': 'toto1234',
               'action': 1 }

urlToVisit = 'http://www.example.com'

#on ouvre une session
with session() as s:
    #on se connecte
    req = s.post(urlToVisit + '/login.php', data=login_data)
    print "<html><body>"
    #comme je sais qu’il y a 40 pages
    for nPage in xrange(1,41):
        #on récupère la page
        request = s.get(urlToVisit + '/some_page.php?p='+str(nPage))
        #que l’on passe à BS
        soup = BeautifulSoup(request.text)    
        print "<h1> Page - ",nPage,"</h1>"
        #Pour tous les liens
        for i in soup.findAll("a","foo"):
            #on récupère l’image
            r = s.get(urlToVisit + '/' + i.img['src'], stream=True)
            #on la télécharge par parties (cf lien SO plus haut)
            if r.status_code == 200:
                with open(i.img['alt'] + ".jpg", 'wb') as f:
                    for chunk in r.iter_content():
                        f.write(chunk)
            print str(i).replace('./images/', './')

print "</body></html>"
Fil RSS des articles de ce mot clé