使用 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面向对象编程
Nov 15 Javascript
分享JavaScript获取网页关闭与取消关闭的事件
Dec 13 Javascript
javascript日期格式化方法汇总
Oct 04 Javascript
js实现(全选)多选按钮的方法【附实例】
Mar 30 Javascript
JavaScript编写检测用户所使用的浏览器的代码示例
May 05 Javascript
js鼠标跟随运动效果
Mar 11 Javascript
利用PM2部署node.js项目的方法教程
May 10 Javascript
基于vue2实现左滑删除功能
Nov 28 Javascript
select标签设置默认选中的选项方法
Mar 02 Javascript
解决vue2.0 element-ui中el-upload的before-upload方法返回false时submit()不生效问题
Aug 24 Javascript
js实现简单的秒表
Jan 16 Javascript
基于jQuery拖拽事件的封装
Nov 29 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支持断点续传的源码
2010/05/16 PHP
使用php get_headers 判断URL是否有效的解决办法
2013/04/27 PHP
php制作unicode解码工具(unicode编码转换器)代码分享
2013/12/24 PHP
PHP 微信支付类 demo
2015/11/30 PHP
PHP开发APP端微信支付功能
2017/02/17 PHP
thinkphp5框架结合mysql实现微信登录和自定义分享链接与图文功能示例
2019/08/13 PHP
PHP高并发和大流量解决方案整理
2019/12/24 PHP
用JS将搜索的关键字高亮显示实现代码
2013/11/08 Javascript
刷新页面的几种方法小结(JS,ASP.NET)
2014/01/07 Javascript
jQuery添加/改变/移除CSS类及判断是否已经存在CSS
2014/08/20 Javascript
JavaScript模拟重力状态下抛物运动的方法
2015/03/03 Javascript
js省市联动效果完整实例代码
2015/12/09 Javascript
基于Bootstrap重置输入框内容按钮插件
2016/05/12 Javascript
全面解析DOM操作和jQuery实现选项移动操作代码分享
2016/06/07 Javascript
EasyUI Pagination 分页的两种做法小结
2016/07/09 Javascript
Jquery树插件zTree实现菜单树
2017/01/24 Javascript
D3.js进阶系列之CSV表格文件的读取详解
2017/06/06 Javascript
微信小程序实现消息框弹出动画
2020/04/18 Javascript
vuex管理状态 刷新页面保持不被清空的解决方案
2019/11/11 Javascript
[51:36]Optic vs Newbee 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
Python打印“菱形”星号代码方法
2018/02/05 Python
Python魔法方法功能与用法简介
2019/04/04 Python
centos 安装Python3 及对应的pip教程详解
2019/06/28 Python
解决python flask中config配置管理的问题
2019/07/26 Python
CSS3线性渐变简单实现以及该属性在浏览器中的不同
2012/12/12 HTML / CSS
HTML5 Web Workers之网站也能多线程的实现
2013/04/24 HTML / CSS
美国奢侈品在线团购网站:Gilt City
2017/11/16 全球购物
在阿联酋购买翻新手机和平板电脑:Teckzu
2021/02/12 全球购物
初中生三年学习生活的自我评价
2013/11/03 职场文书
大学生四年生活自我鉴定
2013/11/21 职场文书
股份转让协议书
2014/04/12 职场文书
军人离婚协议书样本
2014/10/21 职场文书
教师学期个人总结
2015/02/11 职场文书
2015年秋季开学典礼校长致辞
2015/07/16 职场文书
小学家庭教育心得体会
2016/01/14 职场文书
PyTorch dropout设置训练和测试模式的实现
2021/05/27 Python