使用 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基本选择器选择元素使用介绍
Apr 18 Javascript
jquery通过select列表选择框对表格数据进行过滤示例
May 07 Javascript
js实现点击添加一个input节点
Dec 05 Javascript
JavaScript面向对象的实现方法小结
Apr 14 Javascript
JavaScript实现简单的拖动效果
Jul 02 Javascript
Ajax异步获取html数据中包含js方法无效的解决方法
Feb 20 Javascript
详解微信小程序 通过控制CSS实现view隐藏与显示
May 24 Javascript
layui框架中layer父子页面交互的方法分析
Nov 15 Javascript
vue todo-list组件发布到npm上的方法
Apr 04 Javascript
Vue.js点击切换按钮改变内容的实例讲解
Aug 22 Javascript
微信小程序实现搜索历史功能
Mar 26 Javascript
解决vue bus.$emit触发第一次$on监听不到问题
Jul 28 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
咖啡与牛奶
2021/03/03 冲泡冲煮
PHP封装分页函数实现文本分页和数字分页
2014/10/23 PHP
一个完整的php文件上传类实例讲解
2015/10/27 PHP
PHP CURL采集百度搜寻结果图片不显示问题的解决方法
2017/02/03 PHP
精解window.setTimeout()&window.setInterval()使用方式与参数传递问题!
2007/11/23 Javascript
Chrome中模态对话框showModalDialog返回值问题的解决方法
2010/05/25 Javascript
原生的html元素选择器类似jquery选择器
2014/10/15 Javascript
js实现浏览器窗口大小被改变时触发事件的方法
2015/02/02 Javascript
jQuery实现判断滚动条到底部
2015/06/23 Javascript
js控制多图左右滚动切换效果代码分享
2015/08/26 Javascript
微信小程序 参数传递实例代码
2017/03/20 Javascript
WdatePicker.js时间日期插件的使用方法
2017/07/26 Javascript
nodejs微信开发之自动回复的实现
2019/03/17 NodeJs
arctext.js实现文字平滑弯曲弧形效果的插件
2019/05/13 Javascript
vue开发拖拽进度条滑动组件
2019/09/21 Javascript
vue 解决form表单提交但不跳转页面的问题
2019/10/30 Javascript
jquery+ajax实现异步上传文件显示进度条
2020/08/17 jQuery
python使用两种发邮件的方式smtp和outlook示例
2017/06/02 Python
Python实现通过继承覆盖方法示例
2018/07/02 Python
Python多进程写入同一文件的方法
2019/01/14 Python
Python实现二叉树前序、中序、后序及层次遍历示例代码
2019/05/18 Python
使用python搭建服务器并实现Android端与之通信的方法
2019/06/28 Python
python manage.py runserver流程解析
2019/11/08 Python
使用python实现画AR模型时序图
2019/11/20 Python
15个Pythonic的代码示例(值得收藏)
2020/10/29 Python
详解matplotlib绘图样式(style)初探
2021/02/03 Python
canvas 基础之图像处理的使用
2020/04/10 HTML / CSS
美国派对用品及装饰品网上商店:Shindigz
2016/07/30 全球购物
旷课检讨书2000字
2014/01/14 职场文书
圣诞节红领巾广播稿
2014/02/03 职场文书
一般基层干部群众路线教育实践活动个人对照检查材料
2014/11/04 职场文书
2016年母亲节广告语
2016/01/28 职场文书
关于Python中*args和**kwargs的深入理解
2021/08/07 Python
浅谈MySQL表空间回收的正确姿势
2021/10/05 MySQL
Windows 11上手初体验:任务栏和开始菜单等迎来大改
2021/11/21 数码科技
Mysql开启外网访问
2022/05/15 MySQL