使用 nodejs 实现数据采集

nodejs yekong

最近在处理一些数据,但是为了丰富数据,所以还需要从网上抓一些数据过来,起初是手动一点一点复制的,但是数据有点多,每一组数据手动处理的话,至少需要1个小时,20多组数据2天时间下不来,实在无法忍受枯燥的复制粘贴了,于是就想可不可以通过nodejs来抓取这些数据呢?

经过1个小时的研究,终于实现了想要的效果,感觉赚了一天的时间。

请求数据

这里我们请求数据使用axios,所以需要安装一下axios,然后使用axios去请求地址,获取我们想要的信息。

安装依赖

pnpm i axios

请求数据

const urlmove = '地址'

// 请求回来的promise对象数据
function req(url) {
    return axios.get(url).then(function (data) {
        // console.log(data)
        return data
    }).catch((error) => {
        return false
    })
}

处理数据

接下来就是处理数据了,当我们使用axios请求到数据后,就需要cheerio来对这些数据进行处理了,这里我请求的数据在网页的table标签中,所以需要处理table标签,我们只需要标签中特有的数据,所以要使用indexOf过一遍,看是不是需要的,是需要的再进行下一步。因为数据都在a标签内,所以还需要使用cheerio的find标签来获取a标签内的内容。

 const $ = cheerio.load(data)
    let list = []
    $('table tbody tr td table tbody tr').each((index, el) => {
        $(el).each((index2, el2) => {
            console.log()
            var datas = $(el2).html().indexOf('关键词') != -1
            if (datas) {
                var dataInfo = {
                    name: '',
                    code: '',
                    children: []
                }
                $(el2).find('a').each(function (index3, element) {
                    if (index3 == 0) {
                        dataInfo.name = $(element).text()
                    }
                    if (index3 == 1) {
                        dataInfo.code = $(element).text()
                    }
                });
                list.push(dataInfo)
            }
        })
    })

循环抓取

数据需要三级数据,所以需要一个循环处理,为了避免对目标站点造成压力,这里我们设置一个延迟,每隔一段时间请求一次。

function sleep(n) {
    var start = new Date().getTime();//定义起始时间的毫秒数
    while (true) {
        var time = new Date().getTime();//每次执行循环取得一次当前时间的毫秒数
        if (time - start > n) {//如果当前时间的毫秒数减去起始时间的毫秒数大于给定的毫秒数,即结束循环
            break;
        }
    }
}

保存数据

数据抓取完成后,我们需要保存数据,这里我们通过fs来将数据保存到指定的json文件中。
到这里一个nodejs 采集抓取数据的流程就走完了。

完整的实例代码

for (var i = 0; i < list.length; i++) {
    var url = '网址' + list[i].code + '网址后缀/'
    console.log('开始' + list[i].name)
    list[i].children = await getErji(url)
    sleep(5000);
    for (var s = 0; s < list[i].children.length; s++) {
        var url2 = '网址' + list[i].children[s].code + '网址后缀/'
        list[i].children[s].children = await getErji(url2)
        console.log(list[i].children[s].children)
        sleep(5000);
    }
}
const axios = require('axios')
const cheerio = require('cheerio')
const fs = require('fs')
// 需要引入的模块
var list = []
const urlmove = '地址'

// 请求回来的promise对象数据
function req(url) {
    return axios.get(url).then(function (data) {
        // console.log(data)
        return data
    }).catch((error) => {
        return false
    })
}

function sleep(n) {
    var start = new Date().getTime();//定义起始时间的毫秒数
    while (true) {
        var time = new Date().getTime();//每次执行循环取得一次当前时间的毫秒数
        if (time - start > n) {//如果当前时间的毫秒数减去起始时间的毫秒数大于给定的毫秒数,即结束循环
            break;
        }
    }
}

// 获取主页nav内容的函数
async function getHome() {
    const {data} = await req(urlmove)
    const $ = cheerio.load(data)
    let list = []
    $('table tbody tr td table tbody tr').each((index, el) => {
        $(el).each((index2, el2) => {
            console.log()
            var datas = $(el2).html().indexOf('关键词') != -1
            if (datas) {
                var dataInfo = {
                    name: '',
                    code: '',
                    children: []
                }
                $(el2).find('a').each(function (index3, element) {
                    if (index3 == 0) {
                        dataInfo.name = $(element).text()
                    }
                    if (index3 == 1) {
                        dataInfo.code = $(element).text()
                    }
                });
                list.push(dataInfo)
            }
        })
    })
    return list
}

// 获取二级数据
async function getErji(url) {
    const {data} = await req(url)
    const $ = cheerio.load(data)
    let list = []
    $('table tbody tr td table tbody tr').each((index, el) => {
        $(el).each((index2, el2) => {
            // console.log($(el2).html())
            var datas = $(el2).html().indexOf('关键词查询') != -1 && $(el2).html().indexOf('全国') == -1
            if (datas) {
                var dataInfo = {
                    name: '',
                    code: '',
                    children: []
                }
                $(el2).find('a').each(function (index3, element) {
                    if (index3 == 0) {
                        dataInfo.name = $(element).text()
                    }
                    if (index3 == 1) {
                        dataInfo.code = $(element).text()
                    }
                });
                console.log(dataInfo)
                list.push(dataInfo)
            }
        })
        console.log(list)

    })
    return list
}

// 获取每一个导航的数据
async function main() {
    // 一级数据
    let list = await getHome()
    console.log(list)
    // return
    sleep(3000);
    // 二级数据
    for (var i = 0; i < list.length; i++) {
        var url = '网址' + list[i].code + '网址后缀/'
        console.log('开始' + list[i].name)
        list[i].children = await getErji(url)
        sleep(5000);
        for (var s = 0; s < list[i].children.length; s++) {
            var url2 = '网址' + list[i].children[s].code + '网址后缀/'
            list[i].children[s].children = await getErji(url2)
            console.log(list[i].children[s].children)
            sleep(5000);
        }
    }
    console.log(list)
    fs.writeFile('./data.json', JSON.stringify(list), function (err) {
        if (err) {
            return console.log("文件写入失败" + err.message)
        }
        console.log("文件写入成功")
    })
}

//调用函数
main()

喜欢