使用 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函数获取html中className所在的内容并去除标签
Sep 08 Javascript
js实现做通讯录的索引滑动显示效果和滑动显示锚点效果
Feb 18 Javascript
关于vue.js v-bind 的一些理解和思考
Jun 06 Javascript
Javascript实现从小到大的数组转换成二叉搜索树
Jun 13 Javascript
bootstrap treeview 扩展addNode方法动态添加子节点的方法
Nov 21 Javascript
使用javascript做在线算法编程
May 25 Javascript
JavaScript设计模式之缓存代理模式原理与简单用法示例
Aug 07 Javascript
ajaxfileupload.js实现上传文件功能
Apr 19 Javascript
vue 关闭浏览器窗口的时候,清空localStorage的数据示例
Nov 06 Javascript
小程序api实现promise封装过程解析
Nov 21 Javascript
JS数组方法slice()用法实例分析
Jan 18 Javascript
JS中的继承操作实例总结
Jun 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脚本中include文件出错解决方法
2008/11/20 PHP
在JavaScript中调用php程序
2009/03/09 PHP
php面向对象全攻略 (二) 实例化对象 使用对象成员
2009/09/30 PHP
php安装xdebug/php安装pear/phpunit详解步骤(图)
2013/12/22 PHP
浅析php适配器模式(Adapter)
2014/11/25 PHP
php可扩展的验证类实例(可对邮件、手机号、URL等验证)
2015/07/09 PHP
php文档工具PHP Documentor安装与使用方法
2016/01/25 PHP
PHP登录验证功能示例【用户名、密码、验证码、数据库、已登陆验证、自动登录和注销登录等】
2019/02/25 PHP
理解JSON:3分钟课程
2011/10/28 Javascript
jQuery的缓存机制浅析
2014/06/07 Javascript
javascript在当前窗口关闭前检测窗口是否关闭
2014/09/29 Javascript
JS实现三个层重叠点击互相切换的方法
2015/10/06 Javascript
JS实现带有3D立体感的银灰色竖排折叠菜单代码
2015/10/20 Javascript
jQuery验证插件validate使用详解
2016/05/11 Javascript
整理一下常见的IE错误
2016/11/18 Javascript
微信小程序录音与播放录音功能
2017/12/25 Javascript
d3绘制基本的柱形图的实现代码
2018/12/12 Javascript
js中事件对象和事件委托的介绍
2019/01/21 Javascript
vue router总结 $router和$route及router与 router与route区别
2019/07/05 Javascript
[03:10]2014DOTA2 TI马来劲旅Titan首战告捷目标只是8强
2014/07/10 DOTA
[01:11:11]Alliance vs RNG 2019国际邀请赛淘汰赛 败者组BO1 8.20.mp4
2020/07/19 DOTA
python 运算符 供重载参考
2009/06/11 Python
python命令行参数sys.argv使用示例
2014/01/28 Python
终端命令查看TensorFlow版本号及路径的方法
2018/06/13 Python
Python Requests库基本用法示例
2018/08/20 Python
用Q-learning算法实现自动走迷宫机器人的方法示例
2019/06/03 Python
专门经营化妆刷的美国彩妆品牌:Sigma Beauty
2017/09/11 全球购物
巴西最大的在线约会网站:ParPerfeito
2018/07/11 全球购物
Marc O’Polo俄罗斯官方在线商店:德国高端时尚品牌
2019/12/26 全球购物
Cynthia Rowley官网:全球领先的生活方式品牌
2020/10/27 全球购物
小学生开学第一课活动方案
2014/03/27 职场文书
《永远的白衣战士》教学反思
2014/04/25 职场文书
2014年团支部工作总结
2014/11/17 职场文书
离婚案件被告代理词
2015/05/23 职场文书
2015年高三年级组工作总结
2015/07/21 职场文书
导游词之上饶龟峰
2019/10/25 职场文书