【问题标题】:How to download a csv file using PhantomJS如何使用 PhantomJS 下载 csv 文件
【发布时间】:2015-10-12 09:25:04
【问题描述】:

当我使用普通浏览器 (Chrome) 浏览网站 A 时,当我点击网站 A 上的链接时,Chrome 会立即以 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 下载和解析这个文件。我设置了pageonResourceReceived监听器来查看Phantom是否会接收/下载文件。

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 对象时,我得到了页面 A 的 HTML,我不想要那个,我想要 CSV 文件,我需要使用 JavaScript 解析它。

【问题讨论】:

  • Wtf 伙计,如果我告诉我的同事为我的每一篇文章点赞,这几年我在 StackOverflow 和其他网络上的得分将超过 600 分。当我在一小时内看到 3 个赞成票时,我也很惊讶,但这很好也不错。如果你调查这个问题,太多的人面临同样的问题,我想看看是否有人找到了一个好的解决方案。
  • 写完评论后,我查看了您的帖子历史记录,发现这里不太可能存在投票欺诈。不过,我仍然觉得奇怪的是,您在不到 10 分钟的时间内在 [phantomjs] 和 [casperjs] 这样的低票标签中获得了 3 个赞成票。可能是因为 [http],但我有点怀疑。
  • 关于副本,我抓住了错误的链接,但它仍然包含对您问题的可行答案,但它包含在 CasperJS 代码中。我说的是 PhantomJS fork 的 page.onFileDownload
  • 经过几天和几天的调查,这对于 PhantomJS 来说几乎是不可能的。有一些解决方案,但没有那么优雅。在 CasperJS 上花了 3 个小时后,我做到了,所以 使用 CasperJS 不仅因为这个问题,CasperJS 更直观,更易于使用。

标签: javascript http download phantomjs


【解决方案1】:

前面的 2 个答案假设您可以提前知道最终 CSV 文件的 URL。如果链接转到对文件执行 Javascript 计算重定向的 HTML 页面,并且您不想在 PhantomJS 之外评估该 Javascript,则情况并非如此。那么你的选择是:

  1. 将 PhantomJS 放在上游代理后面,并使用所述上游代理拦截下载 URL(及其预期的 Cookie 和 Referer 标头)——但您必须小心确定真正的下载 URL,而不是一些随机数据如果页面也生成二进制 XMLHttpRequest,则为“blob”;
  2. 使用 Headless Chrome 代替 PhantomJS,它可以自动保存下载的文件(或带有 PyVirtualDisplay 的 Firefox,也可以设置为执行此操作,或者等待 Headless Firefox)并监控下载目录——但你必须能够自己弄清楚下载何时完成(或使用上游代理来监控它是否完成,但目前无法将 Headless Chrome/Firefox 设置为忽略 SSL 证书,这意味着如果网站变得“安全”,则更难监控 Headless Chrome/Firefox 的请求,而不是监控 PhantomJS 的请求,至少在修复 Chromium issue 721739 之前;您可以观看 CONNECT 请求,但如果它保持活动状态,您将无法确定转移已完成);
  3. 将 PhantomJS 放在上游代理后面,该代理会将所有未知内容类型更改为 text/plain 并删除 Content-Disposition 标头,因此您可以以正常方式从 PhantomJS 读取文件 - 这应该适用于 CSV 文件,但不会适用于其中包含 0 字节的二进制文件。

如果上游代理可以监控 PhantomJS 发送到远程站点的 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: */*,尽管这可以被使用@987654328 的站点覆盖@。因此,如果上游代理看到一个带有 Accept 标头的请求,其中包含 text/html,并且将 this 请求传递给服务器会生成 CSV 文件或其他非 HTML 文档,那么这是一个很好的很有可能这是要保存的。

【讨论】:

    【解决方案2】:

    经过几天和几天的调查,不得不说有一些解决办法:

    • 在您的评估函数中,您可以调用 AJAX 来下载和编码您的文件,然后您可以将此内容返回给虚拟脚本
    • 您可以使用一些 GitHub 页面上提供的自定义 Phantom 库

    如果您需要使用 PhanotmJS 下载文件,请远离 PhantomJS 并使用 CasperJS。 CasperJS 基于 PhantomJS,但它的语法和程序流程更好、更直观。

    这是解释“Why CasperJS is better than PhantomJS”的好帖子。在这篇文章中,您可以找到有关文件下载的部分。

    如何使用 CasperJS 下载 CSV 文件(即使服务器发送标头 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 函数。

    【讨论】:

    • 我刚刚为 Casper 安装了 PHP 包装器:github.com/alwex/php-casperjs - 关于如何在 PHP 中执行上述操作并下载 CSV 的任何想法?
    【解决方案3】:

    我找到了 PhantomJS 的解决方案。通读这个discussion,我发现了一个jsfiddle,它通过jQuery的ajax方法下载一个url,并将文件编码为base64。

    我要下载的文件是纯文本 (CSV),因此我删除了编码功能。我的目标页面也已经包含了 jQuery,所以我不需要 inject jQuery into the target page

    我的代码假设您已经打开了要使用 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);
    

    【讨论】:

    • 我认为 CasperJS 中的解决方案也是基于这种方法,但它包含了漂亮的 downloadbase64encode 函数。很高兴您找到了一个好的解决方案,希望您的回答对其他人有所帮助。
    • 是的,很遗憾,由于 Selenium 和 C# 的要求,我被 PhantomJS 困住了。
    • Ajax 不支持 cookie,因此该解决方案不适用于 cookie 检查服务器端脚本。伤心:d
    • 这可能有助于重新使用 cookie stackoverflow.com/questions/20953864/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-25
    • 2014-03-18
    • 1970-01-01
    • 2016-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多