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


Posted in Javascript onJanuary 07, 2018

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

项目地址:github.com/mrtanweijie… ,项目里面爬取了 Readhub 、 开源中国 、 开发者头条 、 36Kr 这几个网站的资讯内容,暂时没有对多页面进行处理,因为每天爬虫都会跑一次,现在每次获取到最新的就可以满足需求了,后期再进行完善

爬虫流程概括下来就是把目标网站的HTML下载到本地再进行数据提取。

一、下载页面

Node.js 有很多http请求库,这里使用 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 来进行包装,便于后面使用的时候用上 async/await 。因为有很多网站是在客户端渲染的,所以下载到的页面不一定包含想要的HTML内容,我们可以使用 Google 的 puppeteer 来下载客户端渲染的网站页面。众所周知的原因,在 npm i 的时候 puppeteer 可能因为需要下载Chrome内核导致安装会失败,多试几次就好了:)

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解析都不需要了,进行一下简单的封装,然后就可以像这样使用了: #滑稽 :)

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

二、HTML内容提取

HTML内容提取当然是使用神器 cheerio 了, cheerio 暴露了和 jQuery 一样的接口,用起来非常简单。浏览器打开页面 F12 查看提取的页面元素节点,然后根据需求来提取内容即可

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
 }

三、定时任务

cron 每天跑一跑 
function job () {
 let cronJob = new cron.CronJob({
 cronTime: cronConfig.cronTime,
 onTick: () => {
  spider()
 },
 start: false
 })
 cronJob.start()
}

四、数据持久化

数据持久化理论上应该不属于爬虫关心的范围,用 mongoose ,创建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)

愉快地保存数据

await newsService.batchSave(newsListTem)

更多内容到Github把项目clone下来看就好了。

总结

Javascript 相关文章推荐
关于使用 jBox 对话框的提交不能弹出问题解决方法
Nov 07 Javascript
web基于浏览器的本地存储方法应用
Nov 27 Javascript
动态读取JSON解析键值对的方法
Jun 03 Javascript
60行js代码实现俄罗斯方块
Mar 31 Javascript
前端微信支付js代码
Jul 25 Javascript
AngularJS 文件上传控件 ng-file-upload详解
Jan 13 Javascript
vue实现图片加载完成前的loading组件方法
Feb 05 Javascript
微信小程序如何像vue一样在动态绑定类名
Apr 17 Javascript
JavaScript实现构造json数组的方法分析
Aug 17 Javascript
js实现旋转的星空效果
Nov 01 Javascript
解决qrcode.js生成二维码时必须定义一个空div的问题
Jul 09 Javascript
Vue Router中应用中间件的方法
Aug 06 Javascript
CentOS环境中MySQL修改root密码方法
Jan 07 #Javascript
12条写出高质量JS代码的方法
Jan 07 #Javascript
js数组方法reduce经典用法代码分享
Jan 07 #Javascript
javascript中的replace函数(带注释demo)
Jan 07 #Javascript
基于JavaScript实现简单的音频播放功能
Jan 07 #Javascript
js实现复制功能(多种方法集合)
Jan 06 #Javascript
tangram.js库实现js类的方式实例分析
Jan 06 #Javascript
You might like
PHP人民币金额数字转中文大写的函数代码
2013/02/27 PHP
百度实时推送api接口应用示例
2014/10/21 PHP
php保存任意网络图片到服务器的方法
2015/04/14 PHP
ThinkPHP数据操作方法总结
2015/09/28 PHP
PHP通过微信跳转的Code参数获取用户的openid(关键代码)
2016/07/06 PHP
PHP聚合式迭代器接口IteratorAggregate用法分析
2017/12/28 PHP
Laravel-添加后台模板AdminLte的实现方法
2019/10/08 PHP
javascript预览上传图片发现的问题的解决方法
2010/11/25 Javascript
非主流的textarea自增长实现js代码
2011/12/20 Javascript
js导航菜单(自写)简单大方
2013/03/28 Javascript
js怎么终止程序return不行换jfslk
2013/05/30 Javascript
Express作者TJ告别Node.js奔向Go
2014/07/14 Javascript
jquery动态添加删除(tr/td)
2015/02/09 Javascript
开启BootStrap学习之旅
2016/05/04 Javascript
jQuery实现火车票买票城市选择切换功能
2017/09/15 jQuery
VueJS事件处理器v-on的使用方法
2017/09/27 Javascript
JavaScript this绑定过程深入详解
2018/12/07 Javascript
在layui中使用form表单监听ajax异步验证注册的实例
2019/09/03 Javascript
解决layer 关闭当前弹窗 关闭遮罩层 input值获取不到的问题
2019/09/25 Javascript
Node.js操作MongoDB数据库实例分析
2020/01/19 Javascript
pygame学习笔记(4):声音控制
2015/04/15 Python
更改Ubuntu默认python版本的两种方法python-> Anaconda
2016/12/18 Python
python实现log日志的示例代码
2018/04/28 Python
详解小白之KMP算法及python实现
2019/04/04 Python
python中使用ctypes调用so传参设置遇到的问题及解决方法
2019/06/19 Python
Python读取二进制文件代码方法解析
2020/06/22 Python
IE滤镜与CSS3效果(详细整理分享)
2013/01/25 HTML / CSS
美国翻新电子产品商店:The Store
2019/10/08 全球购物
美国名牌手表折扣网站:Jomashop
2020/05/22 全球购物
国际贸易专业个人求职信格式
2014/02/02 职场文书
教师节宣传方案
2014/05/23 职场文书
放弃继承权公证书
2015/01/23 职场文书
导游词之苏州盘门景区
2019/11/12 职场文书
CocosCreator ScrollView优化系列之分帧加载
2021/04/14 Python
Pytorch可视化的几种实现方法
2021/06/10 Python
SQL实战演练之网上商城数据库商品类别数据操作
2021/10/24 MySQL