成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

nodeJS實現(xiàn)基于Promise爬蟲 定時發(fā)送信息到指定郵件

xuweijian / 2264人閱讀

摘要:也就是說,我的篇文章的請求對應個實例,這些實例都請求完畢后,執(zhí)行以下邏輯他的目的在于對每一個返回值這個返回值為單篇文章的內(nèi)容,進行方法處理。

英國人Robert Pitt曾在Github上公布了他的爬蟲腳本,導致任何人都可以容易地取得Google Plus的大量公開用戶的ID信息。至今大概有2億2千5百萬用戶ID遭曝光。

亮點在于,這是個nodejs腳本,非常短,包括注釋只有71行。

毫無疑問,nodeJS改變了整個前端開發(fā)生態(tài)。本文一步步完成了一個基于promise的nodeJS爬蟲程序,收集簡書任意指定作者的文章信息。并最終把爬下來結果以郵件的形式,自動化發(fā)給目標對象。千萬不要被nodeJS的外表嚇到,既是你是初入前端的小菜鳥,或是剛接觸nodeJS不久的新同學,都不妨礙對這篇文章的閱讀和理解。

爬蟲的所有代碼可以在我的Github倉庫找到,日后這個爬蟲程序還會進行不斷升級和更新,歡迎關注。

nodeJS VS Python實現(xiàn)爬蟲

我們先從爬蟲說起。對比一下,討論為什么nodeJS適合/不適合作為爬蟲編寫語言。
首先,總結一下:

NodeJS單線程、事件驅動的特性可以在單臺機器上實現(xiàn)極大的吞吐量,非常適合寫網(wǎng)絡爬蟲這種資源密集型的程序。

但是,對于一些復雜場景,需要更加全面的考慮。以下內(nèi)容總結自知乎相關問題,感謝@知乎網(wǎng)友,對答案的貢獻。

如果是定向爬取幾個頁面,做一些簡單的頁面解析,爬取效率不是核心要求,那么用什么語言差異不大。

如果是定向爬取,且主要目標是解析js動態(tài)生成的內(nèi)容 :
此時,頁面內(nèi)容是由js/ajax動態(tài)生成的,用普通的請求頁面+解析的方法就不管用了,需要借助一個類似firefox、chrome瀏覽器的js引擎來對頁面的js代碼做動態(tài)解析。

如果爬蟲是涉及大規(guī)模網(wǎng)站爬取,效率、擴展性、可維護性等是必須考慮的因素時候:
大規(guī)模爬蟲爬取涉及諸多問題:多線程并發(fā)、I/O機制、分布式爬取、消息通訊、判重機制、任務調(diào)度等等,此時候語言和所用框架的選取就具有極大意義了。具體來看:

PHP:對多線程、異步支持較差,不建議采用。
NodeJS:對一些垂直網(wǎng)站爬取倒可以。但由于分布式爬取、消息通訊等支持較弱,根據(jù)自己情況判斷。
Python:建議,對以上問題都有較好支持。

當然,我們今天所實現(xiàn)的是一個簡易爬蟲,不會對目標網(wǎng)站帶來任何壓力,也不會對個人隱私造成不好影響。畢竟,他的目的只是熟悉nodeJS環(huán)境。適用于新人入門和練手。

當然,任何惡意的爬蟲性質是惡劣的,我們應當全力避免影響,共同維護網(wǎng)絡環(huán)境的健康。

爬蟲實例

今天要編寫的爬蟲目的是爬取簡書作者:LucasHC(我本人)在簡書平臺上,發(fā)布過的所有文章信息,包括:每篇文章的:

發(fā)布日期;

文章字數(shù);

評論數(shù);

瀏覽數(shù)、贊賞數(shù);
等等。

最終爬取結果的輸出如下:

以下結果,我們需要通過腳本,自動地發(fā)送郵件到指定郵箱。收件內(nèi)容如下:

以上結果只需要一鍵操作便可完成。

爬蟲設計

我們的程序一共依賴三個模塊/類庫:

const http = require("http");
const Promise = require("promise");
const cheerio = require("cheerio");
發(fā)送請求

http是nodeJS的原生模塊,自身就可以用來構建服務器,而且http模塊是由C++實現(xiàn)的,性能可靠。
我們使用Get,來請求簡書作者相關文章的對應頁面:

http.get(url, function(res) {
    var html = "";
    res.on("data", function(data) {
        html += data;
    });

    res.on("end", function() {
        ...
    });
}).on("error", function(e) {
    reject(e);
    console.log("獲取信息出錯!");
});

因為我發(fā)現(xiàn),簡書中每一篇文章的鏈接形式如下:
完整形式:“http://www.jianshu.com/p/ab27...”,
即 “http://www.jianshu.com/p/” + “文章id”。

所以,上述代碼中相關作者的每篇文章url:由baseUrl和相關文章id拼接組成:

articleIds.forEach(function(item) {
    url = baseUrl + item;
});

articleIds自然是存儲作者每篇文章id的數(shù)組。

最終,我們把每篇文章的html內(nèi)容存儲在html這個變量中。

異步promise封裝

由于作者可能存在多篇文章,所以對于每篇文章的獲取和解析我們應該異步進行。這里我使用了promise封裝上述代碼:

function getPageAsync (url) {
    return new Promise(function(resolve, reject){
        http.get(url, function(res) {
            ...
        }).on("error", function(e) {
            reject(e);
            console.log("獲取信息出錯!");
        });
    });
};

這樣一來,比如我寫過14篇原創(chuàng)文章。這樣對每一片文章的請求和處理全都是一個promise對象。我們存儲在預先定義好的數(shù)組當中:

const articlePromiseArray = [];

接下來,我使用了Promise.all方法進行處理。

Promise.all方法用于將多個Promise實例,包裝成一個新的Promise實例。

該方法接受一個promise實例數(shù)組作為參數(shù),實例數(shù)組中所有實例的狀態(tài)都變成Resolved,Promise.all返回的實例才會變成Resolved,并將Promise實例數(shù)組的所有返回值組成一個數(shù)組,傳遞給回調(diào)函數(shù)。

也就是說,我的14篇文章的請求對應14個promise實例,這些實例都請求完畢后,執(zhí)行以下邏輯:

Promise.all(articlePromiseArray).then(function onFulfilled (pages) {
    pages.forEach(function(html) {
        let info = filterArticles(html);
        printInfo(info);        
    });
}, function onRejected (e) {
    console.log(e);
});

他的目的在于:對每一個返回值(這個返回值為單篇文章的html內(nèi)容),進行filterArticles方法處理。處理所得結果進行printInfo方法輸出。
接下來,我們看看filterArticles方法做了什么。

html解析

其實很明顯,如果您理解了上文的話。filterArticles方法就是對單篇文章的html內(nèi)容進行有價值的信息提取。這里有價值的信息包括:
1)文章標題;
2)文章發(fā)表時間;
3)文章字數(shù);
4)文章瀏覽量;
5)文章評論數(shù);
6)文章贊賞數(shù)。

function filterArticles (html) {
    let $ = cheerio.load(html);
    let title = $(".article .title").text();
    let publishTime = $(".publish-time").text();
    let textNum = $(".wordage").text().split(" ")[1];
    let views = $(".views-count").text().split("閱讀")[1];
    let commentsNum = $(".comments-count").text();
    let likeNum = $(".likes-count").text();

    let articleData = {
        title: title,
        publishTime: publishTime,
        textNum: textNum
        views: views,
        commentsNum: commentsNum,
        likeNum: likeNum
    }; 
    
    return articleData;
};

你也許會奇怪,為什么我能使用類似jQuery中的$對html信息進行操作。其實這歸功于cheerio類庫。

filterArticles方法返回了每篇文章我們感興趣的內(nèi)容。這些內(nèi)容存儲在articleData對象當中,最終由printInfo進行輸出。

郵件自動發(fā)送

到此,爬蟲的設計與實現(xiàn)到了一段落。接下來,就是把我們爬取的內(nèi)容以郵件方式進行發(fā)送。
這里我使用了nodemailer模塊進行發(fā)送郵件。相關邏輯放在Promise.all當中:

Promise.all(articlePromiseArray).then(function onFulfilled (pages) {
    let mailContent = "";
    var transporter = nodemailer.createTransport({
        host : "smtp.sina.com",
        secureConnection: true, // 使用SSL方式(安全方式,防止被竊取信息)
        auth : {
            user : "**@sina.com",
            pass : ***
        },
    });
    var mailOptions = {
        // ...
    };
    transporter.sendMail(mailOptions, function(error, info){
        if (error) {
            console.log(error);
        }
        else {
            console.log("Message sent: " + info.response);
        }
    });
}, function onRejected (e) {
    console.log(e);
});

郵件服務的相關配置內(nèi)容我已經(jīng)進行了適當隱藏。讀者可以自行配置。

總結

本文,我們一步一步實現(xiàn)了一個爬蟲程序。涉及到的知識點主要有:nodeJS基本模塊用法、promise概念等。如果拓展下去,我們還可以做nodeJS連接數(shù)據(jù)庫,把爬取內(nèi)容存在數(shù)據(jù)庫當中。當然也可以使用node-schedule進行定時腳本控制。當然,目前這個爬蟲目的在于入門,實現(xiàn)還相對簡易,目標源并不是大型數(shù)據(jù)。

本文只涉及nodeJS的冰山一角,希望大家一起探索。如果你對完整代碼感興趣,請點擊這里。

Happy Coding!

文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://systransis.cn/yun/82252.html

相關文章

  • 用Node EJS寫一個爬蟲腳本每天定時給心愛的她發(fā)一封暖心郵件

    摘要:本文首發(fā)于個人博客項目源碼,歡迎,說不定哪天脫單了就能用到了寫在前面自從用郵箱注冊了很多賬號后,便會收到諸如以下類似的郵件剛開始還以為是一張圖片,后來仔細一看不是圖片呀,好像還是呀,于是好奇寶寶我一下,查閱多篇資料后總結出怎么用前端知識和做 本文首發(fā)于個人博客:VinceBlog 項目源碼:NodeMail,歡迎star,說不定哪天脫單了就能用到了 寫在前面 自從用郵箱注冊了很多賬號后...

    zero 評論0 收藏0
  • 如何通過 Scrapyd + ScrapydWeb 簡單高效地部署和監(jiān)控分布式爬蟲項目

    摘要:支持一鍵部署項目到集群。添加郵箱帳號設置郵件工作時間和基本觸發(fā)器,以下示例代表每隔小時或當某一任務完成時,并且當前時間是工作日的點,點和點,將會發(fā)送通知郵件。除了基本觸發(fā)器,還提供了多種觸發(fā)器用于處理不同類型的,包括和等。 showImg(https://segmentfault.com/img/remote/1460000018772067?w=1680&h=869); 安裝和配置 ...

    zsirfs 評論0 收藏0
  • 部署Scrapy分布式爬蟲項目

    摘要:以上示例代表當發(fā)現(xiàn)條或條以上的級別的時,自動停止當前任務,如果當前時間在郵件工作時間內(nèi),則同時發(fā)送通知郵件。 showImg(https://segmentfault.com/img/remote/1460000018052810); 一、需求分析 初級用戶: 只有一臺開發(fā)主機 能夠通過 Scrapyd-client 打包和部署 Scrapy 爬蟲項目,以及通過 Scrapyd JS...

    techstay 評論0 收藏0
  • 周報小系統(tǒng),支持導出和郵件提醒

    摘要:并利用提供的云引擎服務實現(xiàn)在周五給全員發(fā)送郵件提醒填寫周報,周六周日分別再次對未填人員發(fā)送郵件進行填寫提醒。雖然提供的免費云引擎,本身就支持服務,但是免費版是做測試用的,會自動休眠,不夠穩(wěn)定,經(jīng)常掛掉。 This just is a README. showImg(https://segmentfault.com/img/remote/1460000013260535);showImg...

    cheng10 評論0 收藏0

發(fā)表評論

0條評論

xuweijian

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<