我想使用CasperJS从网站下载.pdf文件列表。它(大多数)工作,但最后几个PDF文件被截断。以下是相关的代码段:
casper.then(function a09() {
for (var index = bill_count-1; index>=0; --index) {
casper.then(downloadOnePdf(index));
};
});
function downloadOnePdf(index) {
return function() {
var selector = 'div#myAjaxDiv tbody tr:nth-child(' + (index+1) + ') form a'
casper.log('click ' + selector, 'info');
casper.click(selector);
// casper.waitForResource(/\/Document/); -- see note
// casper.waitForText('%%EOF'); -- see note
};
};
casper.run();
通过Web代理执行此代码,我可以看到.pdf文件作为响应主体到达。但是,最后两个或三个文件没有完全下载 - 它们被截断 - 我在响应标题'客户端关闭连接之前看到一条消息,然后才收到整个响应'。
这支持了我的预感,即在完全下载pdf之前casperjs代码退出。我尝试添加
casper.waitForResource(/\/Document/)
在我的代码中,但没有帮助。我也尝试过:
casper.waitForText('%%EOF')
但即使我能在回复正文中看到'%% EOF',它也会超时。
所以问题是:确保整个.pdf到达响应主体的正确方法是什么?
ps:细心的读者会注意到我实际上并没有保存.pdf数据。这是另一天的问题......
答案 0 :(得分:1)
事实证明,原始帖子中的截断文件只是较大问题的一小部分,但解决方案并不困难。让我解释一下......
CasperJS无法直接访问响应正文,因此OP casper.click()
在返回响应中PDF数据的表单上的方法不胜一筹到处都是。 AFAIK,无法在本地文件系统上实际保存这些数据。
相反,您需要调用casper.download()
来POST您在单击表单时获得的相同表单。这种方法的关键点很简单,尽管记录很少:
nth-child()
伪类从表中选择单个行。casper.getFormValues()
构建一个POSTable表单。 casper.download()
发布表单并保存结果数据。相关代码摘录如下。我希望有人会觉得这很有用(即使从现在起几个月后我就有人了)。
// ========== helpers
// The following helpers assume that the current DOM contains the table with the download forms
// Return the number of PDFs available for download.
function countPDFs() {
return casper.getElementsAttribute('div#myAjaxDiv tbody tr form input[name="id"]', 'value').length
}
// Get the invoice ID of the index'th invoice: 0 <= index < countPDFs().
function getInvoiceID(index) {
return casper.getElementAttribute('div#myAjaxDiv tbody tr:nth-child(' + (index+1) + ') form input[name="id"]', 'value');
}
// Return the index'th form for downloading a .pdf: 0 <= index < countPDFs().
function getDownloadForm(index) {
return casper.getFormValues('div#myAjaxDiv tbody tr:nth-child(' + (index+1) + ') form')
}
// Download the index'th PDF file, saving it to <target_directory>/<invoiceID>.pdf.
// 0 <= index < countPDFs().
function downloadOnePDF(index, target_directory) {
var
url = 'https://example.com/Invoice',
target = target_directory + '/' + getInvoiceID(index) + '.pdf',
data = getDownloadForm(index);
casper.then(function d01() {
casper.log('downloading pdf ' + index + ' to ' + url);
casper.download(url, target, 'POST', data);
});
}
// ========== casper agenda items
// (initial steps omitted)
// Click on "Invoice" button to bring up the Invoice page
var invoice_link_css = 'a#mnuInvoiceSubmit'
casper.then(function a06() {
casper.click(invoice_link_css)
});
// Make sure the Invoice page has loaded, as evidenced by the presence of the
// bill history table.
casper.then(function a07() {
casper.waitForSelector('div#myAjaxDiv tbody');
});
// Download each .pdf file referenced in the bill history table.
casper.then(function a08() {
var pdf_count = countPDFs();
casper.echo('found ' + pdf_count + ' past bill' + ((pdf_count == 1) ? '' : 's'));
for (var index = pdf_count-1; index>=0; --index) {
downloadOnePDF(index, target_directory);
}
});
casper.run();
此方法将每个.pdf文件保存到本地文件系统,并且不会在OP中出现任何截断问题。