2017-10-23 32 views
7

Próbuję złom stronę internetową za pomocą następującego kodu:Getting TypeError: selector.includes nie jest funkcją kiedy skrobanie z cheerio i jsonframe

const cheerio = require('cheerio'); 
const jsonframe = require('jsonframe-cheerio'); 

const $ = cheerio.load('https://coinmarketcap.com/all/views/all/'); 
jsonframe($); // initializes the plugin 

//exception handling 
process.on('uncaughtException', err => 
    console.error('uncaught exception: ', err)) 
process.on('unhandledRejection', (reason, p) => 
    console.error('unhandled rejection: ', reason, p)) 

const frame = { 
    "crypto": {   
     "selector": "tbody > tr", 
     "data": [{    
      "name": "td:nth-child(2) > a:nth-child(3)", 
      "url": {         
       "selector": "td:nth-child(2) > a:nth-child(3)",  
       "attr": "href"      
      }, 
      "marketcap": "tr > td:nth-child(4)", 
      "price": "tr > td:nth-child(5) > a:nth-child(1)", 
     }] 
    } 

}; 

let companiesList = $('tbody').scrape(frame); 
console.log(companiesList); 

Jednak dostaję UnhandledPromiseRejectionWarning gdy uruchomiony Powyższy przykład kodu :

(node:3890) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: selector.includes is not a function 

Jakieś sugestie co robię źle?

Doceniam twoje odpowiedzi!

UPDATE

zmieniłem mojego kodu poniżej następujący. Jednak mogę tylko złomować pierwszy element.

Jakieś sugestie, dlaczego pozostałe elementy nie zostaną złomowane?

const cheerio = require('cheerio') 
const jsonframe = require('jsonframe-cheerio') 
const got = require('got'); 


async function scrapCoinmarketCap() { 
    const url = 'https://coinmarketcap.com/all/views/all/' 
    const html = await got(url) 
    const $ = cheerio.load(html.body) 

    jsonframe($) // initializing the plugin 

    let frame = { 
     "Coin": "td.no-wrap.currency-name > a", 
     "url": "td.no-wrap.currency-name > a @ href", 
     "Symbol": "td.text-left.col-symbol", 
     "Price": "td:nth-child(5) > a", 
    } 

    console.log($('body').scrape(frame, { 
     string: true 
    })) 
} 

scrapCoinmarketCap() 
+1

Którą wersję węzła używasz? –

+1

Jakiej wersji 'jsonframe-cheerio' używasz? Sądząc po składni w twoim fragmencie, podejrzewam, że polegasz na dokumentacji lub przykładzie wersji 1.x. Najnowsza wersja 2.x wprowadziła wiele zmian. Plik readme zawiera następujące ostrzeżenie: _ "Ostrożnie, jeśli korzystasz z jsonframe z wersji 1.xx, niektóre rzeczy zostały zmienione, aby były bardziej elastyczne, szybsze w użyciu (parametry wbudowane) i bardziej znaczące w składni" ._ – Boaz

+0

@FelixKling Używam 'node --version'' v8.4.0' – mrquad

Odpowiedz

-2

Sposób cheerio.load() nie akceptuje adresów URL - wymaga HTML jako ciąg.

Chociaż nie zajrzałem do kodu źródłowego cheerio, wydaje się, że moduł próbuje przeanalizować URL jako dokument HTML, który oczywiście zawodzi i pojawiają się różne błędy.

Aby rozwiązać problem, należy najpierw załadować zawartość HTML tego adresu URL do zmiennej, a następnie przekazać tę zawartość HTML do cheerio.

Możesz to zrobić z modułami takimi jak request lub got.

Oto przykład ładowanie strony za pomocą got:

const got = require('got') 
const cheerio = require('cheerio') 

got('https://google.com') 
.then(res => { 
    const $ = cheerio.load(res.body) 
    // Continue as usual 
}) 
.catch(console.error) 
+0

Dziękuję za odpowiedź! Uprzejmie proszę o sprawdzenie, czy Twój najmniejszy przykład może pokazać złomowanie przykładowego łącza w moim pytaniu: – mrquad

+0

Jestem całkowicie pewny, że możesz skopiować/wkleić swój oryginalny skrobiący kod do' // continue jak zwykle "komentował blok." Używałeś cheerio niepoprawnie - po prostu wypróbuj go we właściwy sposób i jestem pewien, że wymyślisz resztę! –

+0

Wypróbowałem twój kod i nadal mam ten sam błąd, co powyższy komunikat! – mrquad

4

Na podstawie zaktualizowanego kodu, można zeskrobać wszystkie dane walutowe przez powtarzanie każdego tr:

$('body tr').each(function() { 
    console.log($(this).scrape(frame, { 
    string: true 
    })) 
}) 

Myślę jednak, najczystszym sposobem na zrobienie tego (jak powiedziałem w odpowiedzi another) jest użycie wzoru ramki jsonframe-cheerioList/Array, który jest dokładnie przeznaczony do wykonania:

let frame = { 
    currency: { 
    _s: "tr", // the selector 
    _d: [{ // allow you to get an array of data, not just the first item 
     "Coin": "td.no-wrap.currency-name > a", 
     "Url": "td.no-wrap.currency-name > a @ href", 
     "Symbol": "td.text-left.col-symbol", 
     "Price": "td:nth-child(5) > a" 
    }] 
    } 
} 

console.log($('body').scrape(frame, { 
    string: true 
})) 
+0

Thx za odpowiedź! Jeszcze jedno pytanie, co poleciłbyś, gdybym zrzucił również podstronę z wyodrębnionego adresu URL? Czy muszę uruchomić to poprzez 'for-loop' lub czy jest lepszy sposób w wtyczce' jsonframe'? – mrquad

+0

Nie jestem pewien, ale nie sądzę, że istnieje taka możliwość. Prawdopodobnie będziesz musiał zbudować własną funkcję rekursywną. – TGrif