最近我的好友在寫專案的時候經常會抱怨資料的來源,的確對於一個前端來說,資料介面資料資源永遠是Mock。網上看很多大神python,node玩的飛起。但自我感覺,並沒有一套好的流程方案可以走進我們開發的流程中。為了幫助我的好友並且需要資料的你來說,可以仔細的看看整套流程。因為我也是個前端,所以知道大家需要的是什麼以及處理的方案。那麼就跟著我一起學習下吧!
前言
學海無涯,我希望你可以跟著我的思路簡單的實現下,與其臨淵羨魚,不如退而結網。文章中我會詳細講解每一步的操作和細節,nodejs一些常用的API,以及koa2簡單的語法,大家也可以由此文開始你的koa2學習,真的很好用的一個web框架。另外文章中也會講解資料跨域請求的方案和具體實現,最後就是資料的格式化處理和基本請求。三強上場,共唱一出好戲。
技術棧
- http.request:node http 模組的request方法可以作為httpclient向伺服器發起http請求,爬蟲需要向目標連結發起http請求來獲得頁面資訊
- cheerio:通過 http 請求到的頁面資訊,由於缺乏瀏覽器的dom解析,看起來就是一段凌亂的字串,實在糟糕好在我們可以使用 cheerio 庫將其解析為 dom ,這樣我們就可以使用類似 jquery 的語法去分析頁面資訊
- koa2-static: koa-static靜態資源中介軟體,可以訪問到我們專案中的靜態資源
- koa2-cors: 實現資料跨域ajax請求,這個方法關鍵是在伺服器端進行配置
- axios + promise:由於node單執行緒的特性,不可避免的需要用到大量非同步程式設計的寫法,層層巢狀的回撥寫法已經 low 了,來試試 promise 的寫法
具體實現
一、環境搭建
建立一個新資料夾,進入之後,我們初始化生產package.json檔案
npm init -y
生成的package.json後,安裝koa包,這裡我們用npm來安裝
npm install --save koa
其他的依賴跟上面一樣的方式安裝,這裡就不展開了,寫在一起
npm install --save koa-static
npm install --save koa2-cors
複製程式碼
二、nodejs 上場
熱身,構建一個爬蟲基石
唱戲之前一定要排練好,要有劇本,每個人都應該清楚的知道自己的身份和出場時間。那麼每次上臺時都需要排練下,熱下身。這樣才能演繹一出好戲。我們也一樣,先來一端程式碼熱熱身。在我們的資料夾下新建一個demo01.js吧,然後輸入下面一端程式碼
var http = require('http') // Node.js提供了http模組,用於搭建HTTP服務端和客戶端
var url = 'http://www.runoob.com/nodejs/nodejs-tutorial.html'; //輸入任何網址都可以
http.get(url,function(res){ //傳送get請求
var html=''
res.on('data',function(data){
html += data //字串的拼接
})
res.on('end',function(){
console.log(html)
})
}).on('error',function(){
console.log('獲取資源出錯!')
})
複製程式碼
開啟終端,執行node demo01.js命令,你就會看到這個網頁所有的html結構,這也是為我們的大戲敲響了第一聲鑼鼓。
開始我們的表演
在上面我們可以得到這個網頁的所有HTML,這就以為著我們可以在這個HTML裡去尋找我們需要的資源。nodejs為此提供了一種非常快捷並且方便的cheerio API。前言部分已介紹了它的功能,這裡就直接演示怎麼操作。 引入我們的cheerio
const cheerio = require('cheerio')
引用之後我們在把它包裝一下,讓他更像jquery,jquery的有點就是對dom操作的非常的簡單
var $ = cheerio.load(html)
接下來就是去我們的html中尋找我們需要的資源了,每個人的需求都是不一樣的,這裡就以案例為主,去獲取imooc上的視訊資源。為了讓我們的主體(前面熱身提到的)可讀性良好,因此我們把這部分封裝成一個函式,接收html為引數.
function filterChapters(html) {
var $ = cheerio.load(html)
var chapters = $('.course-wrap') //在html裡尋找我們需要的資源的class
var courseData = [] // 建立一個陣列,用來儲存我們的資源
chapters.each(function(item) { //遍歷我們的html文件
var chapter = $(this)
var chapterTitle = chapter.find('h3').text().replace(/\s/g, "")
var videos = chapter.find('.video').children('li') //使用childern去獲取下個節點
var chapterData = {
chapterTitle: chapterTitle,
videos: []
}
videos.each(function(item) { //遍歷視訊中的資源,title,id, url
var video = $(this).find('.J-media-item') //同樣的方式找到我們需要的class部分
var videoTitle = video.text().replace(/\n/g, "").replace(/\s/g, "");
var id = video.attr('href').split('video/')[1]; //切割我們的href的到我們的id
var url = `http://www.imooc.com/video/${id}` // es6字串模板的方式去通過id拿到我們的視訊url
chapterData.videos.push({
title:videoTitle,
id: id,
url: url
})
})
courseData.push(chapterData)
})
return courseData //返回我們需要的資源
}
複製程式碼
採坑記錄:我們得到的資源可能有換行符或者空格符之類的,如果不去除的話後面的json格式就會出錯,而卻夾帶著\n等符號,這顯然不是我們需要的格式和資料,因此在我們.text()的時候應該把這些html自帶的\n,\t等去除。使用正則和replace API。
var videoTitle = video.text().replace(/\n/g, "").replace(/\s/g, "");
演完收工
拿到我們需要的資源之後,並不會是一個json物件的形式,因此我們還需要加工一次,
var courseData = filterChapters(html)
let content = courseData.map((o)=>{
return JSON.stringify(o) // JSON.stringify() 方法用於將 JavaScript 值轉換為 JSON 字串。
})
複製程式碼
得到我們真正想要的資源以後,接下來就是儲存它了。新建一個index.json檔案用來存放我們的資源。使用nodejs的fs去寫入我們的資料,這裡簡單介紹下fs,fs應該是node中最常用的api了,其中包含了我們很多需要的操作,比如讀,寫 下載。有興趣的同學可以看看文件fs。我們引入fs把爬下來的資料寫進我們的index.json資料夾中
fs.writeFile('./index.json',content, function(err){ //檔案路經,寫入的內容,回撥函式
if(err) throw new Error ('寫檔案失敗'+err);
console.log("成功寫入檔案")
})
複製程式碼
大功告成,我們去看看我們的成果,開啟index.json檔案我們可以看到我們拍下來的資料了
是不是我們需要的資料呢!!!竊喜竊喜。nodejs演技十分的不錯!
二、koa2上場
koa 是什麼,借用官網的一句話:koa --基於Node.js平臺的下一代web開發框架。 它很小,但擴充套件性很強。Koa給人一種乾淨利落的感覺,體積小、程式設計方式乾淨。為什麼我要用一下他呢,nodejs一樣可以完成我接下的操作。的確我們也可以用creatServer去建立一個服務,但是作為程式設計師應該去攝取新知識,尤其是好的受歡迎的,這樣才能保持與時俱進!其KOA2真的挺簡單,比起node來說。前文已匯入了koa,這裡還會直接講如何使用。不懂的同學我覺得可以看看koa官網瞭解下基本的使用。
思考一:拿到了我們需要的資源後,怎麼把它掛在到網上可以請求呢
- easyMock, 把爬下來的資料拷貝一份直接丟到Mock裡它會幫你建立一個url,就可以訪問了。
- koa2 啟動一個服務,把我們的資料掛載上去,訪問埠號
對於一個mock用到快吐的我來說,絕不能忍受爬來的資料又放到mock上。於是開啟我們的koa2之旅。
const app = new Koa()
const staticPath = './static' //靜態資料夾
app.use(static(
path.join( __dirname, staticPath) ////設定靜態檔案地址,這裡本來想用路由的但是覺得沒必要啟動。
))
app.use( async ( ctx ) => { //在我們的頁面輸出hello world,這裡只是為了演示下koa的入門。我們訪問我們的靜態資源在位址列加/index.json
ctx.body = 'hello world'
})
app.listen(3000, () => { //啟動一個3000的埠
console.log('[demo] static-use-middleware is starting at port 3000')
})
複製程式碼
思考二: 興高采烈的那著我的埠去請求資料,發現
不能跨域訪問,這怎麼搞。爬下的資料弄了半天,被chroml攔截。ajax跨域訪問是一個老問題了,解決方法很多,比較常用的是JSONP方法,JSONP方法是一種非官方方法,而且這種方法只支援GET方式,不如POST方式安全。因此我們選擇在伺服器端更改,引用我們的koa2-cors。koa2-cors 的自我理解:
CORS將請求分為簡單請求和非簡單請求,可以簡單的認為,簡單請求就是沒有加上額外請求頭部的get和post請求,並且如果是post請求,請求格式不能是application/json(因為我對這一塊理解不深如果錯誤希望能有人指出錯誤並提出修改意見)。而其餘的,put、post請求,Content-Type為application/json的請求,以及帶有自定義的請求頭部的請求,就為非簡單請求。簡單請求的配置十分簡單,如果只是完成響應就達到目的的話,僅需配置響應頭部的Access-Control-Allow-Origin即可
解決問題
app.use(cors({
origin: function(ctx) {
if (ctx.url === '/index') {
return false;
}
return '*';
},
複製程式碼
三、axios上場
由於本文重在介紹爬蟲並且我最近在寫一個vue專案就用這個演示下axios的基本請求,想了解更多axios可以去axios github上理解更多的用法。
methods: {
getdata () {
axios.get('http://localhost:3000/index.js',{ //訪問我們建立的埠
dataType: 'json',
contentType:"application/json",
crossDomain: true,
})
.then(function(response){
console.log(response.data);
})
.catch(function(err){
console.log(err);
});
}
},
mounted () {
this.getdata() //可以用async/awiter讓你的請求變得更優雅,這裡就不做處理。主要是太懶了...
}
複製程式碼
請求完資料,我們在控制檯列印輸出了我們的data
結束語:
三者一起的功力實在是太強悍了。讓我們看到了一出精彩絕倫的好戲。你看到這裡說明你也是想要了解的。那為什麼不自己動手實現下,我的專案在我github上,你可以clone下來,其實併發不了多少時間的。可以解決以後你資料來源的煩惱,何樂而不為呢?你也可以跟著整篇文章的思路自己實現,期待你更優秀的作品和我分享。歡迎在下方評論以及留言。我是個大三的孩子,(不能說孩子要說學生)最近在找實習公司。希望有推薦的也可以介紹介紹。下篇文章我會推出我的vue實戰作品。你也可以關注我,跟我一起學習。樂與分享,收穫友誼。