我可以使用phantomjs / casperjs获取原始页面源(与当前DOM相比)吗?

时间:2014-06-05 20:31:26

标签: javascript phantomjs casperjs

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

页面执行一些脚本,一旦加载就修改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就像我没有登录一样,即使我使用cookies 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 ?! ***
});

3 个答案:

答案 0 :(得分:3)

嗯,你有没有尝试过一些活动?例如:

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

我认为它无效,无论如何都要尝试。

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

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

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

casper.pageSettings.javascriptEnabled = false;

问题是你需要启用js来获取数据,所以它无法工作......:p是的无用的评论! :)

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

或者您可以使用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和幻影很容易允许。唯一有用的选项是abort(),给我们这个选项:timeout("time -> ms")

onResourceRequested

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

答案 1 :(得分:2)

正如范奇指出的那样,似乎不可能这样做。如果您能够做两个请求,那么这很容易。只需在启用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()获取当前网址:

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());
        })
    });

答案 2 :(得分:-1)

关于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();

问候 大卫