【问题标题】:Scrape html with request/cheerio into js object将带有 request/cheerio 的 html 抓取到 js 对象中
【发布时间】:2015-10-15 19:02:51
【问题描述】:

Cheerio 和 js 的新手。我正在尝试将所有投手名称及其相关统计数据刮到一个 JSON 对象中,如下所示:

var pitchers = {
    name: 'Just Verlander',
    era: 6.62
    etc...
    etc...
}

这是我要抓取的 html:

<tr class="">
<td class="stat-name-width"><img src="../../style/assets/img/mlb/team-logos/tigers.png" height="20"/>  
<span class="pitcher-name">Justin Verlander</span> 
<div class="fantasy-blue inline fantasy-data pitcher-salary-fd">$7,100</div>   
<small class="text-muted pitches">(R)</small> 
<small class="text-muted matchup">(@ BOS)</small></td>
        <td class="stat-stat-width fantasy-blue fantasy-points">
        <td class="stat-stat-width">0-3</td>
        <td class="stat-stat-width">6.62</td>
        <td class="stat-stat-width">1.50</td>
        <td class="stat-stat-width">5.82</td>
        <td class="stat-stat-width">3.18</td>
        <td class="stat-stat-width">2.12</td>
        <td class="stat-stat-width">5.67</td>
        <td class="stat-stat-width">1.03x</td>
        <td class="stat-stat-width">0.96x</td>
        <td class="stat-stat-width">1.09x</td>
        <td class="stat-stat-width">0.90x</td>
</tr> 

在同一页面上大约有 30 个具有相同结构的投手。

这是我目前所拥有的:

test = $('span.pitcher-name').text();给了我所有的投手名字,而不仅仅是一个。

显然我什至没有接近...我无法弄清楚如何让投手名称的孩子与 javascript 对象相关联...任何帮助都非常感谢!

【问题讨论】:

    标签: javascript node.js cheerio


    【解决方案1】:

    你见过the documentation吗?如果你往下看,这里有大量关于如何遍历网站元素的示例。

    例如:

    $('#span.pitcher-name').next() //{['<small class="text-muted pitches">(R)</small>']}

    【讨论】:

    • 是的,我已经阅读了整个自述文件。我的问题是两个方面。我找不到选择器的正确组合来只返回我需要的数据,两个我不明白如何迭代正确的元素并填充一个可以转换为 JSON 的对象。顺便说一句,您的示例返回 DOM 元素。
    • 大多数方法返回集合,您可以像这样访问它们:$('selector').children[0] 或 $('selector').first()。从那里,您可以通过 `.text()' 获取内容。所有这些都在自述文件中进行了解释,所有向上、向下、侧向和读取对象内容的不同方式都在那里!
    • 您能给我看一个将统计信息放入键值对象的示例吗?
    【解决方案2】:

    看起来你想要的是 $().each() 函数。

    使用此函数,您可以遍历标签的每个实例并执行回调函数,如下所示:

    var someObjArr = [];
    
    $('span.pitcher-name').each(function(i, element){
    
        //Get the text from cheerio.
        var text = $(this).text();
    
        //if undefined, create the object inside of our array.
        if(someObjArr[i] == undefined){
    
            someObjArr[i] = {};
        };
    
        //Update the name property of our object with the text value.
        someObjArr[i].name = text;
    }); 
    
    $('div.pitcher-salary-fd').each(function(i, element){
    
        //Get the text from cheerio.
        var text = $(this).text();
    
        //if undefined, create the object inside of our array.
        if(someObjArr[i] == undefined){
    
            someObjArr[i] = {};
        };
    
        //Update the salary property of our object with the text value.
        someObjArr[i].salary = text;
    }); 
    
    console.log(someObjArr); //[ { name: 'Justin Verlander', salary: '$7,100' } ]
    

    这个函数最好的部分之一是它可以同步工作,所以它与 for 循环很相似,而且很容易理解。

    请记住,您可以在回调的 $(this) 部分中打印出每个的子元素。这在您需要找出需要作为标签放置的特定内容的情况下特别有用。例如:

    $('span.pitcher-name').each(function(i, element){
    
        //Return the entire element.
        var pitcherNameElement = $(this);
    
        //Prints all of the element's properties.
        console.log(pitcherNameElement); 
    
    });
    

    现在,为了检索更抽象的事物,例如所有位于同一表行中的项目数组,事情变得稍微复杂一些。为此,我们需要在表格行上使用 $().each 函数,然后检查每个孩子的班级是否匹配。这样,我们可以保持相同的索引。

    $('tr').each(function(i, element){
    
        //get all children of a table row
        var children = $(this)['0'].children;
    
        //this array will hold the matchup data
        var matchupArr = [];
    
        //class to extract
        var statClass = 'stat-stat-width';
    
        //for loop-ing the children
        for(var myInt=0; myInt<children.length; myInt++){
    
            //the next element of this child
            var next = children[myInt].next;
    
            //sometimes next is undefined
            if(next != undefined){
    
                //get the html attribs of the next element
                var attribs = next.attribs;
    
                //sometimes the next element has no attribs
                if(attribs != undefined){
    
                    //class of the next element
                    var myClass = attribs.class;
    
                    //if the next element's class if the one we want
                    if(myClass == statClass){
    
                        //push it to our matchup array
                        matchupArr.push(next.children[0].data);
                    };
                };
            };
        };
    
        //if undefined, create the object inside of our array.
        if(someObjArr[i] == undefined){
    
            someObjArr[i] = {};
        };
    
        //Update the matchup property of our object with our array.
        if(matchupArr.length >0){
            someObjArr[i].matchups = matchupArr;
        };
    });
    

    这有点小技巧,但它显示了基本概念。允许您在父 P 中对所有子 C 执行回调的方法将是对库的一个很好的补充。但是,唉,我们生活在一个不完美的世界。

    祝你好运,刮刮乐!

    【讨论】:

    • 哇。很好的答案谢谢。我已经搞砸了 20 分钟左右,它完全按照你说的做。
    • 我正在尝试对其进行一些扩展,但遇到了一些有趣的事情。当我尝试为每个投手添加统计数据时,像这样` $('td.stat-stat-width').each(function(i, element){ var text = $(this).text(); if( someObjArr[i] == undefined){ someObjArr[i] = {}; }; someObjArr[i].record = text; });` 即使一个投手有一整行的统计数据,它也会为每个投手增加一个。这有意义吗?
    • 我不确定您是否收到有关我的编辑的更新(对于 Stack Overflow 来说有点新意),所以这里有一个评论通知,以防万一。 =)
    • 谢谢泰勒!你是个天才。在过去的 5 分钟里,我从你的帮助中学到的东西比我自己一个星期学到的还要多。
    猜你喜欢
    • 2017-02-27
    • 2014-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多