2013-04-22 15 views
15

Desidero scaricare un file CSV, viene generato su un clic del pulsante tramite una richiesta POST. Ho fatto ricerche al mio meglio sui forum di CasperJs e PhantomJS e sono tornato a mani vuote. In un normale browser come Firefox, dopo la richiesta di post viene visualizzata una finestra di dialogo per il download del browser. Come gestire questo caso PhantomJSdownload di un file che viene fornito come allegato in una risposta di richiesta POST in PhantomJs

TTP/1.1 200 OK 
Cache-Control: private 
Content-Type: text/html; charset=utf-8 
Content-Encoding: gzip 
Vary: Accept-Encoding 
Server: Microsoft-IIS/7.5 
Content-disposition: attachment;filename=ExportData.csv 
X-AspNet-Version: 2.0.50727 
X-Powered-By: ASP.NET 
Date: Fri, 19 Apr 2013 23:26:40 GMT 
Content-Length: 65183 

risposta

9

ho trovato un modo per farlo utilizzando casperjs (dovrebbe funzionare con phantomjs da solo se si implementa la funzione di download usando XMLHttpRequest, ma non l'ho provato).

Ti lascio l'esempio funzionante, che tenta di scaricare il recente PDF mos da this page. Quando si fa clic sul collegamento per il download, viene attivato un codice javascript che genera alcuni campi di input nascosti che vengono poi POSTATI.

Quello che facciamo è sostituire la funzione onsubmit del modulo in modo che annulli l'invio e ottenga la destinazione del modulo (azione) e tutti i suoi campi. Utilizziamo queste informazioni in seguito per eseguire il download effettivo.

var casper=require('casper').create(); 
casper.start("https://sede.gobcan.es/tributos/jsf/publico/notificaciones/comparecencia/ultimosanuncios.jsp", function() { 

    var theFormRequest = this.page.evaluate(function() { 
     var request = {}; 
     var formDom = document.forms["resultadoUltimasNotif"]; 
     formDom.onsubmit = function() { 
      //iterate the form fields 
      var data = {}; 
      for(var i = 0; i < formDom.elements.length; i++) { 
       data[formDom.elements[i].name] = formDom.elements[i].value; 
      } 
      request.action = formDom.action; 
      request.data = data; 
      return false; //Stop form submission 
     } 

     //Trigger the click on the link. 
     var link = $("table.listado tbody tr:first a"); 
     link.click(); 

     return request; //Return the form data to casper 
    }); 

    //Start the download 
    casper.download(theFormRequest.action, "downloaded_file.pdf", "POST", theFormRequest.data); 
}); 

casper.run(); 

Nota: è necessario eseguire con --ignore-SSL-errori, come il CA che usano non è nel tuo browser elenco predefinito di CA.

casperjs --ignore-ssl-errors=true downloadscript.js 
+1

grazie, finalmente sono riuscito a ottenere il download CSV per la mia banca per lavorare con il tuo approccio – vinzenzweber

+0

Questo ha funzionato per me ma nella mia istanza cliccando sul link non ho inviato il modulo perché è stato gestito da javascript. Ho dovuto chiamare $ ("# theForm"). Sumit() per far sì che il modulo fosse effettivamente inviato. –

3

È possibile ascoltare l'evento page.resource.received e download() il file una volta ricevuto:

casper.on('page.resource.received', function(resource) { 
    if (resource.stage !== "end") { 
     return; 
    } 
    if (resource.url.indexOf('ExportData.csv') > -1) { 
     this.download(resource.url, 'ExportData.csv'); 
    } 
}); 
+0

Ciao, l'ho provato ma non sembra funzionare – vumaasha

+1

Inoltre non sono sicuro di come dovrebbe funzionare, a meno che il passo 0 non menzionato sia quello di compilare un ramo di sviluppo di fantasma anziché quello corrente? – dtanders

+0

No, dovrebbe funzionare con phantomjs stabili di default poiché il metodo 'download()' è implementato lato casper (usa XHR dietro la scena). – NiKo

2

@julianjm aproach è quasi la soluzione, ma nel mio caso non ho avuto il nome del modulo corretto per sostituire l'invio del modulo.

Così ho trovato un'altra soluzione con phantomjs beta:

C'è una versione beta di phantomjs 2.0 che include un gestore di eventi che risolve questo problema.

È ancora una versione beta, quindi non c'è il debug.

Così ho sviluppato i clic e i trattamenti di pagina sulla versione di rilascio e quindi ho modificato la versione fantasma per rendere il download funzionante.

casper.start('http://www.website.com.br/', function() { 
    this.page.onFileDownload = function(status){console.log('onFileDownload(' + status + ')'); 

//SYSTEM WILL DETECT THE DOWNLOAD, BUT YOU WILL HAVE TO NAME THE FILE BY YOURSLEF!! 
return "ContactList_08-25-14.csv"; }; 

    }); 
     casper.then(function() { 
     //DO YOUR STUFF HERE TO CLICK ON THE DOWNLOAD LINK. 
     }); 
    casper.run(); 

download:Phantom 2.0 BETA

scaricare il file EXE, rinominare la versione di Phantom.exe per phantom.bkp.exe e inserire questa versione 2.0 sul posto. Poi, in casperjs sarà necessario aggiungere alcune righe alla beggining di casperjs/bin/bootstrap.js

* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
* DEALINGS IN THE SOFTWARE. 
* 
*/ 
var system = require('system'); 
    var argsdeprecated = system.args; 
    argsdeprecated.shift(); 
    phantom.args = argsdeprecated; 

commentare anche il controllo della versione (stesso file):

(function(version) { 
     // required version check 
     /* if (version.major !== 1) { 
      return __die('CasperJS needs PhantomJS v1.x'); 
     } if (version.minor < 8) { 
      return __die('CasperJS needs at least PhantomJS v1.8 or later.'); 
     } 
     if (version.minor === 8 && version.patch < 1) { 
      return __die('CasperJS needs at least PhantomJS v1.8.1 or later.'); 
     } */ 
    })(phantom.version); 

Ricorda, questo è un tweak !!.

Quindi queste righe su bootstrap causeranno problemi se si desidera eseguire la versione di rilascio phantom o slimerjs.

Quindi SVILUPPARE SU VERSIONE DI RILASCIO, piuttosto che modificare questa versione per poter scaricare. Se avete bisogno di eseguire il debug, si dovrà rimuovere le linee di bootstrap.js

0

ho a che fare con un sito scritto con una sorta di quadro ASP.Net, che invia una notevole quantità di dati POST ad ogni richiesta (circa 100 Kb di dati, di cui circa 95 non sembrano mai cambiare tra le richieste - apparentemente legate allo stato della vista).

Tuttavia, nessun metodo che ho trovato ha funzionato per me. Ho esaminato intercepting XHR, ho persino trovato someone who is tackling the very same framework (almeno a giudicare dai selettori) ma con un caso più semplice, ispirato proprio da questa domanda. Ho scoperto che back in the day this couldn't be done con PhantomJS.

Il mio problema è che un clic su un pulsante avvia una catena di richieste AJAX che culmina con l'invio di questo enorme modulo POST, al quale infine il server risponde con una "Content-Disposition: attachment".

Alla fine, ho trovato questo approccio che funziona per me, anche se si tratta di rete-inefficiente:

...setting up everything, until I just need to click on a button... 

phantomData = null; 
phantomRequest = null; 

// Here, I just recognize the form being submitted and copy it. 

casper.on('resource.requested', function(requestData, request) { 
    for (var h in requestData.headers) { 
     if (requestData.headers[h].name === 'Content-Type') { 
      if (requestData.headers[h].value === 'application/x-www-form-urlencoded') { 
       phantomData   = requestData; 
       phantomRequest  = request; 
      } 
     } 
    } 
}); 

// Here, I recognize when the request has FAILED because PhantomJS does 
// not support straight downloading. 

casper.on('resource.received', function(resource) { 
    for (var h in resource.headers) { 
     if (resource.headers[h].name === 'content-disposition') { 
      if (resource.stage === 'end') { 
       if (phantomData) { 
        // to do: get name from resource.headers[h].value 
        casper.download(
         resource.url, 
         "output.pdf", 
         phantomData.method, 
         phantomData.postData 
        ); 
       } else { 
        // Something went wrong. 
       } 
       // Possibly, remove listeners? 
      } 
     } 
    } 
}); 

// Now, click on the button and initiate the dance. 
casper.click(pdfLinkSelector); 

Il download funziona perfettamente, anche se mi rendo conto che il file viene richiesto (e inviato due volte.

[debug] [phantom] Navigation requested: url=https://somesite/SomePage.aspx, type=FormSubmitted, willNavigate=true, isMainFrame=true 
[debug] [application] GOT FORM, REQUEST DATA SAVED 
[warning] [phantom] Loading resource failed with status=fail (HTTP 200): https://somesite/SomePage.aspx 
[debug] [application] END STAGE REACHED, PHANTOMDATA PRESENT 
[debug] [application] ATTEMPTING CASPERJS.DOWNLOAD 
[debug] [remote] sendAJAX(): Using HTTP method: 'POST' 
[debug] [phantom] Downloaded and saved resource in output.pdf 
[debug] [application] TERMINATING SUCCESSFULLY 
[debug] [phantom] Navigation requested: url=about:blank, type=Other, willNavigate=true, isMainFrame=true 
[debug] [phantom] url changed to "about:blank" 

(Avanti, io probabilmente modificare lo script per provare invocare request.abort() dall'interno della resource.requested ascoltatore, impostare un semaforo e richiamare nuovamente il downloader - non sarò in grado di ottenere il nome del file allegato, ma che conta poco per me).