IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Crawler sous Scrapy


Sujet :

Python

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2015
    Messages
    22
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2015
    Messages : 22
    Points : 8
    Points
    8
    Par défaut Crawler sous Scrapy
    Bonsoir à tous !

    Tout d'abord je tiens à préciser que c'est la première fois que je m'essaye au développement sous Python (via scrapy) mais je suis néanmoins familiarisé avec les concepts orientés objets, mais bien plus à l'aise en C.

    La description du projet dans sa globalité n'est pas très importante au regard de la simplicité de ma question:

    - je souhaite déclarer deux tableaux, un contenant des chaînes de caractères et un contenant de simples nombres.
    -une boucle va venir, par exemple, parcourir toutes les positions de mon tableau contenant mes nombres pour venir me les remplacer dans ce code ci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    import scrapy
    
    
    
    tab1=[1,2,3]
    tab2=['hello','world']
    
    class QuotesSpider(scrapy.Spider):
        name = "histo"
    
        def start_requests(self):
             for i in tab1:
            urls = [
                'https://min-api.cryptocompare.com/data/histohour?fsym=ETH&tsym=BTC&limit=60&aggregate=1&toTs=1452680400&extraParams=your_app_name'
               
            ]
            for url in urls:
                yield scrapy.Request(url=url, callback=self.parse)
    
        def parse(self, response):
            page = response.url.split("/")[-2]
            filename = 'histo-%s.html' % page
            with open(filename, 'wb') as f:
                f.write(response.body)
            self.log('Saved file %s' % filename)
    La partie importante qui me pose problème ici est soulignée en gras, je souhaite que "60" soit remplacé par les différentes valeurs présentes dans mon tab1, en langage C j'aurai écris quelque chose comme ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for i=0 to 3
     {
    
            urls = [
                'https://min-api.cryptocompare.com/data/histohour?fsym=ETH&tsym=BTC&limit='%d'&aggregate=1&toTs=1452680400&extraParams=your_app_name',tab1[i]
    Malheureusement en cherchant sur des forums je ne trouve rien, bien qu'étant conscient que je ne trouve pas ma réponse parce que la formulation de ma question est que bien trop imprécise.

    J'espère avoir été assez clair, en vous remerciant par avance et en m'excusant des éventuels affronts que j'aurai pu écrire =)

  2. #2
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Salut,

    C'est plus ou moins similaire en Python
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    >>> indices = [1, 2, 3]
    >>> for i in indices:
    ...     print('indice=%s' % i)
    ... 
    indice=1
    indice=2
    indice=3
    le '%s' peut différer selon le formatage désiré, voir ici:
    https://docs.python.org/3/library/st...ing-formatting


    Edit: je pense que ta fonction génératrice devrait plutôt être ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        def start_requests(self, tab1):
             for i in tab1:
                 urls = 'https://min-api.cryptocompare.com/data/histohour?fsym=ETH&tsym=BTC&limit=%d&aggregate=1&toTs=1452680400&extraParams=your_app_name' % i
                 yield scrapy.Request(url=url, callback=self.parse)
    Note l'argument 'tab1' indispensable parce que inconnu dans l'espace de nom de la fonction.

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2015
    Messages
    22
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2015
    Messages : 22
    Points : 8
    Points
    8
    Par défaut
    Bonjour VinsS et merci pour la rapidité de ta réponse !!!

    Enfait j'avais déjà plus ou moins testé de mettre en argument mon tab1 dans la fonction start_requets, mais visiblement en cherchant un peu, j'ai cru comprendre que pour l'instruction start_request il ne pouvait que posséder exclusivement l'argument self et de fait me voilà bien embêté !!

    Voila mon code adapté avec ton explication :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    import scrapy
     
     
    class QuotesSpider(scrapy.Spider):
        name = "histo"
        tab1=[1000,10]
     
        def start_requests(self, tab1):
            for i in tab1:
                urls = 'https://min-api.cryptocompare.com/data/histohour?fsym=ETH&tsym=BTC&limit=%d&aggregate=1&toTs=1452680400&extraParams=your_app_name' % i
                yield scrapy.Request(url=url, callback=self.parse)
     
     
            def parse(self, response):
                page = response.url.split("/")[-2]
                filename = 'histo-%s.html' % page
                with open(filename, 'wb') as f:
                    f.write(response.body)
                self.log('Saved file %s' % filename)
    L'erreur affichée est de type start_requests() takes exactly 2 arguments (1 given), j'ai également essayé pour résoudre ce problème de déclarer mon tab1 ailleurs dans la fonction mais rien n'y fait

    Si tu as une idée pour contourner le problème je suis preneur =)

  4. #4
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Si tab1 est attribut de classe alors tu peux le supprimer des arguments et utiliser:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
            for i in self.tab1:
    Est-ce normal que la fonction parse() soit plus indentée que la précédente ?

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2015
    Messages
    22
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2015
    Messages : 22
    Points : 8
    Points
    8
    Par défaut
    On touche du doigt l'objectif final!!

    Concernant ta question sur l'indentation, ma fonction parse l'est en effet plus que la précédente, mais ce n'est absolument pas une volonté de ma part, c'est vrai qu'en revanche l'indentation semble vraiment importante et problématique sous python, chose que je n'avais jamais expérimenté avant ! est-ce un problème selon toi dans notre cas précis ?

    Maintenant j'ai fait apparaître un autre problème: avec cette boucle, je souhaite mettre dans "urls" les deux urls que ma boucle for va venir créer (une url dans laquelle à correctement été placé le chiffre 1000 et la deuxieme dans laquelle à correctement été placé le chiffre 10)

    Ainsi, je souhaite qu'il m'écrive dans DEUX fichiers différents les informations recueillies sur les deux url différentes (celles crées par ma boucle for) comme s'en suit

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
     
    import scrapy
     
     
    class QuotesSpider(scrapy.Spider):
        name = "histo"
        tab1 = [1000,10]
     
        def start_requests(self):
            for i in self.tab1:
                urls = 'https://min-api.cryptocompare.com/data/histohour?fsym=ETH&tsym=BTC&limit=%s&aggregate=1&toTs=1452680400&extraParams=your_app_name' % i
     
            for url in urls:
                yield scrapy.Request(url=url, callback=self.parse)
     
        def parse(self, response):
            page = response.url.split("/")[-2]
            filename = 'histo-%s.html' % page
            with open(filename, 'wb') as f:
                f.write(response.body)
            self.log('Saved file %s' % filename)
    Cependant rien de spécial ne se passe avec ce code, les page html ne se crée pas. Le seul moyen d'avoir un résultat (création d'une page html avec le contenu d'une des deux url) est de remplacer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    yield scrapy.Request(url=url, callback=self.parse)
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    yield scrapy.Request(url=urls, callback=self.parse)
    et là encore je ne vais avoir que la création de la page html dont les informations viennent de la deuxième url, j'ai comme l'impression qu'au moment de l'écriture, la page html correspondant à ma première url à bien été crée mais écrasée par la création de la deuxième.

    J'ai essayé de conditionner l'écriture par une boucle, mais je pense être sur la mauvaise voie (?)

  6. #6
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Comme indiqué dans mon post #2, ta fonction génératrice devrait être comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        def start_requests(self):
            for i in self.tab1:
                url = 'https://min-api.cryptocompare.com/data/histohour?fsym=ETH&tsym=BTC&limit=%s&aggregate=1&toTs=1452680400&extraParams=your_app_name' % i
                yield scrapy.Request(url=url, callback=self.parse)
    ce que tu fais est une itération sur la chaîne elle-même (la dernière créée)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    >>> for i in [1, 2]:
    ...     idx = "indice=%s" % i
    ... 
    >>> for i in idx:
    ...     print(i)
    ... 
    i
    n
    d
    i
    c
    e
    =
    2
    >>>

  7. #7
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2017
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2017
    Messages : 2
    Points : 2
    Points
    2
    Par défaut
    Bonjour à toi Pinhut et bonjour à toi VinsS,

    J'essaye de développer un crawler pour raspberry pi à partir des tutoriaux de scrappy mais je rencontre à peu près le même problème que Pinhut.

    En reprenant son code suivant modifié selon les conseils de VinsS (ma structure est très similaire):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class QuotesSpider(scrapy.Spider):
        name = "histo"
        tab1 = [1000,10]
     
        def start_requests(self):
            for i in self.tab1:
                urls = 'https://min-api.cryptocompare.com/data/histohour?fsym=ETH&tsym=BTC&limit=%s&aggregate=1&toTs=1452680400&extraParams=your_app_name' % i
            yield scrapy.Request(url=urls, callback=self.parse)
     
        def parse(self, response):
            page = response.url.split("/")[-2]
            filename = 'histo-%s.html' % page
            with open(filename, 'a') as f:
                f.write(response.body)
            self.log('Saved file %s' % filename)
    J'obtiens les résultats extraits dans un fichier, mais seules les données de la seconde URL (avec la valeur 10 donc) apparaissent dans mon fichier. Apparemment, ce serait parce qu'une seule URL est scrappée, celle prenant la valeur de 10. ( En "2ème" position donc dans le tableau).

    Nom : VinsS.JPG
Affichages : 475
Taille : 66,5 Ko

    En utilisant le code suivant proposé par Pinhut:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        def start_requests(self):
            for i in self.tab1:
                urls = 'https://min-api.cryptocompare.com/data/histohour?fsym=ETH&tsym=BTC&limit=%s&aggregate=1&toTs=1452680400&extraParams=your_app_name' % i
     
            for url in urls:       
                yield scrapy.Request(url=urls, callback=self.parse)
    Python identifie bien qu'il y a deux URLS qui sont générées, mais cette fois-ci encore, seule l'URL prenant la valeur 10 est prise en compte, et dupliquée, puis Scrappy supprime la première URL afin d'éviter les dupplicatas et renvoie l'info. Je pense que le problème que Pinhut et moi-même rencontrons est à ce niveau là. La capture d'écran ci-dessous montre bien le problème:

    Nom : pinhut.JPG
Affichages : 452
Taille : 79,4 Ko

    Cela signifie t'il que la méthode du tableau pour l'insertion des paramêtres n'est pas viable? Doit-on utiliser d'autres fonctions afin d'appeler les données dans le tableau?

    Merci d'avance à tous les deux!

    CM.

  8. #8
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Salut,

    Le yield doit être indenté au même niveau que la ligne qui le précède. Sinon la boucle sur les deux urls ne sert à rien.

  9. #9
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2017
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2017
    Messages : 2
    Points : 2
    Points
    2
    Par défaut
    Bonsoir VinsS,

    Tu es vraiment le sauveur sur ces problèmes ahah merci infiniment! Je m'y ferais pas non plus à cette histoire d'indentation.

    J'ai réussi à progresser depuis la dernière fois (ouf) et ai réussi a maîtriser un peu mieux la fonction url.split pour qu'elle fasse ce que je veux faire..
    Néanmoins mon problème se situe à nouveau dans les start_request..
    En reprenant l'exemple de pinhut:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class QuotesSpider(scrapy.Spider):
        name = "histo"
        tab1 = [1000,10]
     
        def start_requests(self):
            for i in self.tab1:
                urls = 'https://min-api.cryptocompare.com/data/histohour?fsym=ETH&tsym=BTC&limit=%s&aggregate=1&toTs=1452680400&extraParams=your_app_name' % i
                yield scrapy.Request(url=urls, callback=self.parse)
    Ici Pinhut n'a qu'une seule "tab1", mon souhait serait de modifier plusieurs urls de manière séquentielle...
    Disons:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class QuotesSpider(scrapy.Spider):
        name = "histo"
        tab1 = [1000,10]
        tab2 = [3,5]
     
        def start_requests(self):
            for i, j in self.tab1, self.tab2:
                urls = 'https://min-api.cryptocompare.com/data/histohour?fsym=ETH&tsym=BTC&limit=%s&aggregate=%s&toTs=1452680400&extraParams=your_app_name' % i % j
                yield scrapy.Request(url=urls, callback=self.parse)
    J'ai essayé cette solution (qui ne fonctionne pas), un peu comme on pourrait le faire avec du C.
    En parcourant le site je suis tombé sur la fonction Zip, mais de ce que j'en ai compris, elle ne permettrait d'utiliser que des chaines de même nombre de caractères, et je ne sais pas si elle pourrait efficacement résoudre mon problème...

    Théoriquement, je souhaiterais que la boucle aille chercher dans l'ordre les valeurs sur l'url en :
    1. 1000/ 3
    2. 1000/ 5
    3. 10/ 3
    4. 10/ 5

    A terme il faudrait que je puisse définir chacun des paramètres de l'URL. J'ai également croisé la bibliothèque URLLIB mais qui n'a l'air d'être compatible qu'avec Python >3.4, et même dans ce cas je ne suis pas sur de pouvoir modifié les paramètres individuellement.

    J'espère avoir été compréhensible, et merci encore milles fois pour ton aide!

  10. #10
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Citation Envoyé par chimat Voir le message
    En parcourant le site je suis tombé sur la fonction Zip, mais de ce que j'en ai compris, elle ne permettrait d'utiliser que des chaines de même nombre de caractères, et je ne sais pas si elle pourrait efficacement résoudre mon problème...
    tab1 et tab2 sont des listes pas des chaînes de caractères.

    Si je comprend bien ce que tu veux faire zip est bien la fonction ad hoc. for i, j in zip(tab1, tab2)

    Edit: j'avais regardé ton code mais pas la suite.
    Si tu veux la combinaison des valeurs des listes, tu peux le faire avec une listcomprehension.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    >>> t = [1000, 10]
    >>> t1 = [3, 5]
    >>> tt = [(i, j) for i in t for j in t1]
    >>> tt
    [(1000, 3), (1000, 5), (10, 3), (10, 5)]
    et puis tu l'utilises avec for i, j in tt

Discussions similaires

  1. Problème d'installation oracle 8.1.7 sous NT
    Par Anonymous dans le forum Installation
    Réponses: 7
    Dernier message: 02/08/2002, 14h18
  2. webcam : lire sur un port usb en c/c++ ou java. sous win. ?
    Par flo007 dans le forum Choisir un environnement de développement
    Réponses: 2
    Dernier message: 24/05/2002, 23h24
  3. OmniORB : code sous Windows et Linux
    Par debug dans le forum CORBA
    Réponses: 2
    Dernier message: 30/04/2002, 17h45
  4. Je ne peux établir une connexion cliente sous Linux.
    Par Anonymous dans le forum CORBA
    Réponses: 5
    Dernier message: 16/04/2002, 15h57
  5. Réponses: 4
    Dernier message: 27/03/2002, 11h03

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo