使用 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 相关文章推荐
ExtJs GridPanel简单的增删改实现代码
Aug 26 Javascript
JQuery datepicker 使用方法
May 20 Javascript
jquery 操作DOM的基本用法分享
Apr 05 Javascript
解决jquery操作checkbox火狐下第二次无法勾选问题
Feb 10 Javascript
jquery实现点击弹出可放大居中及关闭的对话框(附demo源码下载)
May 10 Javascript
JavaScript代码性能优化总结(推荐)
May 16 Javascript
JS实现密码框的显示密码和隐藏密码功能示例
Dec 26 Javascript
详述 Sublime Text 打开 GBK 格式中文乱码的解决方法
Oct 26 Javascript
vue组件文档(.md)中如何自动导入示例(.vue)详解
Jan 25 Javascript
Vue组件内部实现一个双向数据绑定的实例代码
Apr 04 Javascript
Node Mongoose用法详解【Mongoose使用、Schema、对象、model文档等】
May 13 Javascript
jQuery实现动态操作table行
Nov 23 jQuery
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+xml编程之xpath的应用实例
2015/01/24 PHP
php array_merge函数使用需要注意的一个问题
2015/03/30 PHP
实例讲解PHP表单处理
2019/02/15 PHP
Jquery中children与find之间的区别详细解析
2013/11/29 Javascript
node.js使用nodemailer发送邮件实例
2014/03/10 Javascript
Html5的placeholder属性(IE兼容)实现代码
2014/08/30 Javascript
使用JavaScript 编写简单计算器
2014/11/24 Javascript
实例讲解JQuery中this和$(this)区别
2014/12/08 Javascript
通过BootStrap实现轮播图的实际应用
2016/09/26 Javascript
React实践之Tree组件的使用方法
2017/09/30 Javascript
从源码看angular/material2 中 dialog模块的实现方法
2017/10/18 Javascript
使用angular-cli webpack创建多个包的方法
2018/10/16 Javascript
vue中将html字符串转换成html后遇到的问题小结
2018/12/10 Javascript
如何解决webpack-dev-server代理常切换问题
2019/01/09 Javascript
Javascript 对象(object)合并操作实例分析
2019/07/30 Javascript
如何通过shell脚本自动生成vue文件详解
2019/09/10 Javascript
layui实现根据table数据判断按钮显示情况的方法
2019/09/26 Javascript
React 条件渲染最佳实践小结(7种)
2020/09/27 Javascript
py2exe 编译ico图标的代码
2013/03/08 Python
Django配置文件代码说明
2019/12/04 Python
opencv3/python 鼠标响应操作详解
2019/12/11 Python
浅谈Selenium+Webdriver 常用的元素定位方式
2021/01/13 Python
具有防紫外线功能的高性能钓鱼服装:Hook&Tackle
2018/08/16 全球购物
size?法国官网:英国伦敦的球鞋精品店
2020/03/15 全球购物
金山毒霸系列的笔试题
2013/04/13 面试题
财务会计人员求职的自我评价
2014/01/13 职场文书
毕业生自荐信如何写
2014/03/24 职场文书
青年志愿者先进事迹
2014/05/06 职场文书
导航工程专业自荐信
2014/09/02 职场文书
教学改革问题查摆整改措施
2014/09/27 职场文书
学校党的群众路线教育实践活动制度建设计划
2014/11/03 职场文书
jQuery实现影院选座订座效果
2021/04/13 jQuery
一劳永逸彻底解决pip install慢的办法
2021/05/24 Python
关于python爬虫应用urllib库作用分析
2021/09/04 Python
JS的深浅复制详细
2021/10/16 Javascript
游戏《我的世界》澄清Xbox版暂无计划加入光追
2022/04/03 其他游戏