我正在研究通过Puppeteer和Cheerio实现的Web抓取节点服务器。
我有前端React应用程序使用Soundcloud-widget播放音乐,但问题是该API仅与正确的Soundcloud URL一起使用。
因此,我正在输入UI以通过Scraper在SoundCloud搜索上发送请求,并从那里获取结果。
因为我只关心URL和歌曲名称,是从剪贴簿中获得的
$(a.soundTitle__title)
将名称保留在子span标记中(在他的“ class” attr处),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 ...},未定义/此默认响应/错误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的屏幕截图,也许我在这里做错了吗?
提前感谢!
您不能使用cheerio来抓取诸如Soundcloud之类的Web应用程序,因为该网站通过Javascript和XHR JSON Request(AJAX)发挥了巨大作用。推荐的替代方案:PUPPETEER,因为此无头浏览器几乎可以运行任何Javascript(当然,这是没有GUI的Chrome,当然也有一些限制)。
Soundcloud标题生成仅在页面滚动时产生,因此您需要每隔一段时间使用setInterval运行自动滚动功能。
您可以通过选择选择器或通过侦听页面请求事件并“监视”结果来查询结果。我最好选择第二个,因为这很顺利,没有任何选择器。
因为您只需要歌曲的URL和标题,所以我编写了此脚本。尝试并根据需要对其进行修改。
您可以更改搜索查询和最高代码中的最大结果。即使您可以使用搜索查询作为参数来运行此脚本。例如:$ 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)')
})()