nodejs 爬取前端面經並生成詞雲
阿新 • • 發佈:2019-01-27
前言
最近有 CVTE 的面試但是一直沒有到我,昨天下午牛客網上 CVTE 前端的面經突然多了起來,大致看了一下,和自己之前整理的知識點差的不多,但是基本都問了 nodejs 的問題。正好之前的爬蟲都沒有做過詞雲,藉著這個機會爬一下牛客網的前端面經,順便生成詞雲,看看面試中哪些比較重要
準備工作
基本的步驟前面幾篇爬蟲都有了,不過還是重寫寫一下吧。
- 建立一個資料夾,我這裡叫 spider
- 右鍵點選這個資料夾,有個 CMD 快速通道,點選開啟 CMD
- 執行
npm init
命令,一路回車,最後 yes
執行完以後,會多出一個 package.json 的資料夾,裡面放的是一些專案的資訊 - 在 spider 資料夾下新建一個 index.js 檔案用來寫我們的程式碼。
- 建立一個 data 資料夾用於放我們所需要的資料
- 安裝專案所需要的依賴包
npm istall cheerio --save
這個是用來提取 html 頁面內容的
npm istall async --save
這個是用來非同步併發爬蟲的
npm istall node-gyp --save
這個用於編譯原生C++擴充套件模組
npm istall nodejieba --save
這個是用來分詞的
其中安裝的時候有點小坑,需要有VC++庫、python庫,可以參考這篇文章 nodejieba安裝記(Windows)
網頁結構分析
基本的準備工作做完了,下面開始分析牛客網的網頁,其實沒什麼難的,很容易分析出來我們需要的網頁在這
即類名為 discuss-main
和 clearfix
下面的第一個 <a>
元素。程式碼如下
$('li .discuss-main.clearfix').each(function(){
var title=$(this).children().first().text();
// 這裡是為了根據關鍵詞查詢,如果標題有我們設定的關鍵詞,再把連結放到陣列中
if(title.indexOf(keyWord)>=0 ){
var search=$(this).children().first().attr('href');
let nextLink = "https://www.nowcoder.com" + search;
urlList.push(nextLink);
}
})
接下來就是頁面裡面的實際內容,也很容易分析
即類名為 post-topic-des
下的文字
至此頁面分析工作做完,接下來就是使用 nodejieba 模組來分詞
分詞生成詞雲
關於 nodejieba 的用法可以參考這篇文章 使用 Node.js 對文字內容分詞和關鍵詞抽取
由於 const result = nodejieba.extract(data, 40);
得到的結果是物件,所以寫入檔案之前需要將其轉換為 JSON 字串,用 JSON.stringify(result)
。然後對字串進行處理
程式碼如下
function wordCluod(){
fs.readFile('./data/word.txt', 'utf8', function(err, data){
nodejieba.load({
userDict: './user.utf8',
});
const result = nodejieba.extract(data, 20);
let text = "";
for(let i in result){
text += text[i].word + " " + Math.ceil(text[i].weight) + "\n";
}
fs.writeFile('./data/'+'wordCloud'+'.txt',text, 'utf-8', function (err) {
if (err) {
console.log(err);
}
});
});
}
但是這樣有一個問題,因為他是根據詞頻選取的,所以有一些沒用的詞比如面試官,一面等詞語就會混入到我們的詞中,所以我們需要將有用的資訊過濾出來
const tagList = ['原型', '閉包', 'HTTP', 'CORP', 'TCP', 'https','跨域','XSS','安全','事件','VUE','CSS','演算法','執行緒','NODE'];
let textNo = JSON.stringify(result.filter(item => tagList.indexOf(item.word.toUpperCase()) >= 0));
生成資料如下
和我想象的還是有些差距的,可能程式並不是太完善,然後就可以把資料匯入到任何一個線上詞雲裡面了
完整程式碼
const https=require('https');
const fs=require('fs');
const request=require('request');
const async=require('async');
const cheerio = require('cheerio');
const nodejieba = require('nodejieba');
const startPage =0;//開始頁
const endPage = 4;//結束頁
const keyWord = "";//關鍵詞
const keyWord2 = "前端";
let page=startPage;
let i=0;
//初始url
const url={
hostname: 'www.nowcoder.com',
path: '/discuss?type=2&order=' + startPage,
headers: {
'Content-Type': 'text/html',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36',
}
}
let urlList=[];//儲存圖片頁面地址
//獲取圖片所在頁面
function getUrl(url){
//採用http模組向伺服器發起一次get請求
https.get(url,function(res){
var html='';
//res.setEncoding('binary');
//監聽data事件,每次取一塊資料
res.on('data',function(chunk){
html+=chunk;
});
res.on('end',function(){
var $ = cheerio.load(html); //採用cheerio模組解析html
$('li .discuss-main.clearfix').each(function(){
var title=$(this).children().first().text();
if(title.indexOf(keyWord2)>=0){
var search=$(this).children().first().attr('href');
//console.log(search);
let nextLink = "https://www.nowcoder.com" + search;
urlList.push(nextLink);
}
})
page++;
if(page<=endPage){
let tempUrl='https://www.nowcoder.com/discuss?type=2&order=' + page;
getUrl(tempUrl);
}else{
fetchPage();
}
})
}).on('err',function(err){
console.log(err);
})
}
function fetchPage(){
//非同步控制併發
async.mapLimit(urlList,5,function(url,callback){
https.get(url,function(res){
//console.log(url);
let html='';
//res.setEncoding('binary');
res.on('data',function(chunk){
html+=chunk;
})
res.on('end',function(){
//console.log(html);
var $ = cheerio.load(html); //採用cheerio模組解析html
var content = $('.post-topic-des').text().trim();
//console.log(content);
appendText(content);
})
}).on('err',function(err){
console.log(err);
});
callback(null,'成功');
},
function(err,result){
if (err){
console.log(err)
}
else{
console.log('結束');
wordCluod();
}
})
}
function appendText(text){
fs.appendFile('./data/word.txt', text, 'utf-8', function (err) {
if (err) {
console.log(err);
}
});
}
// 生成詞雲資料
function wordCluod(){
fs.readFile('./data/word.txt', 'utf8', function(err, data){
nodejieba.load({
userDict: './user.utf8',
});
const result = nodejieba.extract(data, 120);
const tagList = ['原型', '閉包', 'HTTP', 'CORP', 'TCP', 'HTTPS','跨域','XSS','安全','事件迴圈','VUE','CSS','演算法','執行緒','NODE','','快取','記憶體','作用域鏈','垂直居中','佈局','狀態碼','原型鏈','ES6','箭頭函式',"PROMISE",'垃圾回收','優化'];
let textNo = JSON.stringify(result.filter(item => tagList.indexOf(item.word.toUpperCase()) >= 0));
let text = JSON.parse(textNo);
let temp = "";
for(let i in text){
temp += text[i].word + " " + Math.ceil(text[i].weight) + "\n";
}
fs.writeFile('./data/'+'wordCloud'+'.txt',temp, 'utf-8', function (err) {
if (err) {
console.log(err);
}
});
});
}
getUrl(url);//主程式開始執行
效果圖
最終效果如圖所示