使用 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 相关文章推荐
jQuery实现简单的间隔向上滚动效果
Mar 09 Javascript
javascript中DOM复选框选择用法实例
May 14 Javascript
JS+CSS实现DIV层的展开、收缩效果
Jan 28 Javascript
强大Vue.js组件浅析
Sep 12 Javascript
Bootstrap Table使用方法解析
Oct 19 Javascript
js实现兼容PC端和移动端滑块拖动选择数字效果
Feb 16 Javascript
原生JS实现幻灯片
Feb 22 Javascript
javascript 秒表计时器实现代码
Mar 09 Javascript
React Native实现地址挑选器功能
Oct 24 Javascript
Angular Excel 导入与导出的实现代码
Apr 17 Javascript
vue前后分离调起微信支付
Jul 29 Javascript
JS中比Switch...Case更优雅的多条件判断写法
Sep 05 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
优化NFR之一 --MSSQL Hello Buffer Overflow
2006/10/09 PHP
php数组函数序列之array_unique() - 去除数组中重复的元素值
2011/10/29 PHP
php提示undefined index的几种解决方法
2012/05/21 PHP
php通过rmdir删除目录的简单用法
2015/03/18 PHP
一个tab标签切换效果代码
2009/03/27 Javascript
jquery.cvtooltip.js 基于jquery的气泡提示插件
2010/11/19 Javascript
javascript中setInterval的用法
2015/07/19 Javascript
jQuery实现可移动选项的左右下拉列表示例
2016/12/26 Javascript
jQuery实现的简单悬浮层功能完整实例
2017/01/23 Javascript
nodejs使用http模块发送get与post请求的方法示例
2018/01/08 NodeJs
浅谈如何通过node.js对数据进行MD5加密
2018/05/16 Javascript
vue项目base64字符串转图片的实现代码
2018/07/13 Javascript
详解性能更优越的小程序图片懒加载方式
2018/07/18 Javascript
CentOS7中源码编译安装NodeJS的完整步骤
2018/10/13 NodeJs
对vue中的事件穿透与禁止穿透实例详解
2019/10/28 Javascript
详解vue3.0 diff算法的使用(超详细)
2020/07/01 Javascript
Python程序员开发中常犯的10个错误
2014/07/07 Python
Python正则表达式的使用范例详解
2014/08/08 Python
Python使用filetype精确判断文件类型
2017/07/02 Python
Mac中Python 3环境下安装scrapy的方法教程
2017/10/26 Python
Python操作mongodb的9个步骤
2018/06/04 Python
python排序函数sort()与sorted()的区别
2018/09/18 Python
对python requests的content和text方法的区别详解
2018/10/11 Python
基于Numpy.convolve使用Python实现滑动平均滤波的思路详解
2019/05/16 Python
python实现大文本文件分割
2019/07/22 Python
Python高级编程之继承问题详解(super与mro)
2019/11/19 Python
python3 xpath和requests应用详解
2020/03/06 Python
基于注解实现 SpringBoot 接口防刷的方法
2021/03/02 Python
英国奢华护肤、美容和Spa品牌:Temple Spa
2019/11/02 全球购物
学习自我鉴定
2014/02/01 职场文书
党员创先争优心得体会
2014/09/11 职场文书
钱塘江大潮导游词
2015/02/03 职场文书
幼儿园五一劳动节活动总结
2015/02/09 职场文书
幼儿园家长工作总结2015
2015/04/25 职场文书
同事离别感言
2015/08/04 职场文书
Java面试题冲刺第十六天--消息队列
2021/08/07 面试题