Как загрузить файл csv с помощью PhantomJS

Когда я просматриваю сайт A, используя обычный браузер (Chrome), и когда я нажимаю ссылку на веб-сайте A, Chrome imediatelly загружает отчет в виде CSV файла.

Когда я проверил заголовки ответов сервера, я получаю следующие результаты:

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

Теперь я хочу загрузить и проанализировать этот файл с помощью PhantomJS. Я установил page onResourceReceived прослушиватель, чтобы увидеть, будет ли Phantom получать/загружать файл.

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

Когда я делаю запрос Phantom для загрузки файла (это page.open('URL OF FILE')), я могу увидеть в журнале Phantom, что этот файл загружен. Вот журналы:

"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"

Я получил файл и его содержимое, но как получить доступ к файлам данных? Когда я печатаю текущий объект PhantomJS page, я получаю HTML-код страницы A, и я не хочу этого, я хочу CSV файл, который мне нужно проанализировать с помощью JavaScript.

Ответ 1

После дней и дней расследования я должен сказать, что есть некоторые решения:

  • В вашей функции оценки вы можете сделать вызов AJAX для загрузки и кодирования вашего файла, затем вы можете вернуть это содержимое обратно в phantom script
  • Вы можете использовать некоторую пользовательскую библиотеку phantom, доступную на некоторых страницах GitHub

Если вам нужно загрузить файл с помощью PhanotmJS, , тогда убегите от PhantomJS и используйте CasperJS. CasperJS основан на PhantomJS, но он имеет гораздо лучший и интуитивный синтаксис и программный поток.

Вот хороший пост, объясняющий "Почему CasperJS лучше, чем PhantomJS". В этом сообщении вы можете найти раздел о загрузке файла.

Как загрузить CSV файл с помощью CasperJS (это работает даже тогда, когда сервер отправляет заголовок Content-Disposition:attachment; filename='file.csv)

Здесь вы можете найти пользовательский файл csv, доступный для загрузки: http://captaincoffee.com.au/dump/items.csv

Чтобы загрузить этот файл с помощью CasperJS, выполните следующий код:

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();

Приведенный выше код загрузит файл http://captaincoffee.com.au/dump/csv.csv CSV и распечатает результаты в виде строки base64. Таким образом, вам даже не нужно загружать данные в файл, у вас есть данные в виде строки base64.

Если вы явно хотите загрузить файл в файловую систему, вы можете использовать функцию download, которая доступна в CasperJS.

Ответ 2

Я нашел решение для PhantomJS. Прочитав этот обсуждение, я нашел jsfiddle, который загружает URL-адрес через jQuery ajax-метод и кодирует файл как base64.

Файл, который я хотел скачать, был простым текстом (CSV), поэтому я удалил функции кодирования. На моей целевой странице также был включен jQuery, поэтому мне не нужно было вставить jQuery на целевую страницу.

В моем коде предполагается, что вы уже открыли страницу, которую хотите загрузить файл, используя PhantomJS, и на этой странице есть jQuery. В моем случае мне пришлось сначала войти на сайт, чтобы получить ссылку для скачивания.

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);

Ответ 3

Предыдущие 2 ответа предполагают, что вы можете заранее знать URL окончательного файла CSV. Это не произойдет, если ссылка перейдет на страницу HTML, которая выполняет перенаправление Javascript в файл, и вы не хотите оценивать этот Javascript вне PhantomJS. Ваши варианты:

  • запустите PhantomJS за прокси-сервером вверх и используйте указанный выше прокси-сервер, чтобы перехватить URL-адрес загрузки (и его ожидаемые заголовки Cookie и Referer), но вы должны быть осторожны, чтобы позитивно идентифицировать настоящий URL-адрес загрузки, а не какие-то случайные данные 'blob', если страница также создает двоичные XMLHttpRequests;
  • вместо PhantomJS используйте Chrome Headless Chrome, который может автоматически сохранять загруженные файлы (или Firefox с PyVirtualDisplay, которые также могут быть настроены для этого, или ждать Headless Firefox) и контролировать каталог загрузок - но вы должны быть способны самостоятельно выяснить, когда загрузка завершена (или использовать прокси-сервер восходящего потока, чтобы контролировать его для завершения, но теперь в Chrome Chrome Chrome не может быть установлено игнорирование сертификатов SSL, а это означает, что сайт будет "безопасным" гораздо труднее отслеживать запросы безглавых Chrome/Firefox, чем отслеживать запросы PhantomJS, по крайней мере до тех пор, пока Chromium issue 721739 не будет исправлено; вы можете смотреть запрос CONNECT, но если он будет сохранен, вы не сможете точно знать, что передача завершена);
  • запустите PhantomJS за восходящим прокси-сервером, который изменяет все неизвестные типы контента на text/plain и удаляет заголовки Content-Disposition, поэтому вы можете нормально читать файл из PhantomJS - это должно работать для файла CSV, но не будет работа для двоичных файлов с 0-байтами в них.

Первый из этих опций (PhantomJS + upstream proxy) упрощается, если прокси-сервер вверх может контролировать заголовок Accept, который PhantomJS отправляет на удаленный сайт. По крайней мере, в версии PhantomJS версии 2.1.1 основные запросы имеют Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8, запросы стилей имеют Accept: text/css,*/*;q=0.1, а все остальные запросы (изображения, скрипты, XMLHttpRequest) по умолчанию равны Accept: */*, хотя это может быть переопределено сайтами, использующими XMLHttpRequest.setRequestHeader(). Поэтому, если прокси-сервер восходящего потока видит запрос с заголовком Accept, содержащим text/html, и передача этого запроса на сервер приводит к CSV файлу или другому не-HTML-документу, тогда есть хороший шанс, это тот, который нужно сохранить.