【问题标题】:Scraping React Site with Phantomjs使用 Phantomjs 抓取 React 站点
【发布时间】:2016-11-05 16:48:54
【问题描述】:

我正在抓取一个使用 React 组件的网站,在 Nodejs 中使用 PhantomJS。

有了这个:https://github.com/amir20/phantomjs-node

代码如下:

phantom.create().then(ph => {
    _ph = ph;
    return _ph.createPage();
}).then(page => {
    _page = page;
    return _page.open(url);
}).then(status => {
    return _page.property('content');
}).then(content => {
    console.log(content);
    _page.close();
    _ph.exit();
}).catch(e => console.log(e));

问题是没有渲染反应内容,它只说:<!-- react-empty: 1 -->" 应该在哪里加载实际的反应组件。

如何废弃渲染的 React 组件?我最初从纯节点请求解决方案切换到 PhantomJS 来解决这个问题,但现在我被卡住了。


更新:

所以我还没有真正的解决方案。我切换到 NightmareJS (https://github.com/segmentio/nightmare),它有一个很好的 .wait('.some-selector') 函数,它一直等到指定的选择器被加载。这解决了我动态加载的反应组件的问题。

【问题讨论】:

  • 这个包是否支持接收 page.onError 回调?有没有错误?
  • 是的,有console.log(status);,它返回成功。我得到了整个 HTML 内容,除了我得到 <!-- react-empty: 1 --> 的反应组件
  • 我怀疑 status 如果来自 page.open 回调,您需要检查 page.onError 回调中的错误。可能是这样的:Why I am not able to render my ReactJS application using PhantomJS

标签: javascript node.js reactjs web-scraping phantomjs


【解决方案1】:

我认为您应该在页面加载后等待渲染页面上的反应元素。下面是使用 Q 承诺的这种等待函数的示例。此函数返回一个承诺并每 50 毫秒检查一次页面状态。如果达到所需的页面状态,该函数将解析该承诺。在超时的情况下,该函数拒绝承诺。

var phantom = require('phantom');
var Q = require('q');
var _ph, _page, _outObj;
var url = 'https://tech.yandex.ru/maps/jsbox/';

phantom.create().then(ph => {
    _ph = ph;
    return _ph.createPage();
}).then(page => {
    _page = page;
    return _page.open(url);
}).then(status => {
    console.log(status);
    return waitState(textPopulated, 3);
}).then(() => {
    return _page.property('content');
}).then(content => {
    console.log(content);
_page.close();
_ph.exit();
}).catch(e => console.log(e));

function textPopulated() {
    return _page.evaluate(function() {
        var layer = document.querySelector('.ace_text-layer');
        return layer && layer.childElementCount;
    }).then(function(childElementCount) {
        console.log('childElementCount: ' + childElementCount);
        return childElementCount > 0;
    });
}

function waitState(state, timeout) {  // timeout in seconds is optional
    console.log('Start waiting for state: ' + state.name);

    var limitTime = timeout * 1000 || 20000;
    var startTime = new Date();

    return wait();

    function wait() {
        return state().then(function(result) {
            if (result) {
                console.log('Reached state: ' + state.name);
                return;
            } else if (new Date() - startTime > limitTime) {
                var errorMessage = 'Timeout state: ' + state.name;
                console.log(errorMessage);
                throw new Error(errorMessage);
            } else {
                return Q.delay(50).then(wait);
            }
        }).catch(function(error) {
            throw error;
        });
    }
}

【讨论】:

  • 请展示如何使用 node.js 桥接问题中提到的 PhantomJS?
  • @Vaviloff 我已经采用了桥的示例
  • 抱歉,我无法测试您的解决方案。我切换到 NightmareJS(请参阅我更新的问题)。它大大简化了我的问题。
猜你喜欢
  • 1970-01-01
  • 2019-12-26
  • 1970-01-01
  • 2011-02-18
  • 1970-01-01
  • 2016-04-29
  • 1970-01-01
  • 2020-06-20
  • 1970-01-01
相关资源
最近更新 更多