我知道,那些夏天,就像青春同樣回不來。 - 宋冬野
青春是回不來了,卻是要準備渡過在西安的第三個夏天了。javascript
我發現,本身對 coding 這件事的稱呼,從敲代碼
改成 寫代碼
了。前端
emmm....敲代碼,自我感受,就像是,習慣了用 const
定義常量的我看到別人用 var
定義的常量。java
對,優雅!node
寫代碼
這三個字,顯得更爲優雅一些,更像是在創做,打磨一件精緻的做品。git
改編自 掘金站長
的一句話:程序員
子非猿,安之 coding 之樂也。
最近訪問 艾特網 的時候發現請求有點慢。github
後來通過一番檢查,發現首頁中搜索熱點須要每次去爬取百度熱搜的數據並當作接口返回給前端,因爲是服務端渲染,接口堵塞就容易出現訪問較慢的狀況。express
就想着對這個接口進行一次重構。npm
1分鐘/3分鐘/5分鐘
爬取新浪微博實時熱搜(新浪微博熱搜點擊率更高一些).json
格式的文件。json
文件的內容需求捋清楚之後就能夠開幹了。json
首先得找到目標站點,以下:(微博實時熱搜)
https://s.weibo.com/top/summary?cate=realtimehot
建立文件夾 weibo
進入文件夾根目錄
使用 npm init -y
快速初始化一個項目
建立app.js
文件
安裝如下依賴
npm i cherrio superagent -D
關於superagent
和cherrio
的介紹
superagent 是一個輕量級、漸進式的請求庫,內部依賴 nodejs 原生的請求 api,適用於 nodejs 環境。cherrio 是 nodejs 的抓取頁面模塊,爲服務器特別定製的,快速、靈活、實施的 jQuery 核心實現。適合各類 Web 爬蟲程序。node.js 版的 jQuery。
打開 app.js
,開始完成主要功能
首先在頂部引入cheerio
、superagent
以及 nodejs 中的 fs
模塊
const cheerio = require("cheerio"); const superagent = require("superagent"); const fs = require("fs");
經過變量的方式聲明熱搜的url
,便於後面 複用
const weiboURL = "https://s.weibo.com"; const hotSearchURL = weiboURL + "/top/summary?cate=realtimehot";
使用 superagent
發送get
請求superagent
的 get
方法接收兩個參數。第一個是請求的 url
地址,第二個是請求成功後的回調函數。
回調函數有倆參數,第一個參數爲 error
,若是請求成功,則返回 null
,反之則拋出錯誤。第二個參數是請求成功後的 響應體
superagent.get(hotSearchURL, (err, res) => { if (err) console.error(err); });
打開目標站對網頁中的 DOM
元素進行一波分析。
對 jQuery
比較熟的小老弟,看到下圖如此簡潔清晰明瞭的 DOM
結構,是否是有 N 種取出它每一個 tr
中的數據並 push
到一個 Array
裏的方法呢?
對!咱們最終的目的就是要經過 jQuery
的語法,遍歷每一個 tr
,並將其每一項的 熱搜地址
、熱搜內容
、 熱度值
、序號
、表情
等信息 push
進一個空數組中
再將它經過 nodejs
的 fs
模塊,寫入一個 json
文件中。
使用 jQuery
的 each
方法,對 tbody
中的每一項 tr
進行遍歷,回調參數中第一個參數爲遍歷的下標 index
,第二個參數爲當前遍歷的元素,通常 $(this)
指向的就是當前遍歷的元素。
let hotList = []; $("#pl_top_realtimehot table tbody tr").each(function (index) { if (index !== 0) { const $td = $(this).children().eq(1); const link = weiboURL + $td.find("a").attr("href"); const text = $td.find("a").text(); const hotValue = $td.find("span").text(); const icon = $td.find("img").attr("src") ? "https:" + $td.find("img").attr("src") : ""; hotList.push({ index, link, text, hotValue, icon, }); } });
在 nodejs
中,要想向上面那樣愉快的寫 jQuery
語法,還得將請求成功後返回的響應體,用 cheerio
的 load
方法進行包裝。
const $ = cheerio.load(res.text);
接着使用 nodejs
的 fs
模塊,將建立好的數組轉成 json字符串
,最後寫入當前文件目錄下的 hotSearch.json
文件中(無此文件則會自動建立)。
fs.writeFileSync( `${__dirname}/hotSearch.json`, JSON.stringify(hotList), "utf-8" );
完整代碼以下:
const cheerio = require("cheerio"); const superagent = require("superagent"); const fs = require("fs"); const weiboURL = "https://s.weibo.com"; const hotSearchURL = weiboURL + "/top/summary?cate=realtimehot"; superagent.get(hotSearchURL, (err, res) => { if (err) console.error(err); const $ = cheerio.load(res.text); let hotList = []; $("#pl_top_realtimehot table tbody tr").each(function (index) { if (index !== 0) { const $td = $(this).children().eq(1); const link = weiboURL + $td.find("a").attr("href"); const text = $td.find("a").text(); const hotValue = $td.find("span").text(); const icon = $td.find("img").attr("src") ? "https:" + $td.find("img").attr("src") : ""; hotList.push({ index, link, text, hotValue, icon, }); } }); fs.writeFileSync( `${__dirname}/hotSearch.json`, JSON.stringify(hotList), "utf-8" ); });
打開終端,輸入 node app
,可看到根目錄下多了個 hotSearch.json
文件。
雖然代碼能夠運行,也能爬取到數據並存入 json 文件。
可是,每次都要手動運行,才能爬取到當前時間段的熱搜數據,這一點都 不人性化!
最近微博熱搜瓜這麼多,咱但是一秒鐘可都不能耽擱。咱們最開始指望的是每隔多長時間 定時執行爬取
操做。瓜可不能停!
接下來,對代碼進行 小部分改造
。
因爲 superagent
請求是個異步方法,咱們能夠將整個請求方法用 Promise
封裝起來,而後 每隔指定時間
調用此方法便可。
function getHotSearchList() { return new Promise((resolve, reject) => { superagent.get(hotSearchURL, (err, res) => { if (err) reject("request error"); const $ = cheerio.load(res.text); let hotList = []; $("#pl_top_realtimehot table tbody tr").each(function (index) { if (index !== 0) { const $td = $(this).children().eq(1); const link = weiboURL + $td.find("a").attr("href"); const text = $td.find("a").text(); const hotValue = $td.find("span").text(); const icon = $td.find("img").attr("src") ? "https:" + $td.find("img").attr("src") : ""; hotList.push({ index, link, text, hotValue, icon, }); } }); hotList.length ? resolve(hotList) : reject("errer"); }); }); }
定時任務咱們可使用 node-schedule
這個 nodejs庫
來完成。
https://github.com/node-schedule/node-schedule
先安裝
npm i node-schedule -D
頭部引入
const nodeSchedule = require("node-schedule");
用法(每分鐘的第 30 秒定時執行一次):
const rule = "30 * * * * *"; schedule.scheduleJob(rule, () => { console.log(new Date()); });
規則參數:
* * * * * * ┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ │ │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun) │ │ │ │ └───── month (1 - 12) │ │ │ └────────── day of month (1 - 31) │ │ └─────────────── hour (0 - 23) │ └──────────────────── minute (0 - 59) └───────────────────────── second (0 - 59, OPTIONAL)
6 個佔位符從左到右依次表明:秒、分、時、日、月、周幾*
表示通配符,匹配任意。當 *
爲秒時,表示任意秒都會觸發,其餘類推。
來看一個 每小時的第20分鐘20秒
定時執行的規則:
20 20 * * * *
更多規則自行搭配。
使用定時任務來執行上面的請求數據,寫入文件操做:
nodeSchedule.scheduleJob("30 * * * * *", async function () { try { const hotList = await getHotSearchList(); await fs.writeFileSync( `${__dirname}/hotSearch.json`, JSON.stringify(hotList), "utf-8" ); } catch (error) { console.error(error); } });
哦對,別忘了 捕獲異常
下面貼上完整代碼(可直接 ctrl c/v):
const cheerio = require("cheerio"); const superagent = require("superagent"); const fs = require("fs"); const nodeSchedule = require("node-schedule"); const weiboURL = "https://s.weibo.com"; const hotSearchURL = weiboURL + "/top/summary?cate=realtimehot"; function getHotSearchList() { return new Promise((resolve, reject) => { superagent.get(hotSearchURL, (err, res) => { if (err) reject("request error"); const $ = cheerio.load(res.text); let hotList = []; $("#pl_top_realtimehot table tbody tr").each(function (index) { if (index !== 0) { const $td = $(this).children().eq(1); const link = weiboURL + $td.find("a").attr("href"); const text = $td.find("a").text(); const hotValue = $td.find("span").text(); const icon = $td.find("img").attr("src") ? "https:" + $td.find("img").attr("src") : ""; hotList.push({ index, link, text, hotValue, icon, }); } }); hotList.length ? resolve(hotList) : reject("errer"); }); }); } nodeSchedule.scheduleJob("30 * * * * *", async function () { try { const hotList = await getHotSearchList(); await fs.writeFileSync( `${__dirname}/hotSearch.json`, JSON.stringify(hotList), "utf-8" ); } catch (error) { console.error(error); } });
express
koa
eggjs
或者原生的 nodejs 項目中,做爲接口返回給前端。熱搜
關鍵字便可實時獲取熱搜數據。都看到這裏啦,就很棒! 點個贊
再走嘛。
程序員導航站:https://iiter.cn
下面是咱的公衆號呀 前端糖果屋
代碼 github 已開源: