超简单!nodeJs爬取豆瓣TOP250书籍

303 阅读2分钟

环境及工具

nodeJs:自行安装

cheerio:解析获取到的html信息(npm install cheerio)

https:用于请求数据

fs:将解析后的书籍信息以json格式存入文件内

项目gitee地址:xulixin/node-spider-topbooks

一,分析URL爬取规则

book.douban.com/top250?star…

当start参数为0时,获取的是排名1-25的书籍,为25时,获取的是排名26-50的书籍,以此类推......

二,爬取数据,并保存数据

由上述分析,可以制定出以下规则,先爬取第一页的数据试试。

const https = require('https')
const fs = require('fs')
const cheerio = require('cheerio')

let rank = 1 //排名
let page = 0//从第一页开始爬取,每页有25条数据
let books = []//爬取到的书籍信息

https.get(`https://book.douban.com/top250?start=${page}`,res=>{
    let data = ''
    res.on('data',chunk=>{
        data += chunk
    })
    res.on('end',()=>{
        const $ = cheerio.load(data)
        $('table .item').each(function(){
            //书籍名称
            let title = $('.pl2 a',this).attr('title')
            //星级
            let start = $('.star .rating_nums',this).text()
            //图片地址
            let img = $('.nbg img',this).attr('src')
            let inq = $('.inq',this).text()
            books.push({
                title,inq,rank,start,img
            })
            rank++
        })
        fs.writeFile('./books.json', JSON.stringify(books),function(err){
            if(!err){
                console.log('书籍信息获取完毕');
            }
        })
    })
})

运行后成功获取到数据,并存入boos.json中。

三,分页查询,获取TOP250全部书籍

我这里使用的递归方案,拿到第一页的数据后,再获取下一页的数据,防止rank乱了

const https = require('https')
const fs = require('fs')
const cheerio = require('cheerio')

let rank = 1 //排名
let page = 0//从第一页开始爬取,每页有25条数据
let books = []//爬取到的书籍信息

function getDBRank(page){
    return new Promise((resolve,reject)=>{
        https.get(`https://book.douban.com/top250?start=${page}`,res=>{
            let data = ''
            res.on('data',chunk=>{
                data += chunk
            })
            res.on('end',()=>{
                const $ = cheerio.load(data)
                $('table .item').each(function(){
                    //书籍名称
                    let title = $('.pl2 a',this).attr('title')
                    //星级
                    let start = $('.star .rating_nums',this).text()
                    //图片地址
                    let img = $('.nbg img',this).attr('src')
                    let inq = $('.inq',this).text()
                    books.push({
                        title,inq,rank,start,img
                    })
                    rank++
                    resolve(`排名第${page+1}至第${page+25}加载完毕`)
                })
            })
        })
    })
}

function getResult(page){
    if(page===250){
        fs.writeFile('./books.json', JSON.stringify(books),function(err){
            if(!err){
                console.log('书籍信息获取完毕');
            }
        })
    }else{
        getDBRank(page).then(res=>{
            console.log('res',res)
            getResult(page+25)
        })
    }
}

getResult(page)

运行,获取top250所有的书籍数据

四,下载书籍对应的图片(以下为完整代码)

封装一个getImages函数,获取图片并将其保存至downImg文件夹内,注意首先得在根目录下建一个downImg文件夹。

const https = require('https')
const fs = require('fs')
const cheerio = require('cheerio')

let rank = 1 //排名
let page = 0//从第一页开始爬取,每页有25条数据
let books = []//爬取到的书籍信息

function getDBRank(page){
    return new Promise((resolve,reject)=>{
        https.get(`https://book.douban.com/top250?start=${page}`,res=>{
            let data = ''
            res.on('data',chunk=>{
                data += chunk
            })
            res.on('end',()=>{
                const $ = cheerio.load(data)
                $('table .item').each(function(){
                    //书籍名称
                    let title = $('.pl2 a',this).attr('title')
                    //星级
                    let start = $('.star .rating_nums',this).text()
                    //图片地址
                    let img = $('.nbg img',this).attr('src')
                    let inq = $('.inq',this).text()
                    books.push({
                        title,inq,rank,start,img
                    })
                    rank++
                    resolve(`排名第${page+1}至第${page+25}加载完毕`)
                })
            })
        })
    })
}

function getResult(page){
    if(page===250){
        fs.writeFile('./books.json', JSON.stringify(books),function(err){
            if(!err){
                console.log('书籍信息获取完毕');
            }
        })
        getImages(books)
    }else{
        getDBRank(page).then(res=>{
            console.log('res',res)
            getResult(page+25)
        })
    }
}

function getImages(imgList){
    imgList.forEach(img=>{
        https.get(img.img,res=>{
            var imgData = ""
            res.setEncoding("binary"); //一定要设置response的编码为binary否则会下载下来的图片打不开
            res.on("data", function(chunk){
                imgData+=chunk;
            });
        
            res.on("end", function(){
                fs.writeFile(`./downImg/${img.rank}_${img.title}.png`, imgData, "binary", function(err){
                    if(err){
                        console.log("下载失败");
                    }
                });
            });
        })
    })
}

getResult(page)

图片也成功下载下来了!