使用 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 相关文章推荐
javascript 定义初始化数组函数
Sep 07 Javascript
使用JavaScript 实现对象 匀速/变速运动的方法
May 08 Javascript
jQuery+HTML5加入购物车代码分享
Oct 29 Javascript
JS弹出新窗口被拦截的解决方法
Aug 09 Javascript
JS实现字符串转驼峰格式的方法
Dec 16 Javascript
JavaScript实现经典排序算法之冒泡排序
Dec 28 Javascript
详解vue.js全局组件和局部组件
Apr 10 Javascript
基于jQuery Ajax实现下拉框无刷新联动
Dec 06 jQuery
vue webpack实用技巧总结
Apr 24 Javascript
vue 实现v-for循环回来的数据动态绑定id
Nov 07 Javascript
js实现拖拽与碰撞检测
Sep 18 Javascript
Vue实现摇一摇功能(兼容ios13.3以上)
Jan 26 Vue.js
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实现的漂亮分页方法
2014/04/17 PHP
phpMyAdmin无法登陆的解决方法
2017/04/27 PHP
laravel 实现向公共模板中传值 (view composer)
2019/10/22 PHP
JavaScript学习笔记之获取当前目录的实现代码
2010/12/14 Javascript
简单实用的全选反选按钮例子
2013/10/18 Javascript
js单例模式的两种方案
2013/10/22 Javascript
jQuery中对未来的元素绑定事件用bind、live or on
2014/04/17 Javascript
ExtJS4如何给同一个formpanel不同的url
2014/05/02 Javascript
jQuery选择器源码解读(三):tokenize方法
2015/03/31 Javascript
js实现文件上传功能 后台使用MultipartFile
2018/09/08 Javascript
Angular请求防抖处理第一次请求失效问题
2019/05/17 Javascript
Node.js 的 GC 机制详解
2019/06/03 Javascript
CKeditor4 字体颜色功能配置方法教程
2019/06/26 Javascript
快速对接payjq的个人微信支付接口过程解析
2019/08/15 Javascript
layui扩展上传组件模拟进度条的方法
2019/09/23 Javascript
Javascript实现简易天数计算器
2020/05/18 Javascript
Python的Flask开发框架简单上手笔记
2015/11/16 Python
python 捕获shell脚本的输出结果实例
2017/01/04 Python
python numpy 部分排序 寻找最大的前几个数的方法
2018/06/27 Python
python绘制地震散点图
2019/06/18 Python
通过实例解析Python RPC实现原理及方法
2020/07/07 Python
HTML5中原生的右键菜单创建方法
2016/06/28 HTML / CSS
HTML table 表格边框的实现思路
2019/10/12 HTML / CSS
DKNY品牌官网:纽约大都会时尚风格
2016/10/20 全球购物
台湾百利市购物中心:e-Payless
2017/08/16 全球购物
美国最佳在线航班预订网站:LookupFare
2019/03/26 全球购物
DC Shoes荷兰官方网站:美国极限运动品牌
2019/10/22 全球购物
德国便宜的宠物店:Brekz.de
2020/10/23 全球购物
英文自我鉴定
2013/12/10 职场文书
给水工程专业毕业生自荐信
2014/01/28 职场文书
支部鉴定材料
2014/06/02 职场文书
微电影大赛策划方案
2014/06/05 职场文书
计算机软件专业求职信
2014/06/10 职场文书
赔偿协议书范本
2014/09/12 职场文书
高中班主任心得体会
2016/01/07 职场文书
《爬天都峰》教学反思
2016/02/23 职场文书