使用 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控制的遮罩层实例介绍
May 29 Javascript
jquery预加载图片的方法
May 27 Javascript
jQuery超赞的评分插件(8款)
Aug 20 Javascript
js仿百度切换皮肤功能(html+css)
Jul 10 Javascript
使用get方式提交表单在地址栏里面不显示提交信息
Feb 21 Javascript
JS SetInterval 代码实现页面轮询
Aug 11 Javascript
bootstrap table实现合并单元格效果
Dec 24 Javascript
轻松解决JavaScript定时器越走越快的问题
May 13 Javascript
Vue-CLI与Vuex使用方法实例分析
Jan 06 Javascript
js实现简单音乐播放器
Jun 30 Javascript
Vue 组件的挂载与父子组件的传值实例
Sep 02 Javascript
Ajax获取node服务器数据的完整步骤
Sep 20 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操作sqlserver关于时间日期读取的小小见解
2009/11/29 PHP
php模板中出现空行解决方法
2011/03/08 PHP
php 如何获取数组第一个值
2013/08/06 PHP
Smarty中常用变量操作符汇总
2014/10/27 PHP
PHP SPL标准库中的常用函数介绍
2015/05/11 PHP
PHP 应用容器化以及部署方法
2018/02/12 PHP
yii框架结合charjs实现统计30天数据的方法
2020/04/04 PHP
js右键菜单效果代码
2007/07/21 Javascript
ext 列表页面关于多行查询的办法
2010/03/25 Javascript
js 取时间差去掉周六周日实现代码
2012/12/25 Javascript
Raphael一个用于在网页中绘制矢量图形的Javascript库
2013/01/08 Javascript
鼠标移到导航当前位置的LI变色处于选中状态
2013/08/23 Javascript
jQuery中:submit选择器用法实例
2015/01/03 Javascript
JQuery中attr属性和jQuery.data()学习笔记【必看】
2016/05/18 Javascript
D3.js实现雷达图的方法详解
2016/09/22 Javascript
详解Angular 4.x Injector
2017/05/04 Javascript
Node.js进阶之核心模块https入门
2018/05/23 Javascript
layui实现form表单同时提交数据和文件的代码
2019/10/25 Javascript
jquery实现轮播图特效
2020/04/12 jQuery
[52:39]完美世界DOTA2联赛PWL S3 CPG vs Forest 第一场 12.16
2020/12/17 DOTA
python抓取网页中的图片示例
2014/02/28 Python
Python实现的检测网站挂马程序
2014/11/30 Python
Python批量创建迅雷任务及创建多个文件
2016/02/13 Python
详解Python中的相对导入和绝对导入
2017/01/06 Python
Python获取某一天是星期几的方法示例
2017/01/17 Python
简述:我为什么选择Python而不是Matlab和R语言
2017/11/14 Python
python利用OpenCV2实现人脸检测
2020/04/16 Python
Python 12306抢火车票脚本 Python京东抢手机脚本
2018/02/06 Python
python3 图片referer防盗链的实现方法
2018/03/12 Python
python中列表的含义及用法
2020/05/26 Python
CSS3的transition和animation的用法实例介绍
2014/08/20 HTML / CSS
Ego Shoes官网:英国时髦鞋类品牌
2020/10/19 全球购物
电子商务专业毕业生自荐书
2014/06/22 职场文书
2015年大学生实习评语
2015/03/25 职场文书
2019暑假阅读倡议书
2019/06/24 职场文书
MySQL数据库之内置函数和自定义函数 function
2022/06/16 MySQL