web-dev-qa-db-fra.com

Comment télécharger un fichier csv en utilisant PhantomJS

Lorsque je navigue sur un site Web A en utilisant un navigateur normal (Chrome) et lorsque je clique sur un lien du site Web A, Chrome télécharge immédiatement le rapport sous forme de fichier CSV.

Lorsque j'ai vérifié les en-têtes de réponse d'un serveur, j'obtiens les résultats suivants:

Cache-Control:private,max-age=31536000
Connection:Keep-Alive
Content-Disposition:attachment; filename="report.csv"
Content-Encoding:gzip
Content-Language:de-DE
Content-Type:text/csv; charset=UTF-8
Date:Wed, 22 Jul 2015 12:44:30 GMT
Expires:Thu, 21 Jul 2016 12:44:30 GMT
Keep-Alive:timeout=15, max=75
Pragma:cache
Server:Apache
Transfer-Encoding:chunked
Vary:Accept-Encoding

Maintenant, je veux télécharger et analyser ce fichier à l'aide de PhantomJS. J'ai défini l'écouteur pageonResourceReceived pour voir si Phantom recevra/téléchargera le fichier.

clientRequests.phantomPage.onResourceReceived = function(response) {
    console.log('Response (#' + response.id + ', stage "' + response.stage + '"): ' + JSON.stringify(response));
};

Lorsque je fais une demande Phantom pour télécharger un fichier (c'est page.open ('URL DU FICHIER')), je peux voir dans le journal Phantom que le fichier est téléchargé. Voici les journaux:

"contentType": "text/csv; charset=UTF-8",
    "headers": {
        "name": "Date",
        "value": "Wed, 22 Jul 2015 12:57:41 GMT"
    },
    "name": "Content-Disposition",
    "value": "attachment; filename=\"report.csv\"",
    "status":200,"statusText":"OK"

J'ai reçu le fichier et son contenu, mais comment accéder aux données du fichier? Lorsque j'imprime l'objet PhantomJS page actuel, j'obtiens le code HTML de la page A et je ne le veux pas, je veux un fichier CSV, que j'ai besoin d'analyser en utilisant JavaScript.

17
MrD

Après des jours et des jours d'enquête, je dois dire qu'il existe des solutions:

  • Dans votre fonction d'évaluation, vous pouvez effectuer AJAX appel pour télécharger et coder votre fichier, puis vous pouvez renvoyer ce contenu au script fantôme
  • Vous pouvez utiliser une bibliothèque Phantom personnalisée disponible sur certaines pages GitHub

Si vous devez télécharger un fichier à l'aide de PhanotmJS, , fuyez PhantomJS et utilisez CasperJS . CasperJS est basé sur PhantomJS, mais il a une syntaxe et un flux de programme bien meilleurs et intuitifs.

Voici un bon article expliquant " Pourquoi CasperJS est meilleur que PhantomJS ". Dans cet article, vous trouverez une section sur le téléchargement de fichiers.

Comment télécharger un fichier CSV à l'aide de CasperJS (cela fonctionne même lorsque le serveur envoie un en-tête Content-Disposition:attachment; filename='file.csv)

Ici vous pouvez trouver des fichiers csv personnalisés disponibles en téléchargement: http://captaincoffee.com.au/dump/items.csv

Pour télécharger ce fichier à l'aide de CasperJS, exécutez le code suivant:

var casper = require('casper').create();

casper.start("http://captaincoffee.com.au/dump/", function() {
    this.echo(this.getTitle())
});
casper.then(function(){
    var url = 'http://captaincoffee.com.au/dump/csv.csv';
    require('utils').dump(this.base64encode(url, 'get'));
});

casper.run();

Le code ci-dessus téléchargera http://captaincoffee.com.au/dump/csv.csv Fichier CSV et imprimera les résultats sous forme de chaîne base64. Donc, de cette façon, vous n'avez même pas à télécharger de données dans un fichier, vous avez vos données sous forme de chaîne base64.

Si vous souhaitez explicitement télécharger un fichier dans un système de fichiers, vous pouvez utiliser la fonction download qui est disponible dans CasperJS.

8
MrD

J'ai trouvé une solution pour PhantomJS. En lisant cette discussion j'ai trouvé un jsfiddle qui télécharge une URL via la méthode ajax de jQuery et code le fichier en base64.

Le fichier que je voulais télécharger était en texte brut (CSV), j'ai donc supprimé les fonctions d'encodage. Ma page cible avait également déjà inclus jQuery, donc je n'avais pas besoin de injecter jQuery dans la page cible .

Mon code suppose que vous avez déjà ouvert la page sur laquelle vous souhaitez télécharger le fichier à l'aide de PhantomJS, et que cette page contient jQuery. Dans mon cas, je devais d'abord me connecter au site afin d'obtenir le lien de téléchargement.

var fs = require('fs');

var page=this;

var result = page.evaluate(function() {

    var out;
    $.ajax({
        'async' : false,
        'url' : 'fullurltodownload.csv',
        'success' : function(data, status, xhr) {
            out = data;
        }
    });
    return out;

});

fs.write('mydownloadedfile.csv', result);
12
Matthew Lock

Les 2 réponses précédentes supposent que vous pouvez connaître à l'avance l'URL du fichier CSV final. Ce ne sera pas le cas si le lien va vers une page HTML qui fait une redirection Javascript vers le fichier et que vous ne voulez pas évaluer ce Javascript en dehors de PhantomJS. Vos options sont alors:

  1. mettre PhantomJS derrière un proxy en amont, et utiliser ledit proxy en amont pour intercepter l'URL de téléchargement (et ses en-têtes attendus de cookie et de référent) - mais vous devez faire attention à identifier positivement l'URL de téléchargement réelle et non pas un `` blob '' de données aléatoires si la page crée également XMLHttpRequests binaire;
  2. au lieu de PhantomJS, utilisez Headless Chrome qui peut enregistrer automatiquement les fichiers téléchargés (ou Firefox avec PyVirtualDisplay, qui peut également être configuré pour le faire, ou attendre Headless Firefox)) et surveiller le répertoire de téléchargement, mais vous je devrais être en mesure de déterminer par vous-même lorsque le téléchargement est terminé (ou d'utiliser un proxy en amont pour le surveiller, mais Headless Chrome/Firefox ne peut actuellement pas être configuré pour ignorer les certificats SSL, ce qui signifie que si le site est "sécurisé"). "il est beaucoup plus difficile de surveiller les demandes de Headless Chrome/Firefox que de surveiller les demandes de PhantomJS, au moins jusqu'à ce que problème Chrome 721739 soit corrigé; vous pouvez regarder une demande CONNECT mais si elle est conservée vivant, vous n'aurez aucun moyen de savoir avec certitude qu'un transfert est terminé);
  3. placez PhantomJS derrière un proxy en amont qui change tous les types de contenu inconnus en text/plain et supprime les en-têtes Content-Disposition, afin que vous puissiez lire le fichier de PhantomJS de la manière normale - cela devrait fonctionner pour un fichier CSV mais ne fonctionnera pas pour les binaires contenant 0 octet.

La première de ces options (PhantomJS + proxy amont) est facilitée si le proxy amont peut surveiller l'en-tête Accept que PhantomJS envoie au site distant. Au moins dans PhantomJS version 2.1.1, les requêtes principales ont Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8, Les requêtes de feuille de style ont Accept: text/css,*/*;q=0.1 Et toutes les autres requêtes (images, scripts, XMLHttpRequest) par défaut à Accept: */* Bien que cela peut être remplacé par les sites qui utilisent XMLHttpRequest.setRequestHeader(). Par conséquent, si le proxy en amont voit une demande avec un en-tête Accept contenant text/html Et transmet cette demande à la les résultats du serveur dans un fichier CSV ou un autre document non HTML, il y a de fortes chances que ce soit celui à enregistrer.

1
Silas S. Brown