最近项目需要一些资讯,因为项目是用 Node js 来写的,所以就自然地用 Node js 来写爬虫了项目地址:github com mrtanweijie…,项目里面爬取了 Readhub 、 开源中国 、 开发者头条 、 36Kr 这几个网站的资讯内容
最近项目需要一些资讯,因为项目是用 Node.js 来写的,所以就自然地用 Node.js 来写爬虫了
项目地址:github.com/mrtanweijie… ,项目里面爬取了 Readhub 、 开源中国 、 开发者头条 、 36Kr 这几个网站的资讯内容,暂时没有对多页面进行处理,因为每天爬虫都会跑一次,现在每次获取到最新的就可以满足需求了,后期再进行完善
爬虫流程概括下来就是把目标网站的HTML下载到本地再进行数据提取。
一、下载页面
Node.js 有很多http请求库,这里使用 request ,主要代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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内核导致安装会失败,多试几次就好了:)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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解析都不需要了,进行一下简单的封装,然后就可以像这样使用了: #滑稽 :)
二、HTML内容提取
HTML内容提取当然是使用神器 cheerio 了, cheerio 暴露了和 jQuery 一样的接口,用起来非常简单。浏览器打开页面 F12 查看提取的页面元素节点,然后根据需求来提取内容即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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
}
|
三、定时任务
1
2
3
4
5
6
7
8
9
10
11
|
cron 每天跑一跑
function job () {
let cronJob = new cron.CronJob({
cronTime: cronConfig.cronTime,
onTick: () => {
spider()
},
start: false
})
cronJob.start()
}
|
四、数据持久化
数据持久化理论上应该不属于爬虫关心的范围,用 mongoose ,创建Model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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)
|
基本操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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
|
资讯
1
2
3
4
|
import BaseService from './BaseService'
import News from '../models/News'
class NewsService extends BaseService {}
export default new NewsService(News)
|
愉快地保存数据
1
|
await newsService.batchSave(newsListTem)
|
更多内容到Github把项目clone下来看就好了。
总结
原文链接:https://juejin.im/post/5a506e6d51882573450156e3?utm_source=tuicool&utm_medium=referral