距離上次教程已通過了快兩週了,沒辦法啊,學業繁忙(¬、¬) (¬_¬)html
const cheerio = require('cheerio'),
$ = cheerio.load('<h2 class="title">Hello world</h2>');
$('h2.title').text('Hello there!');
$('h2').addClass('welcome');
$.html();
//=> <h2 class="title welcome">Hello there!</h2>
複製代碼
額外用法戳這裏node
const Segment = require('segment');
// 建立實例
const segment = new Segment();
// 使用默認的識別模塊及字典,載入字典文件須要1秒,僅初始化時執行一次便可
segment.useDefault();
// 開始分詞
console.log(segment.doSegment('這是一個基於Node.js的中文分詞模塊。'));
// [ { w: '這是', p: 0 },
// { w: '一個', p: 2097152 },
// { w: '基於', p: 262144 },
// { w: 'Node.js', p: 8 },
// { w: '的', p: 8192 },
// { w: '中文', p: 1048576 },
// { w: '分詞', p: 4096 },
// { w: '模塊', p: 1048576 },
// { w: '。', p: 2048 } ]
複製代碼
可是咱們通常不須要輸出詞性,也不須要輸出多餘的標點符號,因此git
const result = segment.doSegment(text, {
simple: true, //不輸出詞性
stripPunctuation: true //去除標點符號
});
// [ '這是', '一個', '基於', 'Node.js', '的', '中文', '分詞', '模塊' ]
複製代碼
更高級用法見segment程序員
所有代碼見githubgithub
基本用法也瞭解了,接下來進入正題吧╰(●’◡’●)╮算法
能夠看到img元素上面src和自定義的data-src屬性都帶有圖片地址,至於爲何再下面的代碼中我沒有獲取src的值 徹底是我太菜了◔ ‸◔?,img.eq(i).src
獲取不到值,只能 prop('data-src')
了數據庫
自定義屬性兼容性不好勁segmentfault
Internet Explorer 11+ Chrome 8+ Firefox 6.0+ Opera 11.10+ Safari 6+瀏覽器
熟悉正則的同窗,稍微分析下圖片的地址就能夠經過正則來獲取url了,如下是我給出的示例 /(https:\/\/user-gold-cdn).+?\/ignore-error\/1/g
須要注意的是/的轉義,以及惰性匹配.+?,關於惰性匹配我這裏不打算說了(稍微提一下下(//▽//),其實就是匹配符合要求的最短串),要是提及來又能夠寫一大堆了bash
想詳細瞭解的同窗能夠看看這個解釋
/** * * @param {any} $ cheerio * @param {any} request 請求函數 */
function saveImg($, request) {
const img = $('.lazyload');
const origin = request.default(); //這裏是我對request進行了一個簡單的封裝,default返回未封裝的request
for (let i = 0; i < img.length; ++i) {
//data.body.match(/(https:\/\/user-gold-cdn).+?\/ignore-error\/1/g)
let src = img.eq(i).prop('data-src');
let name = src.match(/\/.{16}\?/g) && src.match(/\/.{16}\?/g)[0].slice(1, -1); //匹配出圖片名稱
if (name) {
origin.get(src).pipe(fs.createWriteStream(`./images/${name}.png`)); //愉快的下載圖片
}
}
}
複製代碼
介紹下用的數據結構Map,用來存儲詞頻(詞-詞出現的次數)
相似於對象,也是鍵值對的集合,可是「鍵」的範圍不限於字符串,各類類型的值(包括對象)均可以看成鍵。也就是說,Object 結構提供了「字符串—值」的對應,Map 結構提供了「值—值」的對應,是一種更完善的 Hash 結構實現。若是你須要「鍵值對」的數據結構,Map 比 Object 更合適。
其實對於本文來說,鍵都爲字符串,用對象也徹底沒有問題,使用Map徹底是爲了嚐鮮 (●’◡’●)ノ 關於Map複製的解釋,這一點和對象又不同
Map複製
Object複製,做爲參數傳進構造函數並不能夠複製async function getPage(request, url) {
const data = await request.get({ url });
const $ = cheerio.load(data.body);
saveImg($, request);
//獲取內容
let length = $('p').length;
for (let i = 0; i < length; ++i) {
let result = segment.doSegment(
$('p') //大部份內容都是p標籤包裹的,這裏不作過複雜的處理
.eq(i)
.text(),
{
simple: true, //不輸出詞性
stripPunctuation: true //去除標點符號
}
);
result.forEach((item, key) => {
map.set(item, map.get(item) + 1 || 1); //1 + undefined || 1 => 1
});
}
map = sortToken(map);
}
function sortToken(map) {
const words = {}; //存儲詞
let mapCopy = new Map(map); //獲取副本,Map直接賦值應該也是地址引用,參見上文
map.forEach((value, key) => {
//分詞長度大於1
if (value !== 1 && key.length > 1) { //詞頻大於1且不是單個字的留下,單字沒有什麼號分析的吧?
words[key] = value;
}
if (value === 1) { //詞頻太低,直接刷了
mapCopy.delete(key);
}
});
const keys = Object.keys(words);
//排序
keys.sort((a, b) => {
return words[b] - words[a];
});
// 每篇文章詞頻最高的20個詞,有興趣瞭解的同窗能夠去看看top k算法(咱們是獲取前k個,它是獲取第k個,可是它這樣須要把前k個都保存下來,用來比較哪些是前k大)
// 我這個方法只是粗略的獲取詞頻最高的20個詞,實際上會有誤差,假設第一次排序,第十一個詞詞頻爲23,而第二次排序,第十個詞詞頻爲12,這樣原本以前詞頻高的反被刷了
// 但這樣的好處是節省內存(實際上是假的),真正的能夠利用最大堆和利用數據庫存儲,這樣就不用存在內存了
// 最後爬取完了,從數據庫取出數據,再參照top k思想算法得出結果
keys.slice(0, 20).forEach(item => {
console.log(item, words[item]);
});
//返回分詞中詞頻爲1的分詞
return mapCopy;
}
複製代碼
我爬取了最新評論前100個文章的內容進行了分析,得出了以上結果 能夠看到,
代碼
,
方法
,
函數
,
對象
,
執行
,
調用
,
組件
等等跟代碼有關的中文詞語都出現了 不過仍是
一個
最受歡迎,出現次數快1000次了 (」゜ロ゜)」 有興趣的同窗,可使用英文分詞進行分析,分析下程序員們寫文章喜歡寫什麼代碼
以上是我分析的一篇文章裏面的英文
還能夠再分析標題,而後還能夠改進排序算法,直接把整個article-content
(class)的text進行分析,而不是像我同樣,只是分析p標籤 (๑•̀_•́๑) ,最後用可視化工具(例如e-cahrt)把數據展現出來
喜歡的同窗能夠star哦github
以上,若有錯誤,歡迎你們指正