Как загрузить файл 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-документу, тогда есть хороший шанс, это тот, который нужно сохранить.