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 :

Parcourir un serveur rapidement et télécharger des éléments sous conditions [Python 3.X]


Sujet :

Réseau/Web Python

  1. #1
    Membre à l'essai
    Homme Profil pro
    Ingénieur d'Études et de Recherche
    Inscrit en
    Octobre 2016
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'Études et de Recherche
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2016
    Messages : 18
    Points : 21
    Points
    21
    Par défaut Parcourir un serveur rapidement et télécharger des éléments sous conditions
    Bonjour à tous,

    Je souhaite rédiger un script me permettant de me connecter à la base de données des images du rover martien Perseverance qui se trouvent sur ce site de la NASA : https://pds-imaging.jpl.nasa.gov/dat...mi_imgops/sol/

    Chaque sous-dossier correspond à un sol martien (un "jour" sur mars).
    J'ai donc en premier lieu une fonction qui me liste tous les liens vers les différents sols :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    def getTree():
    	url = 'https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/'
    	response = requests.get(url)
    	soup = BeautifulSoup(response.text, 'lxml')
    	urls = [url + a.get('href') + '/ids/edr/scam/' for a in soup.find_all('a') if re.match(r'[0-9]{5}', a.get('href'))]
    	return list(dict.fromkeys(urls))
    La méthode get() de requests met environ 10 secondes à s'exécuter, donc pour cette étape ça peut aller.
    Le problème c'est qu'ensuite, je dois parcourir l'ensemble de ces sous-dossiers pour checker s'il y a une image FITS, car il n'y en a pas systématiquement.

    J'ai vu qu'utiliser Session() pouvait être plus rapide alors actuellement la solution ressemble à :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    tree = getTree()
    session = requests.Session()
    for link in tree:
    	session.get(link)
    Sauf que ça prend une éternité...
    Bon et en plus de ça, je dois checker s'il y a un ou plusieurs fichier FITS, regarder si je n'ai pas déjà ces fichiers, et les télécharger si ce n'est pas le cas. Pareil, j'ai une solution mais pas sûre qu'elle soit optimale...

    En fait ce qui à l'air de prendre le plus de temps, c'est d'obtenir le code HTML de la page. Auriez-vous une solution *vraiment* plus rapide ?
    Si possible, j'aimerais éviter de passer par 36 modules tiers...

    Au plaisir de vous lire !

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 355
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 355
    Points : 36 883
    Points
    36 883
    Par défaut
    Salut,

    Citation Envoyé par xPhoton Voir le message
    En fait ce qui à l'air de prendre le plus de temps, c'est d'obtenir le code HTML de la page.
    Si c'est le cas, c'est que votre réseau est lent ou que les serveurs de la NASA sont surchargés ou qu'ils téléchargent les données au compte goutte pour les petits malins qui utilisent leur serveurs pour y mettre au point leurs codes.

    - W

  3. #3
    Membre à l'essai
    Homme Profil pro
    Ingénieur d'Études et de Recherche
    Inscrit en
    Octobre 2016
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'Études et de Recherche
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2016
    Messages : 18
    Points : 21
    Points
    21
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Salut,



    Si c'est le cas, c'est que votre réseau est lent ou que les serveurs de la NASA sont surchargés ou qu'ils téléchargent les données au compte goutte pour les petits malins qui utilisent leur serveurs pour y mettre au point leurs codes.

    - W
    Alors, j'ai testé depuis chez moi, et c'est pareil. Ça aurait pourtant être pu le réseau entreprise qui limitait certaines choses.
    En tout cas, c'est vrai que même en m'y connectant depuis un navigateur, la page met aussi 10 secondes à répondre j'ai l'impression, et j'ai la fibre.
    Pouvez-vous me confirmer que c'est la même chose chez vous ?

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 355
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 355
    Points : 36 883
    Points
    36 883
    Par défaut
    Citation Envoyé par xPhoton Voir le message
    Pouvez-vous me confirmer que c'est la même chose chez vous ?
    Les tests que vous avez faits sont suffisants pour conforter que ce n'est pas le code qu'il faut regarder.
    Reste à voir comment faire avec i.e. comment un programmeur traite ce genre de problème.
    Mais ce n'est pas un sujet "python" car on aurait le soucis avec n'importe quel langage.

    Bon courage.

    - W

  5. #5
    Expert éminent

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

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

    Je confirme, même avec wget ça prend dix seconde pour la réponse. Le fichier se charge lui immédiatement il ne fait que 64 Ko.

    Maintenant je peux le lire directement depuis mon disque, ce qui change beaucoup de chose en termes de rapidité.

    Si python est lent pour certaines choses, par contre il est foudroyant pour de l'analyse de texte et comme tous tes sous-dossiers sont semble-t-il prédictibles on peut directement construire la liste de leurs urls.

    Comme ceci par exemple:
    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
     
    indexes = []
    with open("index.html.1", "r") as inf:
        for l in inf:
            if 'alt="[DIR]"' in l:
                indexes.append(l.split('href="')[1][:6])
     
    urls = []
    base = "https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/"
    for i in indexes:
        urls.append("%s%sids/edr/" %(base, i))
        urls.append("%s%sids/fdr/" %(base, i))
        urls.append("%s%sids/rdr/" %(base, i))
     
    for u in urls:
        print(u)
    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
     
    ......
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00294/ids/rdr/
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00295/ids/edr/
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00295/ids/fdr/
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00295/ids/rdr/
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00296/ids/edr/
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00296/ids/fdr/
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00296/ids/rdr/
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00297/ids/edr/
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00297/ids/fdr/
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00297/ids/rdr/
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00299/ids/edr/
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00299/ids/fdr/
    https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/00299/ids/rdr/
    Et ça c'est instantané.

  6. #6
    Membre à l'essai
    Homme Profil pro
    Ingénieur d'Études et de Recherche
    Inscrit en
    Octobre 2016
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'Études et de Recherche
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2016
    Messages : 18
    Points : 21
    Points
    21
    Par défaut
    Yes en effet cette partie prend moins d'une demi seconde, c'est ce que fait ma fonction getTree() décrite initialement.
    Mais après il faut aller récupérer le code HTML de chaque lien, et comme il y en a actuellement 208, cela met environ 35 minutes.
    J'ai vu qu'il était possible de paralléliser les requêtes, je vais essayer ça comme solution, si quelqu'un a mieux je suis preneur

  7. #7
    Expert éminent

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 302
    Points : 6 782
    Points
    6 782
    Par défaut
    Ça parait ahurissant comme stats, j'ai voulu essayer.

    Avec le code ci-dessous, j'ai 626 pages qui me donnent 24.764 IMG en 775 secondes (12 min. 55 sec.)

    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
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
     
     
     
     
    import time
    import urllib.request
    from html.parser import HTMLParser
     
     
    def get_page(url):
        user_agent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:49.0)'\
                      ' Gecko/20100101 Firefox/49.0'
        req = urllib.request.Request(url, data=None, 
                                     headers={"User-Agent": user_agent})
        try:
            content = urllib.request.urlopen(req)
        except Exception as why:
            print('urllib error: %s, %s' % (url, why))
            return False
     
        return str(content.read())
     
    class ImgParser(HTMLParser):
        def __init__(self):
            super().__init__()
            self.in_td = False
            self.imgs = []
     
        def handle_starttag(self, tag, attrs):
            if tag == "td":
                #print("in td:", attrs)
                self.in_td = True
     
            if tag == "a" and self.in_td:
                for att in attrs:
                    if att[0] == "href" and att[1].endswith(".IMG"):
                        self.imgs.append(att[1])
                        break
     
                self.in_td = False
     
    indexes = []
    with open("index.html.1", "r") as inf:
        for l in inf:
            if 'alt="[DIR]"' in l:
                indexes.append(l.split('href="')[1][:6])
     
    urls = []
    base = "https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/"
    for i in indexes:
        urls.append("%s%sids/edr/scam/" %(base, i))
        urls.append("%s%sids/fdr/scam/" %(base, i))
        urls.append("%s%sids/rdr/scam/" %(base, i))
     
    image_urls = []
    begin = time.perf_counter()
    print("Scan %s pages" % len(urls))
    for u in urls:
        content = get_page(u)
        if content:
            p = ImgParser()
            p.feed(content)
            image_urls.extend("".join([u, i]) for i in p.imgs)
     
    end = time.perf_counter()
    print("Found %s IMG at: %s" %(len(image_urls), end-begin))
    for i in image_urls[:10]:
        print(i)
    Tu remarqueras que je préfère HTMLParser à BeautifullSoup qui est connu pour être particulièrement lent.
    Je vais essayer en séparant la tâche en plusieurs threads.

  8. #8
    Expert éminent

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

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 302
    Points : 6 782
    Points
    6 782
    Par défaut
    En séparant la tâche en trois threads j'obtiens mes 24.764 IMG en 270 sec. (4 min. 30 sec.)

    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
    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
     
    import time
    import urllib.request
    from html.parser import HTMLParser
    from threading import Thread, Timer
     
     
    def get_page(url):
        user_agent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:49.0)'\
                      ' Gecko/20100101 Firefox/49.0'
        req = urllib.request.Request(url, data=None, 
                                     headers={"User-Agent": user_agent})
        try:
            content = urllib.request.urlopen(req)
        except Exception as why:
            print('urllib error: %s, %s' % (url, why))
            return False
     
        return str(content.read())
     
    class ImgParser(HTMLParser):
        def __init__(self):
            super().__init__()
            self.in_td = False
            self.imgs = []
     
        def handle_starttag(self, tag, attrs):
            if tag == "td":
                self.in_td = True
     
            if tag == "a" and self.in_td:
                for att in attrs:
                    if att[0] == "href" and att[1].endswith(".IMG"):
                        self.imgs.append(att[1])
                        break
     
                self.in_td = False
    def rerun(threads, lst_0, lst_1, lst_2):
        wait_for(threads, lst_0, lst_1, lst_2)
     
    def wait_for(threads, lst_0, lst_1, lst_2):
        if len(threads) < 3:
            t = Timer(10, rerun, args=(threads, lst_0, lst_1, lst_2))
            t.start()
     
        else:
            tot = len(lst_0) + len(lst_1) + len(lst_2)
            end = time.perf_counter()
            print("Found %s IMG at: %s" %(tot, end-begin))
            # TODO Save the lists into a file !
     
    indexes = []
    with open("index.html.1", "r") as inf:
        for l in inf:
            if 'alt="[DIR]"' in l:
                indexes.append(l.split('href="')[1][:6])
     
    urls = []
    base = "https://pds-imaging.jpl.nasa.gov/data/mars2020/mars2020_imgops/data_rmi_imgops/sol/"
    for i in indexes:
        urls.append("%s%sids/edr/scam/" %(base, i))
        urls.append("%s%sids/fdr/scam/" %(base, i))
        urls.append("%s%sids/rdr/scam/" %(base, i))
     
    image_urls = []
    begin = time.perf_counter()
    print("Scan %s pages" % len(urls))
    part = int(len(urls) / 3)
    flags = []
    img_part_0 = []
    img_part_1 = []
    img_part_2 = []
     
    def scan_pages(*args):
        urls, images, flags = args  
        for u in urls:
            content = get_page(u)
            if content:
                p = ImgParser()
                p.feed(content)
                images.extend("".join([u, i]) for i in p.imgs)
        flags.append(1)
     
    Thread(target=scan_pages, args=(urls[0:part], img_part_0, flags)).start()
    Thread(target=scan_pages, args=(urls[part:part*2], img_part_1, flags)).start()
    Thread(target=scan_pages, args=(urls[part*2:], img_part_2, flags)).start()
    wait_for(flags, img_part_0, img_part_1, img_part_2)

  9. #9
    Membre à l'essai
    Homme Profil pro
    Ingénieur d'Études et de Recherche
    Inscrit en
    Octobre 2016
    Messages
    18
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'Études et de Recherche
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2016
    Messages : 18
    Points : 21
    Points
    21
    Par défaut
    Merci VinsS d'avoir prit le temps de tester quelque chose de différent, je vais analyser tout ça parce que c'est vrai que je ne suis pas du tout familier au web scrapping et à ces librairies, je ne savais d'ailleurs pas que BeautifulSoup était réputé pour être lent
    Bon par contre, je ne sais pas pourquoi, mais depuis hier, c'est tout de même beaucoup plus rapide, toujours avec requests.Session(), je récupère ma liste de liens vers les FITS à télécharger en quelques minutes à peine.
    Ensuite, j'ai stocké tous les liens complets (par exemple https://pds-imaging.jpl.nasa.gov/dat...0030I9J03.fits) dans un fichier texte, puis en appliquant ce qui est fait ici, cela fonctionne plutôt bien. Les FITS font tout de même un peu plus de 8Mo, donc quoi qu'il est arrive, initialement j'avais environ 1120 fichiers à télécharger et ça représentait un peu plus de 9Go de data à télécharger.

  10. #10
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 914
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 914
    Points : 7 298
    Points
    7 298
    Par défaut
    Bonjour,

    À mon sens, ça sera bien plus rapide en utilisant les tâches asynchrones (asyncio + aiohttp)

    Ça pourrait ressembler à cela,

    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
     
    import asyncio
    import aiohttp
     
    async def request(session, url):
        async with session.get(url) as resp:
            if resp.status == 200:
                await resp.text()
     
    async def main(links):
        async with aiohttp.ClientSession() as session:
            await asyncio.gather(
                *[request(session, i) for i in enumerate(links)]
            )
     
     
    links = ... # tous les liens récupérés
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main(links))

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

Discussions similaires

  1. comment mettre un des éléments sous une barre de défilement
    Par noelo dans le forum Macros et VBA Excel
    Réponses: 0
    Dernier message: 05/11/2019, 16h51
  2. Serveur FTP pour télécharger des fichiers
    Par momedalhouma dans le forum API standards et tierces
    Réponses: 0
    Dernier message: 28/03/2013, 09h11
  3. Réponses: 0
    Dernier message: 18/09/2009, 05h43
  4. Réponses: 0
    Dernier message: 18/09/2009, 05h43
  5. Suppression des lignes sous condition multiple
    Par baptbapt dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 20/06/2007, 16h23

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