如何使用 PhantomJS 下载 csv 文件
How to download a csv file using PhantomJS
当我使用普通浏览器 (Chrome) 浏览网站 A 并单击网站 A 上的 link 时,Chrome 会立即下载一份报告CSV 文件。
当我检查服务器响应时 headers 我得到以下结果:
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 是否会 receive/download 文件。
clientRequests.phantomPage.onResourceReceived = function(response) {
console.log('Response (#' + response.id + ', stage "' + response.stage + '"): ' + JSON.stringify(response));
};
当我发出 Phantom 请求下载文件时(这是 page.open('URL OF THE 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
object 时,我得到了页面 A 的 HTML,我不想要那个,我想要 CSV 文件,我需要使用 [=33] 来解析它=].
经过日复一日的调查,我不得不说有一些解决方案:
- 在您的评估函数中,您可以调用 AJAX 来下载和编码您的文件,然后您可以 return 此内容返回到幻影脚本
- 您可以使用某些 GitHub 页面上可用的自定义 Phantom 库
如果您需要使用 PhanotmJS 下载文件,然后 运行 远离 PhantomJS 并使用 CasperJS。 CasperJS 基于 PhantomJS,但它有更好更直观的语法和程序流程。
这里很好post解释“Why CasperJS is better than PhantomJS”。在此 post 您可以找到有关文件下载的部分。
如何使用 CasperJS 下载 CSV 文件(即使服务器发送 header 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 字符串。
如果您明确想要将文件下载到文件系统,您可以使用 CasperJS 中提供的 download
函数。
我找到了 PhantomJS 的解决方案。阅读此 discussion I found a jsfiddle,它通过 jQuery 的 ajax 方法下载 url 并将文件编码为 base64。
我要下载的文件是纯文本 (CSV),所以我删除了编码功能。我的目标页面也已经包含 jQuery,所以我不需要 inject jQuery into the target page。
我的代码假定您已经打开了要使用 PhantomJS 下载文件的页面,并且该页面中有 jQuery。就我而言,我必须先登录该站点才能下载 link.
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);
前 2 个答案假设您可以提前知道最终 CSV 文件的 URL。如果 link 转到 HTML 页面,该页面执行 Javascript-computed 重定向到文件并且您不想在外部评估 Javascript PhantomJS 的。那么您的选择是:
- 将 PhantomJS 放在上游代理后面,并使用所述上游代理拦截下载 URL(及其预期的 Cookie 和 Referer headers)——但你必须小心如果页面也生成二进制 XMLHttpRequests,则积极识别真正的下载 URL 而不是一些随机数据 'blob';
- 使用 Headless Chrome 而不是 PhantomJS,它可以自动保存下载的文件(或带有 PyVirtualDisplay 的 Firefox,也可以设置为执行此操作,或者等待 Headless Firefox)并监控下载目录——但是你必须能够自己弄清楚何时下载完成(或使用上游代理来监视它是否完成,但 Headless Chrome/Firefox 当前无法设置为忽略 SSL 证书,这意味着如果站点访问"secure" 监控 Headless Chrome/Firefox 的请求比监控 PhantomJS 的请求要困难得多,至少在 Chromium issue 721739 修复之前是这样;您可以查看 CONNECT 请求,但如果它是keep alive 你将无法确定传输是否已完成);
- 将 PhantomJS 置于上游代理之后,将所有未知内容类型更改为
text/plain
并删除 Content-Disposition
headers,因此您可以以正常方式从 PhantomJS 读取文件 -这应该适用于 CSV 文件,但不适用于其中包含 0 字节的二进制文件。
如果上游代理可以监控 PhantomJS 发送到远程站点的 Accept
header,那么第一个选项(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()
的网站。因此,如果上游代理看到包含 text/html
Accept
header 的请求,并将 this 请求传递给服务器,则会生成 CSV 文件或其他 non-HTML 文件,那么很有可能就是要保存的文件。
当我使用普通浏览器 (Chrome) 浏览网站 A 并单击网站 A 上的 link 时,Chrome 会立即下载一份报告CSV 文件。
当我检查服务器响应时 headers 我得到以下结果:
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 是否会 receive/download 文件。
clientRequests.phantomPage.onResourceReceived = function(response) {
console.log('Response (#' + response.id + ', stage "' + response.stage + '"): ' + JSON.stringify(response));
};
当我发出 Phantom 请求下载文件时(这是 page.open('URL OF THE 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
object 时,我得到了页面 A 的 HTML,我不想要那个,我想要 CSV 文件,我需要使用 [=33] 来解析它=].
经过日复一日的调查,我不得不说有一些解决方案:
- 在您的评估函数中,您可以调用 AJAX 来下载和编码您的文件,然后您可以 return 此内容返回到幻影脚本
- 您可以使用某些 GitHub 页面上可用的自定义 Phantom 库
如果您需要使用 PhanotmJS 下载文件,然后 运行 远离 PhantomJS 并使用 CasperJS。 CasperJS 基于 PhantomJS,但它有更好更直观的语法和程序流程。
这里很好post解释“Why CasperJS is better than PhantomJS”。在此 post 您可以找到有关文件下载的部分。
如何使用 CasperJS 下载 CSV 文件(即使服务器发送 header 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 字符串。
如果您明确想要将文件下载到文件系统,您可以使用 CasperJS 中提供的 download
函数。
我找到了 PhantomJS 的解决方案。阅读此 discussion I found a jsfiddle,它通过 jQuery 的 ajax 方法下载 url 并将文件编码为 base64。
我要下载的文件是纯文本 (CSV),所以我删除了编码功能。我的目标页面也已经包含 jQuery,所以我不需要 inject jQuery into the target page。
我的代码假定您已经打开了要使用 PhantomJS 下载文件的页面,并且该页面中有 jQuery。就我而言,我必须先登录该站点才能下载 link.
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);
前 2 个答案假设您可以提前知道最终 CSV 文件的 URL。如果 link 转到 HTML 页面,该页面执行 Javascript-computed 重定向到文件并且您不想在外部评估 Javascript PhantomJS 的。那么您的选择是:
- 将 PhantomJS 放在上游代理后面,并使用所述上游代理拦截下载 URL(及其预期的 Cookie 和 Referer headers)——但你必须小心如果页面也生成二进制 XMLHttpRequests,则积极识别真正的下载 URL 而不是一些随机数据 'blob';
- 使用 Headless Chrome 而不是 PhantomJS,它可以自动保存下载的文件(或带有 PyVirtualDisplay 的 Firefox,也可以设置为执行此操作,或者等待 Headless Firefox)并监控下载目录——但是你必须能够自己弄清楚何时下载完成(或使用上游代理来监视它是否完成,但 Headless Chrome/Firefox 当前无法设置为忽略 SSL 证书,这意味着如果站点访问"secure" 监控 Headless Chrome/Firefox 的请求比监控 PhantomJS 的请求要困难得多,至少在 Chromium issue 721739 修复之前是这样;您可以查看 CONNECT 请求,但如果它是keep alive 你将无法确定传输是否已完成);
- 将 PhantomJS 置于上游代理之后,将所有未知内容类型更改为
text/plain
并删除Content-Disposition
headers,因此您可以以正常方式从 PhantomJS 读取文件 -这应该适用于 CSV 文件,但不适用于其中包含 0 字节的二进制文件。
如果上游代理可以监控 PhantomJS 发送到远程站点的 Accept
header,那么第一个选项(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()
的网站。因此,如果上游代理看到包含 text/html
Accept
header 的请求,并将 this 请求传递给服务器,则会生成 CSV 文件或其他 non-HTML 文件,那么很有可能就是要保存的文件。