使用 Node.js 開發(fā)資訊爬蟲流程
最近項(xiàng)目需要一些資訊,因?yàn)轫?xiàng)目是用 Node.js 來寫的,所以就自然地用 Node.js 來寫爬蟲了
項(xiàng)目地址:github.com/mrtanweijie… ,項(xiàng)目里面爬取了 Readhub 、 開源中國 、 開發(fā)者頭條 、 36Kr 這幾個(gè)網(wǎng)站的資訊內(nèi)容,暫時(shí)沒有對(duì)多頁面進(jìn)行處理,因?yàn)槊刻炫老x都會(huì)跑一次,現(xiàn)在每次獲取到最新的就可以滿足需求了,后期再進(jìn)行完善
爬蟲流程概括下來就是把目標(biāo)網(wǎng)站的HTML下載到本地再進(jìn)行數(shù)據(jù)提取。
一、下載頁面
Node.js 有很多http請(qǐng)求庫,這里使用 request ,主要代碼如下:
requestDownloadHTML () {
const options = {
url: this.url,
headers: {
'User-Agent': this.randomUserAgent()
}
}
return new Promise((resolve, reject) => {
request(options, (err, response, body) => {
if (!err && response.statusCode === 200) {
return resolve(body)
} else {
return reject(err)
}
})
})
}
使用 Promise 來進(jìn)行包裝,便于后面使用的時(shí)候用上 async/await 。因?yàn)橛泻芏嗑W(wǎng)站是在客戶端渲染的,所以下載到的頁面不一定包含想要的HTML內(nèi)容,我們可以使用 Google 的 puppeteer 來下載客戶端渲染的網(wǎng)站頁面。眾所周知的原因,在 npm i 的時(shí)候 puppeteer 可能因?yàn)樾枰螺dChrome內(nèi)核導(dǎo)致安裝會(huì)失敗,多試幾次就好了:)
puppeteerDownloadHTML () {
return new Promise(async (resolve, reject) => {
try {
const browser = await puppeteer.launch({ headless: true })
const page = await browser.newPage()
await page.goto(this.url)
const bodyHandle = await page.$('body')
const bodyHTML = await page.evaluate(body => body.innerHTML, bodyHandle)
return resolve(bodyHTML)
} catch (err) {
console.log(err)
return reject(err)
}
})
}
當(dāng)然客戶端渲染的頁面最好是直接使用接口請(qǐng)求的方式,這樣后面的HTML解析都不需要了,進(jìn)行一下簡單的封裝,然后就可以像這樣使用了: #滑稽 :)
await new Downloader('http://36kr.com/newsflashes', DOWNLOADER.puppeteer).downloadHTML()
二、HTML內(nèi)容提取
HTML內(nèi)容提取當(dāng)然是使用神器 cheerio 了, cheerio 暴露了和 jQuery 一樣的接口,用起來非常簡單。瀏覽器打開頁面 F12 查看提取的頁面元素節(jié)點(diǎn),然后根據(jù)需求來提取內(nèi)容即可
readHubExtract () {
let nodeList = this.$('#itemList').find('.enableVisited')
nodeList.each((i, e) => {
let a = this.$(e).find('a')
this.extractData.push(
this.extractDataFactory(
a.attr('href'),
a.text(),
'',
SOURCECODE.Readhub
)
)
})
return this.extractData
}
三、定時(shí)任務(wù)
cron 每天跑一跑
function job () {
let cronJob = new cron.CronJob({
cronTime: cronConfig.cronTime,
onTick: () => {
spider()
},
start: false
})
cronJob.start()
}
四、數(shù)據(jù)持久化
數(shù)據(jù)持久化理論上應(yīng)該不屬于爬蟲關(guān)心的范圍,用 mongoose ,創(chuàng)建Model
import mongoose from 'mongoose'
const Schema = mongoose.Schema
const NewsSchema = new Schema(
{
title: { type: 'String', required: true },
url: { type: 'String', required: true },
summary: String,
recommend: { type: Boolean, default: false },
source: { type: Number, required: true, default: 0 },
status: { type: Number, required: true, default: 0 },
createdTime: { type: Date, default: Date.now }
},
{
collection: 'news'
}
)
export default mongoose.model('news', NewsSchema)
基本操作
import { OBJ_STATUS } from '../../Constants'
class BaseService {
constructor (ObjModel) {
this.ObjModel = ObjModel
}
saveObject (objData) {
return new Promise((resolve, reject) => {
this.ObjModel(objData).save((err, result) => {
if (err) {
return reject(err)
}
return resolve(result)
})
})
}
}
export default BaseService
資訊
import BaseService from './BaseService'
import News from '../models/News'
class NewsService extends BaseService {}
export default new NewsService(News)
愉快地保存數(shù)據(jù)
await newsService.batchSave(newsListTem)
更多內(nèi)容到Github把項(xiàng)目clone下來看就好了。
總結(jié)
相關(guān)文章
Node中的util.promisify()方法的基本使用和實(shí)現(xiàn)
眾所周知,在JS中實(shí)現(xiàn)異步編程主要是通過以下幾種方案,回調(diào)函數(shù),觀察者模式,Generator,Promise,async / await ,今天就和大家一起聊一下在node中的一個(gè)util.promisify()這個(gè)API的基本使用和基本實(shí)現(xiàn)2023-07-07
nodejs同步調(diào)用獲取mysql數(shù)據(jù)時(shí)遇到的大坑
今天小編就為大家分享一篇關(guān)于nodejs同步調(diào)用獲取mysql數(shù)據(jù)時(shí)遇到的大坑,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03
如何利用node實(shí)現(xiàn)靜態(tài)文件緩存詳解
HTTP 緩存機(jī)制作為 Web 應(yīng)用性能優(yōu)化的重要手段,對(duì)于從事 Web 開發(fā)的同學(xué)們來說,應(yīng)該是知識(shí)體系的基礎(chǔ)環(huán)節(jié),也是想要成為前端架構(gòu)的必備技能,這篇文章主要給大家介紹了關(guān)于如何利用node實(shí)現(xiàn)靜態(tài)文件緩存的相關(guān)資料,需要的朋友可以參考下2021-07-07
在Node.js中實(shí)現(xiàn)文件復(fù)制的方法和實(shí)例
這篇文章主要介紹了在Node.js中實(shí)現(xiàn)文件復(fù)制的方法和實(shí)例,使用FS模塊實(shí)現(xiàn),需要的朋友可以參考下2014-06-06
node環(huán)境下運(yùn)行js代碼缺少window環(huán)境的原因以及解決方法
Node是一個(gè)基于Chrome?V8引擎的運(yùn)行環(huán)境,讓JavaScript運(yùn)行在服務(wù)端的開發(fā)平臺(tái),這篇文章主要給大家介紹了關(guān)于node環(huán)境下運(yùn)行js代碼缺少window環(huán)境的原因以及解決方法,需要的朋友可以參考下2023-11-11
使用 Node.js 實(shí)現(xiàn)圖片的動(dòng)態(tài)裁切及算法實(shí)例代碼詳解
這篇文章主要介紹了使用 Node.js 實(shí)現(xiàn)圖片的動(dòng)態(tài)裁切功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09
Node.js內(nèi)置模塊events事件監(jiān)聽發(fā)射詳解
這篇文章主要為大家介紹了Node.js內(nèi)置模塊events事件監(jiān)聽發(fā)射詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
node.js開發(fā)中使用Node Supervisor實(shí)現(xiàn)監(jiān)測(cè)文件修改并自動(dòng)重啟應(yīng)用
這篇文章主要介紹了node.js開發(fā)中使用Node Supervisor實(shí)現(xiàn)監(jiān)測(cè)文件修改并自動(dòng)重啟應(yīng)用的功能,從而避免大量重復(fù)的CTRL+C終止程序動(dòng)作,需要的朋友可以參考下2014-11-11

