信阳使用 Node.js 开发资讯爬虫流程

河南网站建设 phpacg 2年前 (2018-04-23) 153次浏览 0个评论

最近项目需求一些资讯,由于项目是用 Node.js 来写的,所以就自然地用 Node.js 来写爬虫了

项目地址:github.com/mrtanweijie… ,项目外面爬取了 Readhub 、 开源中国 、 开发者头条 、 36Kr 这几个网站的资讯内容,暂时没有对多页面停止处置,由于每天爬虫都会跑一次,如今每次获取到最新的就可以满足需求了,前期再停止完善

爬虫流程概括上去就是把目的网站的HTML下载到本地再停止数据提取。

一、下载页面

Node.js 有很多http央求库,这里运用 request ,主要代码如下: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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 来停止包装,便于前面运用的时分用上 async/await 。由于有很多网站是在客户端渲染的,所以下载到的页面不一定包括想要的HTML内容,我们可以运用 Google 的 puppeteer 来下载客户端渲染的网站页面。众所周知的缘由,在 npm i 的时分 puppeteer 能够由于需求下载Chrome内核招致装置会失败,多试几次就好了:) 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)
  }
 })
 }

当然客户端渲染的页面最好是直接运用接口央求的方式,这样前面的HTML解析都不需求了,停止一下复杂的封装,然后就可以像这样运用了: #诙谐 :)

1
await new Downloader('http://36kr.com/newsflashes', DOWNLOADER.puppeteer).downloadHTML()

二、HTML内容提取

HTML内容提取当然是运用神器 cheerio 了, cheerio 暴露了和 jQuery 一样的接口,用起来十分复杂。阅读器翻开页面 F12 检查提取的页面元素节点,然后依据需求来提取内容即可 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
 }

三、定时义务

1
2
3
4
5
6
7
8
9
10
11
cron 每天跑一跑
function job () {
 let cronJob = new cron.CronJob({
 cronTime: cronConfig.cronTime,
 onTick: () => {
  spider()
 },
 start: false
 })
 cronJob.start()
}

四、数据耐久化

数据耐久化实际上应该不属于爬虫关心的范围,用 mongoose ,创立Model 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)

基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

资讯

1
2
3
4
import BaseService from './BaseService'
import News from '../models/News'
class NewsService extends BaseService {}
export default new NewsService(News)

愉快地保管数据

1
await newsService.batchSave(newsListTem)

更多内容到Github把项目clone上去看就好了。

总结

 

原文链接:https://juejin.im/post/5a506e6d51882573450156e3?utm_source=tuicool&utm_medium=referral

喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址