美文网首页
nodejs爬取微信热文并分析关键字

nodejs爬取微信热文并分析关键字

作者: 哭不是罪 | 来源:发表于2020-04-30 16:04 被阅读0次

前两天忽然想爬取微信热文,分析一下关键字,看最近热文都在关注什么话题。

本来想完全用html+js实现的,但是爬取文章数据绕不过跨域拦截问题,我也暂时没找到好的处理方案,所以还是放在nodejs中做爬数据的事了。

爬取的网站是微小宝,我没做登录,最多爬取50篇文章。

分词模块换了3个:segment、novel-segment、nodejieba
segment 文章字数稍微多点,分词过程中就会出现内存溢出的情况,还需要使用--max-old-space-size配置更大的内存。
novel-segment 解决了内存溢出的问题但是分词模块感觉有误,虽然中文难以分词,但是你这分的也太随性了吧。
nodejieba 解决了以上两个问题,虽然依然存在分词不准确的情况,但是相比前两个已经很好了。

安装nodejieba 出现了一些小插曲,根据这篇文章解决了 https://blog.csdn.net/fengxiaoxiao_1/article/details/77073918

效果图:


image.png

可以看出目前最热的话题还是疫情相关信息,当然跟抓取的时间也有很大关系。上午我抓取的时候,最热的话题还是芯片,因为最近美国疫情的问题都没空解决又忙于制裁华为了。

代码如下:
html部分:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div class="box">
        <div class="form">
            <div>
                <label for="">抓取文章数:</label>
                <input id="page-size" type="number" placeholder="请输入抓取的文章数,默认为1"><button id="submit">提交</button>
            </div>
        </div>
        <div class="echarts-box">
            <div id="wait" style="display:none;">请求数据中,请耐心等待......</div>
            <div id="main" style="width: 1400px;height:500px;display:none;"></div>
        </div>
    </div>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/4.7.0/echarts.min.js"></script>
    <script>
        $(document).ready(function () {
            // 初始化图表
            function initEcharts(xAxisData, seriesData) {
                var myChart = echarts.init(document.getElementById('main'));
                var option = {
                    title: {
                        text: '微信公众号热文关键词'
                    },
                    tooltip: {},
                    xAxis: {
                        name: '关键词',
                        data: xAxisData,
                        axisLabel: {
                            interval: 0
                        },
                    },
                    yAxis: {},
                    series: [{
                        type: 'bar',
                        data: seriesData,
                        itemStyle: {
                            normal: {
                                label: {
                                    show: true,
                                }
                            }
                        }
                    }]
                };
                myChart.setOption(option);
            }

            // 发起请求获取数据
            function ajaxSubmit() {
                const waitEl = document.querySelector("#wait");
                const echartsEl = document.querySelector("#main");
                const pageSize = $('#page-size').val()
                waitEl.style.display = "block";
                echartsEl.style.display = "none";
                $.ajax({
                    type: 'get',
                    url: 'http://127.0.0.1:8000/',
                    data: {
                        pageSize: pageSize > 50 ? 50 : (pageSize || 1)
                    },
                    success(res) {
                        if (res.code === 0) {
                            let resultArr = res.data;
                            resultArr.sort(function (a, b) {
                                return b.count - a.count
                            })
                            resultArr = resultArr.slice(0, 25)
                            const wordArr = resultArr.map(item => item.word);
                            const countArr = resultArr.map(item => item.count);
                            initEcharts(wordArr, countArr);
                            waitEl.style.display = "none";
                            echartsEl.style.display = "block";
                        }
                    }
                })
            }

            // 点击按钮事件
            $('#submit').click(ajaxSubmit)
        })
    </script>
</body>

</html>

nodejs部分如下:

const express = require("express");
const axios = require("axios");
var nodejieba = require("nodejieba"); // 分词模块
const cheerio = require("cheerio"); // 解析dom模块
const app = express();


const config = {
    port: 8000,
    url: (pageSize) => `https://data.wxb.com/rank/article?baidu_cat=%E6%80%BB%E6%A6%9C&baidu_tag=&page=1&pageSize=${pageSize}&type=2&order=`
}

app.all('*', function (req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Content-Type');
    res.header('Access-Control-Allow-Methods', '*');
    res.header('Content-Type', 'application/json;charset=utf-8');
    next();
});

// 请求文章链接
function reqArticleUrl(pageSize) {
    console.log('开始爬取文章列表...----------------------start-------------------------');
    return new Promise((resolve, reject) => {
        axios.get(config.url(pageSize))
            .then(res => {
                if (res.data.errcode === 0) {
                    resolve(res)
                }
            })
            .catch(err => {
                reject(err)
            })
    })
}

// 获取处理后文章字符串
async function reqArticleData(urlArr) {
    console.log('开始爬取文章内容...');
    return new Promise((resolve, reject) => {
        let pAllArr = [];
        urlArr.forEach((el, i) => {
            pAllArr.push(reqUrl(el.url))
        })
        Promise.all(pAllArr).then(res => {
            resolve(res.join(""))
        })
    })
}

// 请求具体文章内容
function reqUrl(url) {
    return new Promise((resolve, reject) => {
        axios.get(url).then(res => {
            let $ = cheerio.load(res.data);
            let text = htmlDecode($('#js_content').text().replace(/[\r\n]/g, "").replace(/\s+/g, ""));
            resolve(text)
        })
    })
}

// Unicode编码转为汉字
function htmlDecode(str) {
    str = unescape(str.replace(/\\u/g, "%u"));
    str = str.replace(/&#(x)?(\w+);/g, function ($, $1, $2) {
        return String.fromCharCode(parseInt($2, $1 ? 16 : 10));
    });
    return str;
}

// 将文章进行分词处理
async function packageData(str) {
    return new Promise((resolve, reject) => {
        console.log('开始分词...');
        var arr = nodejieba.tag(str)
        console.log('分词结束...');
        var myarr = [];
        console.log('筛选特定符号中...');
        arr.forEach(e => {
            if (e.tag === 'n' && e.word.length > 1) {
                // 只保留两字以上的名词 
                myarr.push(e.word)
            }
        });
        console.log('计算单次个数中...');
        var myJson = {};
        myarr.forEach(data => {
            if (!myJson[data]) {
                myJson[data] = 1;
            } else {
                myJson[data]++;
            }
        });
        console.log('去掉1次以下词语');
        var arr2 = [];
        for (var word in myJson) {
            if (myJson[word] <= 1) {
                continue;
            }
            arr2.push({ word, count: myJson[word] });
        }
        arr2.sort((json1, json2) => json2.c - json1.c);
        resolve(arr2)
    })
}

app.get('/', async function (req, res) {
    let pageSize = req.query.pageSize || 1;
    const result = await reqArticleUrl(pageSize);
    const result2 = await reqArticleData(result.data.data);
    console.log('未分词前文章长度', result2.length);
    const data = await packageData(result2)
    console.log('处理完毕,返回数据----------------------end-------------------------');
    res.send({ code: 0, data })
});

app.listen(config.port, () => {
    console.log(`${config.port}端口服务已启动`);
});

如有错误还请指出

相关文章

网友评论

      本文标题:nodejs爬取微信热文并分析关键字

      本文链接:https://www.haomeiwen.com/subject/ysbgwhtx.html