Загрузка файла, который поставляется в виде вложения в ответе запроса POST в PhantomJs
Я хочу загрузить CSV файл, он создается при нажатии кнопки через запрос POST. Я исследовал все возможное на форумах casperJs и phantomJS и вернулся с пустыми руками. В обычном браузере, таком как firefox, после запроса на почту появляется диалоговое окно загрузки браузера. Как обрабатывать этот случай в 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
Ответы
Ответ 1
Я нашел способ сделать это с помощью casperjs (он должен работать только с phantomjs, если вы реализуете функцию загрузки с помощью XMLHttpRequest, но я не пробовал).
Я оставлю вам рабочий пример, который пытается загрузить недавно обновленный PDF файл из этой страницы. Когда вы нажимаете ссылку для загрузки, запускается какой-то код javascript, который генерирует некоторые скрытые поля ввода, которые затем POSTED.
Что мы делаем, это заменить функцию onsubmit формы так, чтобы она отменяет подачу и получает форму (действие) формы и все ее поля. Мы используем эту информацию позже для фактической загрузки.
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();
Примечание. Вы должны запустить его с помощью -ignore-ssl-errors, поскольку CA, который они используют, не находится в списке CA вашего браузера по умолчанию.
casperjs --ignore-ssl-errors=true downloadscript.js
Ответ 2
Вы можете прослушивать событие page.resource.received
и download()
файл при его получении:
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');
}
});
Ответ 3
@julianjm aproach - это почти решение, но в моем случае у меня не было правильного имени формы, чтобы заменить отправку формы.
Итак, я нашел другое решение с использованием phantomjs beta:
Существует бета-версия phantomjs 2.0, которая включает обработчик событий, который решает эту проблему.
Это еще бета-версия, поэтому отладки нет.
Итак, я разработал клики и обработки страниц в версии выпуска, а затем изменил версию phantom, чтобы сделать загрузку.
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();
Загрузить: Phantom 2.0 BETA
Загрузите exe, переименуйте версию выпуска phantom.exe в phantom.bkp.exe
и вставьте эту версию 2.0 на место.
Затем в casperjs вам нужно будет добавить несколько строк при начале работы 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;
также комментировать проверку версии (тот же файл):
(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);
Помните, это настройка!.
Таким образом, эти строки в бутстрапе вызовут проблемы, если вы хотите запустить версию phantom release или slimerjs.
Итак, РАЗРАБОТАТЬ ВЕРСИЯ RELEASE, а не настраивать эту версию для загрузки.
Если вам нужно отлаживать, вам придется удалить строки bootstrap.js
Ответ 4
Мне приходится иметь дело с сайтом, написанным с какой-то структурой ASP.Net, которая отправляет замечательное количество данных POST по каждому запросу (около 100 Кбайт данных, из которых примерно 95 никогда не меняется между запросами - состояние просмотра по-видимому).
Однако ни один метод, который я мог найти, не работал у меня. Я просмотрел перехват XHR, я даже нашел кого-то, кто занимается тем же самым каркасом ( по крайней мере, судя по выборам), но с более простым случаем, вдохновленным именно этим вопросом. Я узнал, что в тот день, когда это невозможно сделать с помощью PhantomJS.
Моя проблема заключается в том, что нажатие кнопки запускает цепочку запросов AJAX, достигающую высшей точки с отправкой этой огромной формы POST, на которую, наконец, сервер отвечает "Content-Disposition: attachment".
В конце концов, я нашел такой подход, который работает для меня, даже если он неэффективен в сети:
...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);
Загрузка работает безупречно, даже если я вижу, что файл запрашивается (и отправляется) дважды.
[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"
(Далее, я, вероятно, изменю script, чтобы попытаться вызвать request.abort()
из прослушивателя resource.requested
, установить семафор и снова вызвать загрузчика - я не смогу получить имя файла вложения, но это мало для меня).