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

Réseau/Web Python Discussion :

Possibilité de scrapping ? [Python 3.X]


Sujet :

Réseau/Web Python

  1. #1
    Membre habitué
    Homme Profil pro
    Master Data Manager
    Inscrit en
    Février 2017
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Master Data Manager
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2017
    Messages : 113
    Points : 148
    Points
    148
    Par défaut Possibilité de scrapping ?
    Bonjour à tous.

    Contexte :

    J'ai régulièrement besoin de trouver des "nouveau" outils coupants puis les codifiées dans un ERP. Cela prend pas mal de temps, comme c'est fais à la main il y a risque d'erreur et je ne parle pas de la dégradation de ma santé mentale au cours de ce genre d'activité

    Voici plus en détail la procédure faite a la mano:

    - Je cherche par exemple "DSKM 2.5" sur le site https://www.toolsunited.com/App/EN/T...e,[],null]
    - Sur les premières lignes de résultat, je clique sur détail afin de trouver l'outil qui a les caractéristiques que je cherche.
    Nom : 2023-01-29 15_02_39-Window.png
Affichages : 228
Taille : 21,7 Ko

    - Une fois trouvé je collecte les caractéristiques.
    Nom : 2023-01-29 15_03_23-Window.png
Affichages : 233
Taille : 76,5 Ko


    L'idée est de faire un script qui va faire la recherche, collecter les premières lignes de résultat avec les détails des caractéristiques de chaque outil puis, dans un deuxième temps je sélectionnerai l'outil adéquat et cela me produira un fichier que je pourrai injecter dans l'erp sans risque d'erreur de recopie.

    Après quelques recherches et il semble que Python + Selenium soit adapté ce que je cherche à faire.

    J'ai donc fait des essais, mais je n'arrive pas à grand-chose.

    Je n'arrive pas à cliquer sur l'icône détail Nom : 2023-01-29 15_05_57-Window.png
Affichages : 318
Taille : 276 octets d'une ligne pour ouvrir la fenêtre "pop-up" avec les détails de l'outil... Bref, je galère pas mal du coup si quelqu'un pouvait me montrer comment collecter les détails sur une des lignes, cela m'aiderait pas mal à avancer.

    EDIT: Désolé, une seule des images s'affiche alors que j'en ai mis trois pour illustrer mon propos. Je ne vois pas pourquoi…
    Nom : TOOLSUNITED_800.gif
Affichages : 221
Taille : 1,91 Mo

  2. #2
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 873
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 873
    Points : 3 717
    Points
    3 717
    Par défaut
    Citation Envoyé par Puppet_Master Voir le message
    Je n'arrive pas à cliquer sur l'icône détail Nom : 2023-01-29 15_05_57-Window.png
Affichages : 318
Taille : 276 octets d'une ligne pour ouvrir la fenêtre "pop-up" avec les détails de l'outil... Bref, je galère pas mal du coup si quelqu'un pouvait me montrer comment collecter les détails sur une des lignes, cela m'aiderait pas mal à avancer.
    Ben commençons par le clique...

    Voici un exemple de code qui récupère tous les boutons puis demande sur lequel tu veux cliquer...

    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
     
    import time
    from selenium import webdriver
     
    # driver = webdriver.Chrome()
    driver = webdriver.Firefox()
    driver.get("https://www.toolsunited.com/App/EN/TuMenu/ShowResult?search=[[%22Volltext%C2%A7dskm%202.5%22],%22Root%22,0,100,%22default%22,true,[],null]")
     
    time.sleep(5)
     
    details_btn =  driver.find_elements_by_class_name("borderlessBtnDiv")
     
    print(f"Il y a {len(details_btn)} boutons 'détails'...")
    num = int(input(f"Sur quel bouton veux-tu cliquer ? (Choisis un nombre entre 1 et {len(details_btn)}): "))
    details_btn[num-1].click()
    Dans cet exemple il y a 100 boutons mais apparemment on ne peut cliquer que sur ceux qui sont visibles...

    Pour les autres il faut faire défiler la scrollbar...

    Mais là tu as un exemple pour commencer...

  3. #3
    Membre habitué
    Homme Profil pro
    Master Data Manager
    Inscrit en
    Février 2017
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Master Data Manager
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2017
    Messages : 113
    Points : 148
    Points
    148
    Par défaut
    Merci pour votre réponse @Beginner.

    J'ai un peu avancé…

    Quand j'essaie d'utiliser la méthode "find_elements_by_class_name("borderlessBtnDiv")", python me signale que la méthode n'existe pas sur l'objet :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        td_list = driver.find_elements_by_class_name("borderlessBtnDiv")
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    AttributeError: 'WebDriver' object has no attribute 'find_elements_by_class_name'
    Par contre, avec la méthode "find_elements(By.CSS_SELECTOR, "#gridForResultList tr td .borderlessBtnDiv")" cela fonctionne.

    Voici les bouts de code qui fonctionne. Ce n'est pas propre mais ce n'est que du test pour voir la faisabilité…


    Code python : 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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    from selenium import webdriver
    #from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.common.by import By
    #from selenium.webdriver.support.wait import WebDriverWait  
    import time
     
     
    driver = webdriver.Firefox()
    driver.implicitly_wait(30)
    driver.maximize_window()
     
     
    driver.get("https://www.toolsunited.com/App/EN/TuMenu/ShowResult?search=[[],%22Root%22,0,100,%22default%22,true,[],null]")
     
    # collecte la liste des boutons details
    #td_list = WebDriverWait(driver, 4).until(lambda driver: driver.find_elements(By.CSS_SELECTOR, "#gridForResultList tr td .borderlessBtnDiv"))
    #td_list = driver.find_elements_by_class_name("borderlessBtnDiv")
    td_list = driver.find_elements(By.CSS_SELECTOR, "#gridForResultList tr td .borderlessBtnDiv")
     
    #print(td_list)
     
    count = 0
    for td in td_list:
        count += 1
        td.click()
     
        # collecte les lignes
        lst_data = driver.find_elements(By.CSS_SELECTOR, "div .k-grid.k-widget.k-grid-display-block table tbody tr")
     
        # lecture des lignes
        with open("t"+str(count)+".csv", 'w') as f:
            for row in lst_data:
                columns = row.find_elements(By.TAG_NAME, "td")
                l = []
                for c in range(len(columns)):
                    l.append(columns[c].text)
                f.write(';'.join(l) + "\n")
     
     
        time.sleep(2)
        ferme = driver.find_element(By.XPATH, "//html//body//div[5]//div[1]//div//a[2]")
        print("ferme >>> ")
        ferme.click()
     
    driver.quit()


    Ça me récupère des choses non voulues et comme vous le mentionniez, impossible d'ouvrir un item non visible.

    A voir comment on peut scroller un peu à chaque item et mieux cibler le tableau des détails.

    Si vous avez des pistes je suis tout ouïe

  4. #4
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 873
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 873
    Points : 3 717
    Points
    3 717
    Par défaut
    Citation Envoyé par Puppet_Master Voir le message
    Quand j'essaie d'utiliser la méthode "find_elements_by_class_name("borderlessBtnDiv")", python me signale que la méthode n'existe pas sur l'objet :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
        td_list = driver.find_elements_by_class_name("borderlessBtnDiv")
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    AttributeError: 'WebDriver' object has no attribute 'find_elements_by_class_name'
    Par contre, avec la méthode "find_elements(By.CSS_SELECTOR, "#gridForResultList tr td .borderlessBtnDiv")" cela fonctionne.
    Oui c'est une autre syntaxe, je ne sais pas encore laquelle est nouvelle...

    Voici le code adapté à cette syntaxe :
    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
    import time
    from selenium import webdriver
    from selenium.webdriver.common.by import By
     
    # driver = webdriver.Chrome()
    driver = webdriver.Firefox()
    driver.get("https://www.toolsunited.com/App/EN/TuMenu/ShowResult?search=[[%22Volltext%C2%A7dskm%202.5%22],%22Root%22,0,100,%22default%22,true,[],null]")
     
    time.sleep(3)
     
    # details_btn =  driver.find_elements_by_class_name("borderlessBtnDiv")
    details_btn = driver.find_elements(By.CLASS_NAME, 'borderlessBtnDiv')
    driver.execute_script("window.scrollTo(0,  document.documentElement.scrollHeight);")
     
    print(f"Il y a {len(details_btn)} boutons 'détails'...")
    num = int(input(f"Sur quel bouton veux-tu cliquer ? (Choisis un nombre entre 1 et {len(details_btn)}): "))
    details_btn[num-1].click()




    Citation Envoyé par Puppet_Master Voir le message
    ...impossible d'ouvrir un item non visible.

    A voir comment on peut scroller un peu à chaque item et mieux cibler le tableau des détails.
    Il suffit de faire défiler la scrollbar jusqu'au bout...

    Le nouveau code ci-dessus le fait mais cela utilise un bout de code en JavaScript...

    Ensuite on a accès à tous les éléments...

  5. #5
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 873
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 873
    Points : 3 717
    Points
    3 717
    Par défaut
    Citation Envoyé par Puppet_Master Voir le message

    Par contre, avec la méthode "find_elements(By.CSS_SELECTOR, "#gridForResultList tr td .borderlessBtnDiv")" cela fonctionne.
    Oui on peut aussi utiliser "css selector"...

    Juste la class .borderlessBtnDiv c'est suffisant...


    Citation Envoyé par Puppet_Master Voir le message

    Ça me récupère des choses non voulues et comme vous le mentionniez,
    C'est quelle partie exactement que tu veux récupérer ?

  6. #6
    Membre habitué
    Homme Profil pro
    Master Data Manager
    Inscrit en
    Février 2017
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Master Data Manager
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2017
    Messages : 113
    Points : 148
    Points
    148
    Par défaut
    Citation Envoyé par Beginner.
    Juste la class .borderlessBtnDiv c'est suffisant...


    Citation Envoyé par Beginner.
    C'est quelle partie exactement que tu veux récupérer ?

    A minima le tableau "BNN1 DIN4000", et le top serait d'avoir également le "302-01 ISO".

    Les images sur la droite du pop-up qui affiche les détails, sont-elles récupérables à votre avis ?

  7. #7
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 873
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 873
    Points : 3 717
    Points
    3 717
    Par défaut
    Tu récupères trop de choses car les css selector est mal choisi je pense...

    Citation Envoyé par Puppet_Master Voir le message


    A minima le tableau "BNN1 DIN4000", et le top serait d'avoir également le "302-01 ISO".

    Les images sur la droite du pop-up qui affiche les détails, sont-elles récupérables à votre avis ?
    Peux-tu m'indiquer cela avec une image parce que là je ne vois pas...

    En tous cas il y a une table au milieu avec des tas infos... Faut-il prendre toute la table ou juste centaines lignes ?

    Citation Envoyé par Puppet_Master Voir le message
    Les images sur la droite du pop-up qui affiche les détails, sont-elles récupérables à votre avis ?
    lesquelles ? Une image pour voir... ?

  8. #8
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 873
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 873
    Points : 3 717
    Points
    3 717
    Par défaut
    Ah oui je viens de voir... Ok mais c'est les deux tables entières que tu veux ?

  9. #9
    Membre habitué
    Homme Profil pro
    Master Data Manager
    Inscrit en
    Février 2017
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Master Data Manager
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2017
    Messages : 113
    Points : 148
    Points
    148
    Par défaut
    Les trois colonnes des deux tableaux. (oui toutes les lignes)
    Images attachées Images attachées  

  10. #10
    Membre expert
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    2 873
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 2 873
    Points : 3 717
    Points
    3 717
    Par défaut
    Citation Envoyé par Puppet_Master Voir le message
    Les trois colonnes des deux tableaux. (oui toutes les lignes)
    - Alors as-tu constaté que certaines lignes ne sont pas affichées ? Mais elles sont quand même dans le DOM...
    du coup il faut filtrer : rejeter toutes les lignes avec "display:none"...

    Au début j'ai utilisé ce css selector '.detailsPage .k-grid.k-widget.k-grid-display-block table tbody tr:not([style*="display: none"])'Mais la partie : 'not([style*="display: none"])' n'est pas fiable car il suffit qu'il y ait un caractère différent (même un espace) pour que cela échoue...

    -Et pour les colonnes (td) pareil, certaines ne sont pas affichées...

    Et là j'ai utilisé ce css selector 'td:not([style*="display:none"])...

    Cette fois il y a un espace en moins : "display:none"]) et non "display: none"])...

    ---> Il est plus fiable de tester juste le "none" : '...:not([style*="none"])...

    Mais cela ne fonctionnera pas si il y a un style avec "none" ne correspondant pas à "display"...

    Regarde si cela fonctionne et si tu constates que cela ne fonctionne pas dans certains cas alors il faudra utiliser une solution qui teste vraiment si on n'a ou pas "display" à "none"...


    Un exemple de code qui récupère juste les deux tables du premier article :

    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    from selenium import webdriver
    from selenium.webdriver.common.by import By
     
    # driver = webdriver.Chrome()
    driver = webdriver.Firefox()
    driver.implicitly_wait(7)
     
    driver.maximize_window()
     
    driver.get("https://www.toolsunited.com/App/EN/TuMenu/ShowResult?search=[[%22Volltext%C2%A7dskm%202.5%22],%22Root%22,0,100,%22default%22,true,[],null]")
     
    driver.execute_script("window.scrollTo(0,  document.documentElement.scrollHeight);")
    details_btn = driver.find_elements(By.CLASS_NAME, 'borderlessBtnDiv')
    # le premier détail...
    details_btn[0].click()
     
     
    # DIN4000
    table_DIN4000 = driver.find_element(By.CSS_SELECTOR, ".DINGTCSwitches > div:last-child")
    print(f"------------\n{table_DIN4000.text}")
    table_DIN4000.click()  
     
    tr_lst = driver.find_elements(By.CSS_SELECTOR, '.detailsPage .k-grid.k-widget.k-grid-display-block table tbody tr:not([style*="none"])')
     
    with open(f"csv\\t1_DIN4000.csv", 'w') as f:    
        for tr in tr_lst:
            td_lst = tr.find_elements(By.TAG_NAME, 'td:not([style*="none"])') 
            string = ""
            for td in td_lst:
                string += td.text + ";"                      
            f.write(string[:-1] + "\n")    
     
     
    # 303-06
    table_303_06 = driver.find_element(By.CSS_SELECTOR, ".DINGTCSwitches > div:first-child")
    print(f"------------\n{table_303_06.text}")
    table_303_06.click()  
     
    # time.sleep(1)
    tr_lst = driver.find_elements(By.CSS_SELECTOR, '.detailsPage .k-grid.k-widget.k-grid-display-block table tbody tr:not([style*="none"])')
     
    print(len(tr_lst))
    with open(f"csv\\t1_303-06.csv", 'w') as f:    
        for tr in tr_lst:
            td_lst = tr.find_elements(By.TAG_NAME, 'td:not([style*="none"])') 
            string = ""
            for td in td_lst:
                string += td.text + ";"                      
            f.write(string[:-1] + "\n")
    Pour récupérer les détails des autres articles, il faudra juste une boucle...

    Les deux fichiers sont mis dans le dossier "csv"...

  11. #11
    Membre habitué
    Homme Profil pro
    Master Data Manager
    Inscrit en
    Février 2017
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Master Data Manager
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2017
    Messages : 113
    Points : 148
    Points
    148
    Par défaut
    Super !

    Merci du coup de main !

  12. #12
    Nouveau membre du Club
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Février 2016
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur

    Informations forums :
    Inscription : Février 2016
    Messages : 20
    Points : 28
    Points
    28
    Par défaut
    Bonjour,

    Il est possible de récupérer directement un fichier JSON avec l'ensemble des infos que tu demandes.
    Avec SeleniumWire, on peut capturer les requêtes réseaux.

    Après avoir cliqué (ligne 15 du script de Beginner), l'accès au fichier JSON est disponible.
    Ex : https://www.toolsunited.com/App/EN/A...e698aa9-TrueTU

    Ensuite, il suffit de parcourir le json comme un dictionnaire.

    C'est probable que l'on puisse, récupérer tous les outils visibles sur la page d'un seul coup et reconstruire l'url ci-dessus, avant d'avoir cliqué.

  13. #13
    Membre habitué
    Homme Profil pro
    Master Data Manager
    Inscrit en
    Février 2017
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Master Data Manager
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2017
    Messages : 113
    Points : 148
    Points
    148
    Par défaut
    Bonjour @JayceOne

    Je viens de regarder le JSON retourné par "GetJsonArticleDetails" et en effet il y a tout ce dont j'ai besoin. Merci pour l'info !

    Je ne vais pas avoir le temps de regarder le fonctionnement de SeleniumWire avant ce w-end mais, cela semble une meilleure alternative.

    Je me note ça et je reviendrai faire état de mon avancement ici

    PS : Si vous avez des exemples ou idées je suis toujours preneur

    Edit : Je pose ça ici en guise de mémo et je retourne au taf ...
    Code text : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    https://www.toolsunited.com/App/FR/Article/GetJsonArticleDetails?article=24696400130703869&dataSource=toolsunited&FR-TU-71-5926-432d-8604-5bd11ccb9ab9-TrueTU
     
    article=24696400130703869 => Id d'article
    dataSource=toolsunited => Constante
    FR- => Constante
     TU-71-5926-432d-8604-5bd11ccb9ab9 => UserId (search 'setUserId' in html)
     -TrueTU => Constante

  14. #14
    Nouveau membre du Club
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Février 2016
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur

    Informations forums :
    Inscription : Février 2016
    Messages : 20
    Points : 28
    Points
    28
    Par défaut
    Il faut simplement adapter un peu, le premier exemple de la doc:
    https://pypi.org/project/selenium-wire/

  15. #15
    Membre habitué
    Homme Profil pro
    Master Data Manager
    Inscrit en
    Février 2017
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Master Data Manager
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2017
    Messages : 113
    Points : 148
    Points
    148
    Par défaut
    Bonjour.

    J'ai pas mal avancé sur le sujet. Et vous n'y est pas pour rien

    L'outil n'est pas terminé mais, la partie scrapping n'est plus bloquante.

    Voilà la démarche utilisée:

    1) lancement l'url de recherche via Selenium
    2) collecte la liste des id article
    3) boucle sur la liste id
    3.1) avec requests, on récupère le JSON "GetJsonArticleDetails"
    3.2) on crée un répertoire selon des infos reçues
    3.2) on écrit le JSON dans le dossier
    3.3) on récupère les deux images de l'outil.

    Code python3 : 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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
     
    from seleniumwire import webdriver
    from selenium.webdriver.common.by import By
    import time, requests, json, re, os
     
    # crée et retourne le dossier de l'article
    def mkdir(data):
        cat = ""
        for i in data["Classifications"]:
            if i["ClassificationSystem"] == "ISO":
                cat = i["TextLabelNoNorm"]
        fab = data["COMPLabel"]
        art = data["ArticleNumber"]
        cab = data["Barcode"]
        dir_name = cat + "__" + fab + "__" + art + "__" + cab
        if not os.path.exists("./" + dir_name):
            os.mkdir("./" + dir_name)
        return dir_name
     
     
    # Recupere les images jpg et png de l'article
    def get_images(data):
        imgs = dict()
        for i in data["Mmss"].keys():
            r = re.match(".*\.(jpg|png)", str(data["Mmss"][i]))
            if r:
                k = (
                    "https://www.toolsunited.com/Images/Component/"
                    + data["Mmss"]["J3"]
                    + "/"
                    + re.search("...$", data["Mmss"][i]).group().upper()
                    + "_"
                    + data["Mmss"]["J3"]
                    + "/"
                    + data["Mmss"][i]
                )
                imgs[k] = imgs.get(k, 0) + 1
        path = mkdir(data)
        for i in imgs.keys():
            img_data = requests.get(i).content
            filename = re.sub(r"^.*/([^/]*)$", r"\1", i)
            with open("./" + path + "/" + filename, "wb") as f:
                f.write(img_data)
     
     
    # initialise le pilote de firefox
    driver = webdriver.Firefox()
    driver.implicitly_wait(7)
    driver.maximize_window()
     
    # ouvre sur la recherche a scraper
    # TODO modifier cette url en fonction des arguements
    driver.get(
        "https://www.toolsunited.com/App/EN/TuMenu/ShowResult?search=[[],%22Root%22,0,10,%22default%22,true,[],null]"
    )
    time.sleep(3)
    # scrolling
    driver.execute_script("window.scrollTo(0,  document.documentElement.scrollHeight);")
     
    # collecte les lignes du tableau de resultat de recherche
    td_list = driver.find_elements(By.CSS_SELECTOR, "#gridForResultList tr")
     
    # crée un iterateur d'id article
    ids = iter([i.get_attribute("id") for i in td_list])
     
    # composition fix de l'url json detail article
    req_prefix = "https://www.toolsunited.com/App/FR/Article/GetJsonArticleDetails?article="
    req_sufix = "&dataSource=toolsunited&FR-TU-71-5926-432d-8604-5bd11ccb9ab9-TrueTU"
     
    # collecte json detail pour chaque article
    end = object()
    i = next(ids, end)
    while i is not end:
        url = req_prefix + i + req_sufix
        res = requests.get(url)
        if res.status_code == 200:
            data = res.json()
            path = mkdir(data)
            with open("./" + path + "/" + i + ".json", "w") as f:
                f.write(json.dumps(res.json(), indent=4))
                i = next(ids, end)
            get_images(data)
            continue
        elif res.status_code == 405:
            # userid doit etre valider par un captcha
            # si pas de captcha possibilité de ban :(
            driver.get(
                "https://www.toolsunited.com/App/FR/TuMenu/ShowResult?search=[[%22Volltext%C2%A7NWCW%22],%22Root%22,0,100,%22default%22,true,[],null]"
            )
            input("Valide captcha et press une touche pour continuer ...")
            continue
        else:
            # autre status pas encore géré
            print(res.status_code)
            print(res.raise_for_status())
            input("ENTER pour continuer !")
     
    driver.quit()

    A utiliser avec parcimonie si vous ne voulez pas ban votre ip

    Je marque le sujet comme résolu.
    Toutefois, si vous avez des remarques n'hésitez pas !

  16. #16
    Membre chevronné
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    721
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2006
    Messages : 721
    Points : 1 876
    Points
    1 876
    Par défaut
    Je suis étonnée que vous n'utilisiez pas Beautiful Soup pour extraire les liens des images. Mais vous pourriez aussi tout simplement utiliser les fonctions de Selenium comme driver.find_elements, ce que vous faites déjà ailleurs (ligne 61).
    Utiliser des regex pour parser du HTML n'est jamais une bonne idée.

    Mais je pense qu'il y a un problème de compréhension: vous utilisez à la fois le module requests:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    res = requests.get(url)
    et Selenium pour traiter le même site. Cela manque de cohérence. Choisissez un des deux. En pratique, vous aurez besoin de Selenium dès lors que le Javascript est requis, ou Ajax.

    Il me semble que vous devriez laisser tomber requests puisque vous pouvez écrire driver.get à la place. Ce code peut être simplifié.

  17. #17
    Membre habitué
    Homme Profil pro
    Master Data Manager
    Inscrit en
    Février 2017
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Master Data Manager
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2017
    Messages : 113
    Points : 148
    Points
    148
    Par défaut
    Bonjour @binarygirl

    Merci pour votre retour.

    Citation Envoyé par binarygirl Voir le message
    Je suis étonnée que vous n'utilisiez pas Beautiful Soup
    Je ne connaissais pas ce module, en effet il a semble pas mal.

    Citation Envoyé par binarygirl Voir le message
    pour extraire les liens des images. Mais vous pourriez aussi tout simplement utiliser les fonctions de Selenium comme driver.find_elements, ce que vous faites déjà ailleurs (ligne 61).
    Pour collecter les liens des images, j'ai préféré reconstituer les URL depuis les informations du JSON, fonction get_images(), plutôt que de refaire une requête vers le site. L'idée était de limiter les interactions avec le site.


    Citation Envoyé par binarygirl Voir le message
    Utiliser des regex pour parser du HTML n'est jamais une bonne idée.
    Je suis bien d'accord, c'est pour cela que je ne le fais pas.

    Les deux regex utilisé dans le script :
    1) L.25 = permet de sélectionner les valeurs intéressantes de la section "Mmss" du JSON pour la constitution des URL des images.
    2) L.41 = Permet d'extraire le nom de l'image depuis l'URL pour nommer le fichier en local.


    Citation Envoyé par binarygirl Voir le message
    Mais je pense qu'il y a un problème de compréhension: vous utilisez à la fois le module requests:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    res = requests.get(url)
    et Selenium pour traiter le même site. Cela manque de cohérence. Choisissez un des deux. En pratique, vous aurez besoin de Selenium dès lors que le Javascript est requis, ou Ajax.

    Il me semble que vous devriez laisser tomber requests puisque vous pouvez écrire driver.get à la place. Ce code peut être simplifié.
    Oui, je reconnais que cela parait mélangé.

    Pourquoi :
    1) j'utilise selenium pour la première url, url de recherche. Là j'ai besoin de javascipt pour avoir le tableau de résultat. (d'ailleurs je devrais repasser à selenium plutôt que seleniumwire)
    2) je récupère les id article pour faire des requêtes get qui me retourne un JSON. Pas besoin de javascript (du coup je passe par requests)

    Il faudrait que je teste de remplacer requests par selenium comme vous le suggéré.


    Je suis "novice" sur ce langage, je ne connais pas bien l'écosystème et les bonnes pratiques.

    Encore merci de votre retour, cela aide à grandir

  18. #18
    Nouveau membre du Club
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Février 2016
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur

    Informations forums :
    Inscription : Février 2016
    Messages : 20
    Points : 28
    Points
    28
    Par défaut
    Bonjour,

    À la place de diminuer le nombre d'articles par page, mettre une temporisation entre chaque requête. (ligne 75)
    Une à deux secondes suffisent généralement. À augmenter en cas de blocage.

    Avec requests, il faut au minimum mettre un agent utilisateur dans les en-têtes. Sinon tu seras perçu comme un robot.

    Citation Envoyé par Puppet_Master Voir le message
    Il faudrait que je teste de remplacer requests par selenium comme vous le suggéré.
    J'utilise souvent les 2 conjointement. Sinon, ce serait mieux de faire le contraire.

  19. #19
    Membre chevronné
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    721
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2006
    Messages : 721
    Points : 1 876
    Points
    1 876
    Par défaut
    Citation Envoyé par JayceOne Voir le message
    J'utilise souvent les 2 conjointement. Sinon, ce serait mieux de faire le contraire.
    Je pense que cela induit une complexité inutile, bien que chaque module a ses avantages.
    Pour moi la règle est relativement simple: pour un site simple qui ne nécessite pas de JS, ou pour travailler avec une API, requests est le choix évident.
    S'il y a du JS, Ajax, voire du captcha ou un besoin d'interaction plus complexe alors Selenium s'impose. J'utilise beaucoup Selenium pour faire des captures d'écran aussi.

    Par rapport au site que vous scrappez, avoir à la fois requests et Selenium revient à maintenir deux sessions distinctes. Certes, vous pouvez toujours tenter de partager les cookies, et même spoofer le user agent et harmoniser les headers des deux côtés, mais le fingerprinting sera toujours différent. Et il y a plus de chances d'être détecté comme un bot en utilisant requests. Même en spoofant le user agent, comme vous le mentionnez très justement, et c'est le minimum à faire quand on veut faire du scrapping.

    Et justement en parlant de session, il y a cette notion dans le module requests qui permet d'améliorer les performances.
    Donc au lieu d'écrire:
    on pourrait avoir
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    s = requests.Session()
    s.get(url)
    et ainsi de suite.

  20. #20
    Nouveau membre du Club
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Février 2016
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur

    Informations forums :
    Inscription : Février 2016
    Messages : 20
    Points : 28
    Points
    28
    Par défaut
    Pour ma part, j'utilise Selenium que quand j'ai pas le choix et suis plus à l'aise avec requests.
    Dans le cas de ce site et selon la demande de départ, il est parfaitement possible d'utiliser que requests, même si cela ne saute pas aux yeux.

    Citation Envoyé par binarygirl Voir le message
    Par rapport au site que vous scrappez, avoir à la fois requests et Selenium revient à maintenir deux sessions distinctes.
    Oui, vous avez raison. Mais est-ce vraiment pénalisant. Je n'ai pas scrapper des milliers de sites, ni constaté de ralenti ou de blocage en les utilisant conjointement.


    Citation Envoyé par binarygirl Voir le message
    Et justement en parlant de session, il y a cette notion dans le module requests qui permet d'améliorer les performances.
    Intéressant merci. Je vais tester la prochaine fois que j'ai des données à récupérer.
    Quel retour d'expérience vous avez avec ?

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Possibilite de replication partielle ?
    Par Mupps dans le forum Requêtes
    Réponses: 5
    Dernier message: 19/03/2004, 15h54
  2. Recherche d'une possibilite
    Par Alexnancy dans le forum Langage SQL
    Réponses: 8
    Dernier message: 29/01/2004, 23h46
  3. Les possibilité que C++ offre par rapport à Pascal Objet
    Par Riko dans le forum Langages de programmation
    Réponses: 13
    Dernier message: 01/02/2003, 21h38
  4. quels sont les possibilitées???
    Par lolo-d dans le forum OpenGL
    Réponses: 11
    Dernier message: 16/05/2002, 00h41

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