从Cheerio的剪贴簿页面获取信息

时间:2019-11-07 13:20:09

标签: node.js puppeteer cheerio html-parser

我正在研究使用Puppeteer和Cheerio实现的Web抓取节点服务器。

我有一个前端React应用程序使用Soundcloud-widget播放音乐,但事实是该API仅适用于正确的Soundcloud URL。

因此,我正在输入UI,以便通过Scraper在SoundCloud搜索上发送请求,并从那里获取结果。

因为我只关心URL和歌曲名称,是从剪贴簿中获取的


$(a.soundTitle__title)

将名称保留在子span标记中(在他的“ class”属性中),并将URL作为href足够。

问题是我要得到


{
 options: {
  withDomLvl1: true,
  normalizeWhitespace: false,
  xml: false,
  decodeEntities: true
},
length: 0,
prevObject: {
  options: {
   withDomLvl1: true,
   normalizeWhitespace: false,
   xml: false,
   decodeEntities: true
  }
 }
}

是跨度/歌曲名称的默认cheerio输出, 和href网址的“未定义”。

即使我尝试使用{.text()/ .attr(“ class”)/ etc ...}, undefind /此默认响应/错误text()不是函数

这是我的代码-


... req

const addaptReq = req.text.replace(' ', '%20');  
const url = `https://soundcloud.com/search?q=${addaptReq}`;

let myBrowser;

puppeteer
 .launch()
 .then(browser => {
     myBrowser = browser;
     return myBrowser.newPage();
   })
 .then(page => {
     return page.goto(url).then(() => {
         return page.content();
      });
  })
 .then(html => {
      // console.log(html)
      $('a.soundTitle__title', html, ).each(result => {
        let songName = $('span', result)
        let songURL = $(result).attr('href')

        //  hopefuly name will give the span text (which is it class and href the URL)


          console.log(songName, songURL)

      })
   }).then(() => {
       myBrowser.close()
   })
  .catch(err => {
      console.log(err);
   });

我用devtools附加了soundcloud的屏幕截图,也许我在那儿做错了什么?

提前谢谢!

soundcloud screenshot

1 个答案:

答案 0 :(得分:0)

  1. 您不能使用cheerio来抓取诸如Soundcloud之类的Web应用程序,因为该网站通过Javascript和XHR JSON Request(AJAX)发挥了巨大作用。推荐的替代方法:PUPPETEER,因为这种无头浏览器几乎可以运行任何Javascript(当然,这是没有GUI的Chrome,当然也有一些限制)。

  2. Soundcloud标题生成仅在页面滚动时产生,因此您需要使用setInterval每次运行一次自动滚动功能。

  3. 您可以通过选择选择器或侦听页面请求事件并“窥探”结果来查询结果。我最好选择第二个,因为它工作顺利,没有任何选择器。

  4. 因为您只需要歌曲的URL和标题,所以我编写了此脚本。尝试并根据需要对其进行修改。

  5. 您可以使用大写代码更改搜索查询和最大结果。即使您可以使用搜索查询作为参数来运行此脚本。例如:$ node search_soundcloud.js“ iris goo goo dolls”。如果您在此处未传递参数,则它将搜索“ goo goo dolls”作为脚本默认值。

const puppeteer = require ('puppeteer')

;(async () => {
    const input = process.argv.length < 3 ? 'goo goo dolls' : process.argv[2]
    const maximumSongs = 100
    const titlesArray = []
    const searchquery = input.split(' ').join('%20')
    const url = `https://soundcloud.com/search?q=${searchquery}`

    const browser = await puppeteer.launch({
        headless: true,
        devtools: false
    })
    const [page] = await browser.pages()
    page.setDefaultNavigationTimeout(0)

    page.setRequestInterception(true)

    page.on('request', async request => {
        if (request.resourceType() === 'font' ||
            request.resourceType() === 'image' ||
            request.resourceType() === 'media' ){
            request.abort()
        } else {
            request.continue()
        }
    })

    page.on('requestfinished', async request => {
        if ( request.url().search('https://api-v2.soundcloud.com/search?') > -1 ) {
            const response = await request.response()
            const content = await response.json()
            const songs = content.collection
            for ( let num in songs ) {
                if (titlesArray.length < 100 && typeof songs[num].title !== 'undefined') {
                    console.log ( `[${titlesArray.length + 1}]  ${songs[num].title}` )
                    console.log ( `${songs[num].permalink_url}\n` )
                    titlesArray.push ( songs[num].title )
                } else if (typeof songs[num].title !== 'undefined') {
                    const exit = await browser.close()
                }
            }
        }
    })

    const search = await page.goto(url, {waitUntil: 'networkidle2'})

    const scroll = await page.evaluate ('const autoscroll = setInterval( () => {window.scrollBy(0,100)}, 250)')

})()