Présentation

Pouvoir constituer une base d’apprentissage pour un algorithme de reconnaissance d’images n’est pas toujours évident. En effet, pour pouvoir entraîner un CNN (Convolutional Neural Network), un réseau de neurones spécialisé dans ce type de traitement, il faut compter plusieurs (dizaines) de milliers d’images. Ces images, en outre, doivent déjà être classées, c’est à dire savoir de quel type d’image il s’agit (on parle d’apprentissage supervisé), et servir d’exemple.

Ce tutoriel propose une méthode en Python pour extraire de Google Image (on parle de scraping qui signifie « grattage ») tout ce dont vous aurez besoin, par exemple, 1000 images correspondant à la recherche « chat ».

Remarque sur le tutoriel

Pour que ce tutoriel ne s’éparpille pas inutilement, on a choisi de se concentrer uniquement sur les lignes de codes intéressantes. On vous conseille donc de prendre le temps de tout lire, pour acquérir les briques élémentaires et essayer d’écrire votre propre script ensuite. Dans tous les cas, vous pourrez retrouver le code complet sur GitHub – qu’on utilise tous les jours chez Pensée Artificielle – dans le dernier paragraphe de cet article 🙂

Préparation et dépendances

Notre script va travailler ainsi : grâce à Selenium, un Framework de test, on va pouvoir lancer de manière automatisée Firefox (ou un autre navigateur), faire notre recherche Google, et télécharger la totalité des images indiquées.

Pour cela, on aura besoin de …

Pour installer Selenium, il ne s’agit pas d’un « logiciel » mais d’un package Python. Il faut donc ouvrir une commande Windows et saisir :

pip install selenium

(pip est un gestionnaire de package qui s’installe en même temps que Python 3)

Notre script Google Image Scraping

Configuration

Commençons par définir nos variables

# Configuration
download_path = "dataset/"
# Images
words_to_search = ['robot','Pensée Artificielle']
nb_to_download = [75,10]
first_image_position = [25,0]
  1. download_path est le sous-dossier du dossier courant dans lequel seront stockées les images (elles seront dans des dossiers du même nom que les mots recherchés, donc ici /dataset/robot/ et /dataset/pensee-artificielle/)
  2. words_to_search contient une liste de mots clés à chercher (indépendamment les uns des autres) pour en télécharger les images
  3. nb_to_download indique, par mot clé, le nombre d’images à télécharger (ici 75 « robot » et 10 « Pensée Artificielle)
  4. first_image_position précise à partir de la combien-t-ième image il faut commencer à télécharger. Pour « robot », on téléchargera donc les images 25 à 100 de Google Image.

Connexion à Google Image

Maintenant que tout est prêt, on va faire des boucles sur nos listes pour traiter les mots clés un à un.
Dans un premier temps, on positionne une variable supplémentaire number_of_scrolls. Il faut savoir que Google Image charge exactement 400 images avant de proposer le bouton « Show more results », et qu’il faut un peu scroller avant de l’avoir. Pour que notre script fonctionne bien, on va devoir commencer par scroller les résultats de recherche suffisamment de fois pour avoir toutes les images à télécharger.

# Number_of_scrolls * 400 images will be opened in the browser
number_of_scrolls = int((number + first_position)/ 400 + 1)

De plus, il va falloir créer les répertoires où seront stockées les images téléchargées afin de pouvoir mieux les répartir en jeux de données pour nos algorithmes d’apprentissage ensuite.

# Create directories to save images
if not os.path.exists(download_path + text.replace(" ", "_")):
    os.makedirs(download_path + text.replace(" ", "_"))

Maintenant que tout est prêt, on peut se connecter à Google Image.
Tout d’abord, on définit le driver Selenium. Il s’agit d’une instanciation d’un navigateur web qui va être contrôlé par notre script. On va pouvoir interagir avec (cliquer sur des boutons, trouver des éléments dans la page, etc…) facilement.

# Connect to Google Image
url = "https://www.google.co.in/search?q="+text+"&source=lnms&tbm=isch"
driver = webdriver.Firefox()
driver.get(url)
headers = {}
headers['User-Agent'] = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"
extensions = {"jpg", "jpeg", "png", "gif"}

Remarque : si vous souhaitez utiliser un autre navigateur que Firefox, il faudra faire quelques recherches sur Internet. Par exemple pour Chrome, on apprend de Google qu’il faut mettre (attention à ne pas oublier de télécharger le webdriver et à le mettre dans le répertoire)

driver = webdriver.Chrome()

Ensuite on scroll automatiquement la page pour charger toutes les images de la recherche. Pour cela, on utilise un script inclus dans Selenium (scrollBy), ainsi que la fonctionnalité « find_element_by_xpath » qui permet de trouver n’importe quel élément.
Astuce : pour avoir le XPATH d’un élément, vous pouvez utiliser Google Chrome. Faites clic droit sur l’élément qui vous intéresse (un bouton par exemple) puis « Inspecter ». Dans la console développeur qui s’ouvre, la ligne de l’élément désiré est surlignée. Faites clic droit puis « Copy -> Copy Xpath ».

# Prepare Google Page
for _ in range(number_of_scrolls):
    for __ in range(10):
        # Multiple scrolls needed to show all 400 images
        driver.execute_script("window.scrollBy(0, 1000000)")
        time.sleep(0.2)
    # to load next 400 images
    time.sleep(2.5)
    try:
        driver.find_element_by_xpath("//input[@value='Show more results']").click()
        time.sleep(2.5)
    except Exception as e:
        print("Less images found:"+ str(e))
        break

Les time.sleep permettent de laisser au navigateur le temps de charger la suite des images (pour ne pas aller trop vite).

Téléchargement des images

Le téléchargement des images se fait en deux temps. Tout d’abord, pour chaque image, on va devoir récupérer l’URL de la vraie image (et non de la miniature), ainsi que le type d’image. Dans un second temps, on ouvrira cette URL et on la téléchargera.

Récupération de l’URL de l’image

Comme tout à l’heure, on ouvre chaque image par son XPATH : toutes les images ont pour classe rg_meta.

Il faut ensuite savoir que Google attache à chaque image un bout de JSON (du texte formaté en balises, un peu comme du HTML) qui décrit l’image. On récupère donc le JSON de chaque image et on va chercher le contenu des deux balises suivantes :

  1. ou = l’URL de l’image dont on regarde le JSON
  2. ity = le type d’image (jpg, png, etc…)
# Process (download) images
imges = driver.find_elements_by_xpath('//div[contains(@class,"rg_meta")]')

img_url = json.loads(img.get_attribute('innerHTML'))["ou"]
img_type = json.loads(img.get_attribute('innerHTML'))["ity"]

Dernière étape de notre périple : on va ouvrir chaque URL d’image et télécharger ce qui nous est renvoyé.
Pour cela, on dispose de urllib, une librairie incluse dans Python et axée sur le web. Grâce à Request, on peut définir une requête HTTP à exécuter ensuite, via urlopen. La méthode read permet de lire le contenu de la réponse, qui est une image binaire renvoyée aimablement par les sites interrogés.
Il ne reste plus qu’à écrire sur notre disque, en binaire, l’image obtenue (avec Python on a les méthodes open et write). A noter que le flux qu’on enregistre est en binaire, donc il faut bien créer son fichier local en binaire pour que ça fonctionne.

# Download image and save it
req = urllib.request.Request(img_url, headers=headers)
raw_img = urllib.request.urlopen(req).read()
f = open(download_path+text.replace(" ", "_")+"/"+str(img_skip+downloaded_img_count)+"."+img_type, "wb")
f.write(raw_img)
f.close

Pour aller plus loin

Beaucoup de scripts de ce type existent. Par exemple, on a celui de Genokan, de CurlPic, de FileCat, ou encore via le Google API. Chaque approche est différente et présente de nombreux avantages et inconvénients.

La version ici proposée est assez simple et intuitive, et repose sur Selenium. De plus, on peut facilement contrôler ce qu’il se passe donc on l’apprécie particulièrement.

Code complet

Retrouvez le code complet du projet sur le GitHub de Pensée Artificielle : www.github.com/penseeartificielle

 

Crédit de l’image de couverture : Steve GibsonCC0 1.0