【问题标题】:Cheerio problems on parsing html by selectors选择器解析 html 的 Cheerio 问题
【发布时间】:2015-12-25 00:19:33
【问题描述】:
    var request = require('request');
    var cheerio = require('cheerio');

    request('http://www.gatherproxy.com/proxylist/anonymity/?t=Elite', function (error, response, html) {
      if (!error && response.statusCode == 200) {
        var $ = cheerio.load(html);

        var temp = $('#tblproxy tbody tr.loading-row')

        console.log(temp.attr('class'))

      }
    });

网页在http://www.gatherproxy.com/zh/proxylist/anonymity/?t=Elite

我想得到这个元素,它的选择器是#tblproxy > tbody > tr.loading-row

我在谷歌控制台尝试了同样的事情,

var s = $('#tblproxy > tbody > tr.loading-row')
undefined
s.attr('class')
"loading-row"

但它在cheerio 的上下文中不起作用,程序的输出是未定义的,知道吗?

【问题讨论】:

    标签: javascript jquery node.js selector cheerio


    【解决方案1】:

    我注意到您尝试查询的元素tbody 是异步加载的。这超出了request 模块的能力范围。您可以使用 phantomjs 以无头方式模拟网页并从网页模块中获取 html。如果您想创建更多自定义网页模块,可以参考phantomjs documentation

    分叉这个github repo demo

    首先,创建一个网页模块来获取特定页面的html。

    phantom/request.js

    'use strict';
    
    var page = require('webpage').create();
    var system = require('system');
    
    page.open(system.args[1], function(status) {
    
        console.log(page.evaluate(function() {
            return document.documentElement.innerHTML;
        }));
    
        phantom.exit();
    
    });
    

    其次,为phantom 目录中的所有网页模块创建一个phantomjs cli 包装器。

    lib/phantom.js

    'use strict';
    
    var path = require('path');
    var spawn = require('child_process').spawn;
    var phantomjs = require('phantomjs');
    var fs = require('fs');
    var binPath = phantomjs.path;
    var slice = Array.prototype.slice;
    
    var phantomPath = path.join(
        __dirname,
        '..',
        'phantom'
    );
    
    exports = module.exports = function() {
    
        var args = slice.call(arguments);
        var callback = args.pop();
    
        var command = spawn(binPath, args);
    
        command.stdout.on('data', function(data) {
            callback(null, data.toString());
        });
    
        command.stderr.on('data', function(data) {
            callback({ message: data.toString() }, null);
        });
    
    };
    
    // create methods base on the ./phantom directory web page modules
    fs.readdirSync(phantomPath).reduce(function(context, filename) {
    
        var index = path.basename(filename, '.js');
    
        context[index] = function() {
            exports.apply(null, [path.join(phantomPath, filename)].concat(slice.call(arguments)));
        };
    
    }, exports);
    

    最后,使用lib/phantom.js脚本的request方法获取html页面。

    index.js

    'use strict';
    
    var phantom = require('./lib/phantom');
    var cheerio = require('cheerio');
    
    var address = 'http://www.gatherproxy.com/proxylist/anonymity/?t=Elite';
    
    phantom.request(address, function(err, html) {
    
        if(err) {
            console.log('error');
            return;
        }
    
        var $ = cheerio.load(html);
    
        var temp = $('#tblproxy tbody tr.loading-row');
    
        console.log(temp.attr('class'));
    
    });
    

    【讨论】:

      【解决方案2】:

      从页面的代码源来看,#tblproxy中没有tbody,所以从选择器中去掉:

      var temp = $('#tblproxy tr.loading-row');
      

      更新

      按照bublik42的评论,如果随机出现tbody,可以使用find()

      var temp = $('#tblproxy').find('tr.loading-row');
      

      【讨论】:

      • tbody 在页面源代码中,但它是#tblproxy 内部的唯一元素。 Cheerio 以某种方式忽略了它。
      • 奇怪,我刚刚检查了 Iron (Chromium fork)、IE11、Firefox 和 Cheerio 下载的 html,看不到 tbody。
      猜你喜欢
      • 2013-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-25
      • 2015-10-07
      • 1970-01-01
      • 1970-01-01
      • 2013-05-05
      相关资源
      最近更新 更多