【问题标题】:Can I get the original page source (vs current DOM) with phantomjs/casperjs?我可以使用 phantomjs/casperjs 获取原始页面源(与当前 DOM 相比)吗?
【发布时间】:2014-06-05 20:31:26
【问题描述】:

我正在尝试获取特定网页的原始来源。

页面一加载就会执行一些修改 DOM 的脚本。我想在任何脚本或用户更改文档中的任何对象之前获取源代码。

使用 Chrome 或 Firefox(可能还有大多数浏览器),我可以查看 DOM(调试实用程序 F12)或查看原始源代码(右键单击,查看源代码)。后者是我想要完成的。

是否可以使用 phantomjs/casperjs 做到这一点?

在进入该页面之前,我必须登录。这在 casperjs 上运行良好。 如果我浏览到该页面并呈现结果,我知道我在正确的页面上。

casper.thenOpen('http://'+customUrl, function(response) {
    this.page.render('example.png'); // *** Renders correct page (current DOM) ***
    console.log(this.page.content); // *** Gets current DOM ***
    casper.download('view-source:'+customUrl, 'b.html', 'GET'); // *** Blank page ***
    console.log(this.getHTML()); // *** Gets current DOM ***
    this.debugPage(); // *** Gets current DOM ***
    utils.dump(response); // *** No BODY ***
    casper.download('http://'+customUrl, 'a.html', 'GET');  // *** Not logged in ?! ***
});

我尝试过this.download(url, 'a.html'),但它似乎没有共享相同的上下文,因为它返回 HTML,就好像我没有登录一样,即使我使用 cookie casperjs test.casper.js --cookies-file=cookies.txt 运行。

我认为我应该继续分析这个选项。


我也尝试过casper.open('view-source:url') 而不是casper.open('http://url'),但它似乎无法识别网址,因为我只是得到一个空白页。

我已经使用我拥有的实用程序查看了从服务器获得的原始 HTTP 响应,并且此消息的正文(即 HTML)是我需要的,但是当页面在浏览器中加载时,DOM 已经被修改.

我试过了:

casper.thenOpen('http://'+url, function(response) {
    ...
}

但是response 对象只包含标题和一些其他信息,但不包含正文。


我也尝试了事件onResourceRequested

这个想法是中止特定网页(引用者)所需的任何资源的下载。

onResourceRequested: function(casperObj, requestData, networkRequest) {
for (var i=0; i < requestData.headers.length; i++) {
    var obj = requestData.headers[i];
    if (obj.name === "Referer" && obj.value === 'http://'+customUrl) {
        networkRequest.abort();
        break;
    }
}

不幸的是,修改 DOM 的脚本最初似乎是内联的主 HTML 页面(或者此代码没有按照我的意愿执行)。


¿有什么想法吗?

这里是完整的代码:

phantom.casperTest = true;
phantom.cookiesEnabled = true;

var utils = require('utils');
var casper = require('casper').create({
    clientScripts:  [],
    pageSettings: {
        loadImages:  false,
        loadPlugins: false,
        javascriptEnabled: true,
        webSecurityEnabled: false
    },
    logLevel: "error",
    verbose: true
});

casper.userAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X)');

casper.start('http://www.xxxxxxx.xxx/login');

casper.waitForSelector('input#login',
    function() {
        this.evaluate(function(customLogin, customPassword) {
            document.getElementById("login").value = customLogin;
            document.getElementById("password").value = customPassword;
            document.getElementById("button").click();
        }, {
            "customLogin": customLogin,
            "customPassword": customPassword
        });
    },
    function() {
        console.log('Can't login.');
    },
    15000
);

casper.waitForSelector('div#home',
    function() {
        console.log('Login successfull.');
    },
    function() {
        console.log('Login failed.');
    },
    15000
);

casper.thenOpen('http://'+customUrl, function(response) {
    this.page.render('example.png'); // *** Renders correct page (current DOM) ***
    console.log(this.page.content); // *** Gets current DOM ***
    casper.download('view-source:'+customUrl, 'b.html', 'GET'); // *** Blank page ***
    console.log(this.getHTML()); // *** Gets current DOM ***
    this.debugPage(); // *** Gets current DOM ***
    utils.dump(response); // *** No BODY ***
    casper.download('http://'+customUrl, 'a.html', 'GET');  // *** Not logged in ?! ***
});

【问题讨论】:

    标签: javascript phantomjs casperjs


    【解决方案1】:

    嗯,你有没有尝试使用一些事件?例如:

    casper.on('load.started', function(resource) {
        casper.echo(casper.getPageContent());
    });
    

    我觉得不行,还是试试吧。

    问题是:您无法在正常的 casperJS 步骤中执行此操作,因为您页面上的脚本已经执行。如果我们可以绑定 on-DOM-Ready 事件,或者有类似的特定 casper 事件,它就可以工作。问题:必须加载页面才能将一些 js 从 Casper 发送到 DOM 环境。所以绑定onready是不可能的(我不明白如何)。我认为使用 phantom 我们可以在加载事件之后抓取 DATA,因此只有在呈现页面时。

    因此,如果无法通过事件破解它并且可能存在一些延迟,那么您唯一的解决方案是阻止修改您的 DOM 的脚本。

    还有 phantomJS 选项,你可以使用它:在 casper 中:

    casper.pageSettings.javascriptEnabled = false;
    

    问题是你需要启用js来取回数据,所以它不能工作......:p是的,没用的评论! :)

    否则,您必须阻止使用事件修改 DOM 的所需资源/脚本。

    或者您可以使用resource.received 事件在修改 DOM 的特定资源出现之前抓取所需的数据。

    事实上我不认为这是可能的,因为如果你创建一个步骤来从页面取回一些数据只是特定资源出现之前,当你的步骤被执行时,资源将会加载.在您的步骤抓取数据时,有必要冻结以下资源。

    虽然不知道该怎么做,但这些事件可以帮助你:

    casper.on('resource.requested', function(request) {
        console.log(" request " + request.url);
    });
    
    casper.on('resource.received', function(resource) {
        console.log(resource.url);
    });
    
    casper.on('resource.error',function (request) {
        this.echo('[res : id and url + error description] <-- ' + request.id + ' ' + request.url + ' ' + request.errorString);
    });
    

    另见How do you Disable css in CasperJS?。 可行的解决方案:您识别脚本并阻止它们。但如果你需要它们,我不知道,这是个好问题。也许我们可以推迟特定脚本的执行。我不认为 Casper 和 phantom 轻易允许这样做。唯一有用的选项是 abort(),给我们这个选项:timeout("time -&gt; ms")

    onResourceRequested

    这里有一个类似的问题:Injecting script before other

    【讨论】:

    • 而不是中止,您是否尝试在收到的足够资源上取回 HTML?与var fs = require('fs'); fs.write("results.html", casper.getPageContent(), 'w');
    【解决方案2】:

    正如 Fanch 指出的那样,似乎不可能做到这一点。如果您能够执行两个请求,那么这将变得容易。只需在启用 JavaScript 和不启用 JavaScript 的情况下执行一个请求,这样您就可以抓取页面源并进行比较。

    casper
        .then(function(){
            this.options.pageSettings.javascriptEnabled = false;
        })
        .thenOpen(url, function(){
            this.echo("before JavaScript");
            this.echo(this.getHTML());
        })
        .then(function(){
            this.options.pageSettings.javascriptEnabled = true;
        })
        .thenOpen(url, function(){
            this.echo("before JavaScript");
            this.echo(this.getHTML());
        });
    

    您可以根据需要更改顺序。如果您已经在想要为其添加原始标记的页面上,则可以使用 casper.getCurrentUrl() 获取当前 URL:

    casper
        .then(function(){
            // submit or whatever
        })
        .thenOpen(url, function(){
            this.echo("after JavaScript");
            this.echo(this.getHTML());
            this.options.pageSettings.javascriptEnabled = false;
    
            this.thenOpen(this.getCurrentUrl(), function(){
                this.echo("before JavaScript");
                this.echo(this.getHTML());
            })
        });
    

    【讨论】:

      【解决方案3】:

      关于docs可以使用#debugPage()获取当前页面的内容。

      casper.userAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X)');
      
      casper.start('http://www.xxxxxxx.xxx/login');
      
      casper.waitForSelector('input#login', ... );
      
      casper.then(function() {
        this.debugHTML();
      });
      
      casper.run();
      

      问候 大卫

      【讨论】:

      • OP 想要完全不变的源,但 debugPage 打印当前页面。这不是答案。
      • 更新了我的答案以使用#debugHTML() 而不是#debugPage()
      • 那也行不通。它不返回原始 HTML。
      • @thebinary:请删除此非答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-03
      • 2012-12-04
      • 1970-01-01
      • 2012-08-21
      • 1970-01-01
      相关资源
      最近更新 更多