如何使用Cheerio刮除命名元素之间的“原始”文本节点

时间:2019-04-21 18:59:10

标签: node.js web-scraping cheerio textnode

Cheerio不喜欢没有适当标签的html(实际上是谁?)。我正在尝试抓取一些菜单,并且我想要的内容在html中的元素之间。有没有一种方法可以解析这些文件,并使用cheerio将它们另存为大块?菜单是5天菜单,下面每天都有不同的课程。元素(天)与菜单项处于同一级别(兄弟姐妹)。

这是棘手的部分:菜单项没有任何属性。这是一个“原始”文本节点。

我无法更改html。

这是html结构,请注意原始文本节点是“标头”的同级。

<div class="meny" style="clear:left;line-height:1.6em;padding-bottom:2em;">
    <strong>Måndag</strong>
    <br>Klassisk wallenbergare på kalvfärs serveras med gräddsås, lingonsylt, och potatismos
    <br>Dragonbrässerad fiskfilé serveras med basilika och ruccolacrème samt kokt potatis
    <br>Pasta med strimlad ryggbiff, champinjoner och lök i krämig grönpepparsås
    <br>Pasta vegetale med rostad paprika, lök och purjolök i krämig örtsås
    <br>Grillad högrevsburgare serveras med ost, bacon, briochebröd och country fries
    <br>
    <br><strong>Tisdag</strong>
    <br>Stekt fläsk med löksås, bruna bönor eller raggmunk och lingon
    <br>Thailändsk biffgryta med citrongräs, kokosgrädde, limeblad, wokgrönsaker och rödcurry
    <br>Hollandaisebakad torskfilé på purjolöksbädd serveras med vitvinssås och kokt potatis
    <br>Pasta penne med bacon, ädelost, champinjoner, blomkål och grädde
    <br>Vegetarisk Thaigryta serveras med jasminris
    <br>Grillad högrevsburgare serveras med ost, bacon, briochebröd och country fries
    <br>
    <br><strong>Onsdag</strong>
    <br>Kycklingschnitzel serveras med barbequesås och rostad kulpotatis
    <br>Honung och enbärsbakad laxfilé serveras med citruscrème och örtslungad potatis
    <br>Pasta med strimlad kycklingfilé i rosmarin och citronsås
    <br>Karibisk falafelrulle med salsa och vitlöksdressing
    <br>Grillad högrevsburgare serveras med ost, bacon, briochebröd och country fries
    <br>
    <br><strong>Torsdag</strong>
    <br>Grillad karréskiva serveras med bearnaisesås och klyftpotatis
    <br>Stekt dubbelpanerad fiskfilé serveras med dill och rödlöksröra
    <br>Pasta med strimlad fläskfilé, paprika och lök i krämig gorgonzolasås
    <br>Grillad högrevsburgare serveras med ost, bacon, briochebröd och country fries
    <br>
    <br><strong>Fredag</strong>
    <br>LÅNGFREDAG STÄNGT</div>

所需的json输出,“ day”用于i18n ...

weekMenu = {
            name: "menuname",


            weekDayMenus: {
                monday: {
                    day: "",
                    dayMenu: "",
                },
                tuesday: {
                    day: "",
                    dayMenu: "",
                },
                wednesday: {
                    day: "",
                    dayMenu: "",
                },
                thursday: {
                    day: "",
                    dayMenu: "",
                },
                friday: {
                    day: "",
                    dayMenu: "",
                },
            }
        };

这是我到目前为止尝试过的,不用说,它不起作用,因为它仅输出标头。它不包含带有content()的文本节点子级,因为它们是同级而不是子级。

cheeriojs

   var a = $('div.meny')
                    .clone()
                    .remove().eq(0) //remove second menu div    
                    .find('strong').eq(0) //point to first 'day'
                    .siblings() //select the other days
                    .remove() //remove the other days
                    .end() //move pointer back to the start


                    .contents() //get the text nodes associated with the selected 'header'
                    .filter(function (idx, elem) {
                        console.log(elem.data)
                        return elem.type === 'text';
                    })
                    .end()
                    .text()

2 个答案:

答案 0 :(得分:0)

这就是我要做的:

let menu = $('strong').map((i, strong) => {
  return {
    name: $(strong).text(),
    weekDayMenus: {
      monday: {
        day: "",
        dayMenu: $(strong).next()[0].nextSibling.data.trim(),
      },
      tuesday: {
        day: "",
        dayMenu: $(strong).next().next()[0].nextSibling.data.trim(),
      },
    }
  }
}).get()

因此,解释是next()提供了一个cheerio节点,因此您想要next()[0]是一个javascript节点,而那些具有nextSibling(可以是文本节点)的节点

最后一个似乎没有完整的菜单,因此您需要添加异常处理。

答案 1 :(得分:0)

解决方案:

///function
let menu = $('div.meny').slice(0, 1).children('strong').map((i, strong) => {

                    var nodez = getNextSiblings.getAll($(strong)[0])

                    const dayMenuToReturn = []
                    for (var i = 0; i < nodez.length; i++) {

                        if (nodez[i].type === "text") {
                            dayMenuToReturn.push(nodez[i].data)
                        }

                        if (nodez[i].name === "strong") {
                            break
                        }
                    }

                    return {
                        day: $(strong).text(),
                        dayMenu: dayMenuToReturn
                    }
                }).get()
///GetNextSiblings.js
exports.getAll = function (el) {
    var siblings = [];
    while (el = el.nextSibling) {
        siblings.push(el)
    }
    return siblings;
}

输出:

[
    {
        "day": "Måndag",
        "dayMenu": [
            "ANNANDAG PÅSKSTÄNGT!!"
        ]
    },
    {
        "day": "Tisdag",
        "dayMenu": [
            "Köttfärslimpa serveras med gräddsås, potatismos, lingonsylt och pressgurka",
            "Soltorkad tomatbakad sejfilé serveras med basilikasås",
            "Pasta chicken thai med kycklingfilé och grönsaker i krämig thaisås",
            "Pasta Pesto vegetale med zucchini, röd paprika och rödlök i krämig pestosås",
            "Kebabrulle serveras med fefferoni, sriracha och vitlöksdressing"
        ]
    },
    {
        "day": "Onsdag",
        "dayMenu": [
            "Italiensk kalvfärsbiff serveras med röd pestosås och basilikarostad kulpotatis",
            "Sprödbakad torskfilé serveras med skirat smör och gröna ärtor",
            "Pasta carbonara serveras med äggula, riven grand padano",
            "Indisk lins och böngryta serveras med basmatiris och mynta yoghurt",
            "Kebabrulle serveras med fefferoni, sriracha och vitlöksdressing"
        ]
    },
    {
        "day": "Torsdag",
        "dayMenu": [
            "Säsongens sista Ärtsoppa eller krämig hummersoppa serveras med pannkakor, sylt och grädde",
            "Kreolsk kycklinggryta serveras med cajunkokt ris och chiliaioli",
            "Pocherad torskfilé serveras med purjolöksås och handskalade räkor",
            "Pasta penne med strimlad kycklingfilé och grönsaker i mild gorgonzolasås",
            "Vegetarisk ärtsoppa serveras med pannkakor, sylt och grädde",
            "Kebabrulle serveras med fefferoni, sriracha och vitlöksdressing"
        ]
    },
    {
        "day": "Fredag",
        "dayMenu": [
            "Grilltallrik med karréskiva, choritzo, drumstick, bearnaisesås, barbequesås och klyftpotatis",
            "Stekt dubbelpanerad fiskfilé serveras med remouladsås och pommes frites",
            "Pasta med räkor, kräftstjärtar, fänkål och blekselleri i krämig purjolöksås",
            "Ris och quornfärsfylld paprika serveras med yoghurt och tomatsås",
            "Kebabrulle serveras med fefferoni, sriracha och vitlöksdressing"
        ]
    }
]

谢谢你的帮助,地图就是狗屎