前情提要:客户端渲染,当前页面加载渲染完成后,拿到列表数据才能获得子页面信息,进而抓取子页面的数据
Puppeteer是一个nodeJs库,能够提取动态数据,网页抓取能力更强大。
安装依赖包
npm i puppeteer
我这里node版本v18.16.0, 安装下来的puppeteer版本是
"puppeteer": "^23.2.1",
初始化
页面入口:
(async () => {
const {page, browser} = await init()
handlePage(baseUrl, page, browser)
})()
初始化函数:
async function init(){
const browser = await puppeteer.launch({headless: false})
const page = await browser.newPage()
// 如果当前页面有访问权限,需要设置cookie
await page.setCookie({
name: 'key',
value: 'value',
domain: '.XXX.com',
path: '/'
})
return {page, browser};
}
如果页面需要登录,可以查看登录后的网页cookie,自己设置一下
开始处理页面
async function handlePage(url, page, browser){
await page.goto(url);
const id = ...; // 通过地址栏获取当前页面id
console.log(`当前页面id为${id}`);
const targetDomList = await page.$$('.dom-class')
console.log(`当前页面有${targetDomList.length}个子页面`);
const response = await axios.get(`https://www.XXX.com/XXX/XXX?a=1&b=2`)
const items = ... // 拿到接口返回的数据
const allSubUrls = []
for(let i = 0; i < items.length; i++) {
const {contentId, articleInfo} = items[i]
if(articleInfo){
allSubUrls.push(`https://www.XXX.com/XXX/${contentId}?sid=${id}`)
}
}
console.log('拿到了所有子页面地址');
console.log(allSubUrls);
await handleSubPages(allSubUrls, page, browser)
await browser.close();
}
问:这里为什么不直接点击跳转?
答:点击后页面跳转,原始的page对象不再指向当前活动的页面;由于是客户端渲染,这里直接拿到接口数据,进而拿到了子页面地址
爬取子页面数据
async function handleSubPages(urls, page, browser){
const data = [];
for (let i = 0; i < urls.length; i++) {
const url = urls[i]
await page.goto(url)
await page.waitForSelector('#dom-id') // 等待dom-id容器渲染完成
const domContent = await page.$eval('#dom-id', el => el.innerHTML)
const $ = cheerio.load(domContent) // 使用cheerio加载HTML页面
const videoNodes = $('video') // 获取节点
// console.log(`当面页面找到${videoNodes.length}个视频`);
const videoList = [];
videoNodes.each((index, node) => {
const url = $(node).attr('src')
videoList.push(url.split('?')[0])
})
data.push(...videoList)
}
console.log(data);
// 将数据写入JSON文件
fs.writeFile('./output.json', JSON.stringify(data), 'utf-8', () => {
console.log('生成json文件成功!')
})
await browser.close()
}
最后将目标数据通过 output 文件输出;
除了 puppeteer,这里还用到了 axios 和 cheerio