使用 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 相关文章推荐
JS调用CS里的带参方法实例
Aug 01 Javascript
jquery按回车提交数据的代码示例
Nov 05 Javascript
JS获取当前网页大小以及屏幕分辨率等
Sep 05 Javascript
Javascript中使用A标签获取当前目录的绝对路径方法
Mar 02 Javascript
C++中的string类的用法小结
Aug 07 Javascript
JS实现的网页背景闪电闪烁效果代码
Oct 17 Javascript
前端JS面试中常见的算法问题总结
Dec 23 Javascript
关于Vue实现组件信息的缓存问题
Aug 23 Javascript
Vue组件之全局组件与局部组件的使用详解
Oct 09 Javascript
详解vue.js下引入百度地图jsApi的两种方法
Jul 27 Javascript
Layui 动态禁止select下拉的例子
Sep 03 Javascript
vue router-link 默认a标签去除下划线的实现
Nov 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
PHPMailer的主要功能特点和简单使用说明
2014/02/17 PHP
PHP根据传入参数合并多个JS和CSS文件的简单实现
2014/06/13 PHP
通过PHP简单实例介绍文件上传
2015/12/16 PHP
在openSUSE42.1下编译安装PHP7 的方法
2015/12/24 PHP
详解cookie验证的php应用的一种SSO解决办法
2017/10/20 PHP
表单(FORM)的一些实用效果代码
2007/03/25 Javascript
js 编码转换 gb2312 和 utf8 互转的2种方法
2013/08/07 Javascript
ExtJS4中的requires使用方法示例介绍
2013/12/03 Javascript
简单谈谈node.js 版本控制 nvm和 n
2015/10/15 Javascript
纯JavaScript代码实现移动设备绘图解锁
2015/10/16 Javascript
AngularJS 过滤与排序详解及实例代码
2016/09/14 Javascript
Angular4学习笔记之实现绑定和分包
2017/08/01 Javascript
JavaScript实现的数字与字符串转换功能示例
2017/08/23 Javascript
vue-router项目实战总结篇
2018/02/11 Javascript
vue多页面开发和打包正确处理方法
2018/04/20 Javascript
Bootstrap-table使用footerFormatter做统计列功能
2018/09/07 Javascript
原生JS实现逼真的图片3D旋转效果详解
2019/02/16 Javascript
微信小程序实现多行文字超出部分省略号显示功能
2019/10/23 Javascript
vue-socket.io跨域问题有效解决方法
2020/02/11 Javascript
Python模糊查询本地文件夹去除文件后缀的实例(7行代码)
2017/11/09 Python
pyqt 多窗口之间的相互调用方法
2019/06/19 Python
Python实现的微信红包提醒功能示例
2019/08/22 Python
Django中使用MySQL5.5的教程
2019/12/18 Python
Python定义函数时参数有默认值问题解决
2019/12/19 Python
使用OpenCV获取图片连通域数量,并用不同颜色标记函
2020/06/04 Python
解决Keras的自定义lambda层去reshape张量时model保存出错问题
2020/07/01 Python
美国一家专业的太阳镜网上零售商:Solstice太阳镜
2016/07/25 全球购物
土耳其时尚购物网站:Morhipo
2017/09/04 全球购物
数据库面试要点基本概念
2013/10/31 面试题
办护照工作证明范本
2014/01/14 职场文书
学生会竞选演讲稿
2014/04/24 职场文书
营业用房租赁协议书
2014/11/26 职场文书
库房管理员岗位职责
2015/02/12 职场文书
乡镇党建工作总结2015
2015/05/19 职场文书
2015年小学财务工作总结
2015/07/20 职场文书
2016年中秋节晚会领导致辞
2015/11/26 职场文书