Bien débuter un projet Python

Rédigé par jeromef


14 février 2014 Python, tutoriel aucun



Cet article est tiré (traduit en fait) de l'excellent article de Jeff Knupp
Je ne le connais pas perso mais je l'embrasse.
Vous pouvez retrouver ici.




Voici donc les étapes d'un début de projet réussi pour lui:


1. Installer et utiliser virtualenv (se servir de virtualenvwrapper cf Mettre un environnement virtuel sur MAC

2. Versionner (GIT ou autre on supposera ici GIT) --> git.init + ajouter un .gitignore (pour ignorer les fichiers Python compilés et les répertoires __pycache__ ) cf aussi Jean Paul Githubez moi ca
Pour cela, créez un fichier nommé .gitignore avec le contenu suivant:

 *. Pyc
 __pycache__

3. Ecrire un README.md (en markdown)
… on peut ajouter tout ça à GIT :
git add .gitignore README.md
git commit -m "initial commit"

4. Création d'un Squelette avec fonctions + class avec docstring
(pour l'exemple nous prenons un script dont l'objet est de créer un fichier csv contenant les meilleurs films d'extrapolation de l'année dernière (de IMDB) et les mots clés sur IMDB qui leur sont associés)
On commence donc par créer un fichier imdb.py

"""Script to gather IMDB keywords from 2013's top grossing movies."""
import sys

def main():
    """Main entry point for the script."""
    pass

if __name__ == '__main__':
    sys.exit(main())

Ensuite création des "stubs" pour les fonctions ou class dont j'aurais besoin

"""Script to gather IMDB keywords from 2013's top grossing movies."""
import sys

URL = "http://www.imdb.com/search/title?at=0&sort=boxoffice_gross_us,desc&start=1&year=2013,2013"

def main():
    """Main entry point for the script."""
    pass

def get_top_grossing_movie_links(url):
    """Return a list of tuples containing the top grossing movies of 2013 and link to their IMDB
    page."""
    pass

def get_keywords_for_movie(url):
    """Return a list of keywords associated with *movie*."""
    pass

if __name__ == '__main__':
    sys.exit(main())

Notez que la function get_keywords_for_movie (url) inclue le paramètre movie_url ce qui peut paraitre étrange à ce niveau mais part du principe que comme je ne sais pas quels arguments aura la fonction, je laisse ouvert.
Un petit commit pour ne rien perdre
On commence par définir un "main" qui permet une communication transverse pour les fonctions du projet dans le imdb.py :

import csv

def main():
    """Main entry point for the script."""
    movies = get_top_grossing_movie_links(URL)
    with open('output.csv', 'w') as output:
        csvwriter = csv.writer(output)
        for title, url in movies:
            keywords = get_keywords_for_movie(
                'http://www.imdb.com{}keywords/'.format(url))
            csvwriter.writerow([title, keywords])

On peut utiliser les 2 fonctions sans les avoir codées et main fait donc ce qu'on avait prévu soit : Récupère les tops films et génère un fichier csv avec leurs mots-clés.
Maintenant, tout ce qui reste est la mise en œuvre des fonctions manquantes.
Fait intéressant, même si nous savons get_keywords_for_movie seront appelés après get_top_grossing_movie_links , nous pouvons les mettre en œuvre dans l'ordre que nous aimons (ce qui ne serait pas le cas si nous avions choisi de développer directement). Ainsi nous pouvons mettre en oeuvre et tester (!) ces fonctions en démontrant qu'elles sont peut couplées.

Définissons get_keywords_for_movie tout d'abord:

def get_keywords_for_movie(url):
    """Return a list of keywords associated with *movie*."""
    keywords = []
    response = requests.get(url)
    soup = BeautifulSoup(response.text)
    tables = soup.find_all('table', class_='dataTable')
    table = tables[0]
    return [td.text for tr in table.find_all('tr') for td in tr.find_all('td')]

Request et beautifulsoup font leur apparition, il est donc temps de définir les requirements du projet via un
pip freeze requirements.txt
Passons main tenant à get_top_grossing_movie_links:

def get_top_grossing_movie_links(url):
    """Return a list of tuples containing the top grossing movies of 2013 and link to their IMDB
    page."""
    response = requests.get(url)
    movies_list = []
    for each_url in BeautifulSoup(response.text).select('.title a[href*="title"]'):
        movie_title = each_url.text 
        if movie_title != 'X':
            movies_list.append((movie_title, each_url['href']))
    return movies_list

Le if movie_title != 'X' est en réponse au select peut être un peu trop permissif. Plutôt que d'essayer de faire juste, je filtre tout simplement les liens qui sont faux avec le if.
Voici le contenu de imdb.py final complet :


 "" "Script de recueillir IMDB mots-clés à partir des films Top des Ventes de 2013." ""
 système d'importation
 demandes d'importation
 de bs4 importation BeautifulSoup
 csv à l'importation

 URL = "http://www.imdb.com/search/title?at=0&sort=boxoffice_gross_us, desc & start = 1 & annee = 2013,2013"

 get_top_grossing_movie_links def (url):
     "" "Retourne une liste de tuples contenant les films d'extrapolation haut de 2013 et à leur lien IMDB
 page. "" "
     réponse = demandes. get (url)
     movies_list = []
     . pour each_url dans BeautifulSoup (. réponse texte), sélectionnez ('title un [href * = "title"].):
         MOVIE_TITLE = each_url. texte 
         si MOVIE_TITLE = 'X':
             movies_list. append ((MOVIE_TITLE, each_url ['href']))
     retourner movies_list



 def get_keywords_for_movie (url):
     "" "Retourne une liste de mots-clés associés à * film *." ""
     Mots-clés = []
     réponse = demandes. get (url)
     soupe = BeautifulSoup (réponse. texte)
     tables = soupe. find_all ('table', 'dataTable' = class_)
     table = tables [0]
     retourner [td. texte tr dans le tableau. find_all ('tr') pour td en tr. find_all («TD»)]


 def main ():
     "" "Le point principal d'entrée pour le script." ""
     films = get_top_grossing_movie_links (URL)
     avec open ('output.csv', 'w') en sortie:
         csvwriter = csv. écrivain (sortie)
         pour le titre, url dans les films:
             keywords = get_keywords_for_movie ('http://www.imdb.com {} mots clés / ». Format (url))
             csvwriter. writerow ([titre, mots-clés])


 if __ name__ == '__main__':
     système. sortie (main ())


Pour compléter, je pense qu'il faudrait se pencher sur (ou ajouter à cette méthode) l'intégration de :

- tests unitaires (ne me demandez pas je ne sais pas encore ce que c'est)
- documentation automatique (cf. mon article sur sphynx )

Partager cet article sur :



la #1 mercredi 19 février 2014 @ 18:01

Excellent article parlant du sujet. Ce site internet est également sympathique à découvrir


Jerome #2 vendredi 21 février 2014 @ 00:55

@la : Merci content que cela vous plaise et en esperant que vos projets python ou autre en subissent les retombees positives. Je vais sous peu debuter la mise en ligne de l avancee du projet ApiClock, ce sera l occasion de confronter avec la mise en pratique !


Les commentaires sont fermés.