使用 Node.JS 爬取网页、存储数据
前言
以前在做爬虫项目是使用Python,操作起来不大熟练,后来了解到 cheerio 这个JS库,发现挺好用。这里就贡献一下一个小型的爬虫项目。
项目选取了ETH区块浏览器:etherscan.io , 目的是获取该网站下所有ETH ERC20 代币的Logo。
项目描述
使用 Node.JS 爬取网页图片、下载图片到本地、上传图片到CDN、详细信息存入数据库
项目实现
- 获取所有的ETH代币的logo以及基础信息
- 将基础信息保存至数据库
- 下载logo图片至本地
- 将logo上传到CDN ,同时将CDN地址保存至数据库
- 删除本地下载的图片 (暂未实现,比较简单)
所用框架
- Node.js (运行环境)
- Qiniu.js (上传图片至CDN)
- Sequelize.js (mysql ORM 框架)
- Axios.js (网络请求框架)
关于 cheerio.js
官方有这么一句定义:
cheerio.js是jquery核心功能的一个快速灵活而又简洁的实现,主要是为了用在服务器端需要对DOM进行操作的地方
说到jquery其实再熟悉不过了,除此之外,它的用法和jquery也差不多,下面是官网示例:
const cheerio = require('cheerio')
const $ = cheerio.load('<h2 class="title">Hello world</h2>')
$('h2.title').text('Hello there!')
$('h2').addClass('welcome')
$.html()
//=> <h2 class="title welcome">Hello there!</h2>
安装
npm install cheerio
业务实现
config.js 配置文件
这个就不提供了,有机密 ?
Service 处理文件下载、图片上传
download_service.js 文件下载以及查询
download_service.js 主要提供两个功能:
- 保存图片到本地
- 图片是否存在
const fs = require('fs')
const request = require('request')
const download_service = {
}
/**
* 下载图片至本地 - 未完全进行错误捕获,需优化
* @param {*} src 要下载的文件url
* @param {*} dest 要保存的文件名
*/
download_service.download_pic = (src, dest) => {
return new Promise((resolve, reject) => {
console.log(`${
dest} downloading`)
try {
const reader = request(src).pipe(fs.createWriteStream(dest))
reader.on('close', () => {
console.log(`${
dest} save local success`)
resolve(true)
})
} catch (error) {
console.error(`${
dest} save local error , ${
error.toString()}`)
reject(error)
}
})
}
/**
* 查询本地文件是否存在
* @param {*} dest 文件地址
*/
download_service.find_file = (dest) => {
return new Promise((resolve) => {
fs.access(dest, (err) => {
resolve(err === null)
})
})
}
module.exports = download_service
upload_service.js 处理文件上传
const qiniu_sdk = require('qiniu')
const {
qiniu } = require('../config/config')
const qiniu_service = {
}
qiniu_sdk.conf.ACCESS_KEY = qiniu.ACCESS_KEY
qiniu_sdk.conf.SECRET_KEY = qiniu.SECRET_KEY
// 要上传的空间
const bucket = qiniu.bucket
// 域名
const domain = qiniu.domain
// 生成上传文件的 token
const token = (bucket, key) => {
const policy = new qiniu_sdk.rs.PutPolicy({
isPrefixalScope: 1, scope: bucket + ':' + key })
return policy.uploadToken()
}
const config = new qiniu_sdk.conf.Config();
/**
* 上传文件到七牛
* @param {*} file_name
* @param {*} file_path
*/
qiniu_service.upload_file = (file_name, file_path, prefix = "eth/image/token/") => {
// 保存到七牛的地址
const file_save_path = prefix + file_name
// 七牛上传的token
const up_token = token(bucket, file_save_path)
const extra = new qiniu_sdk.form_up.PutExtra()
const formUploader = new qiniu_sdk.form_up.FormUploader(config)
return new Promise(resolve => {
// 上传文件
formUploader.putFile(up_token, file_save_path