Commit 1e8a530e authored by 陈豪's avatar 陈豪

generate add os/org

parent 4c3087d4
WXT_ORIGIN = 'https://www.weixiaotong.com.cn/' WXT_ORIGIN = 'https://www.weixiaotong.com.cn/'
DOCUMENT_WIDTH = 1500 DOCUMENT_WIDTH = 1500
DOCUMENT_HEIGHT = 2668 DOCUMENT_HEIGHT = 2668
BROWER_PAGE_COUNT = 3
OPEN_MONITORING_SYSTEM = 1
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"description": "", "description": "",
"main": ".eslintrc.js", "main": ".eslintrc.js",
"scripts": { "scripts": {
"test": "node ./src/server/scripts/generateImage" "test": "node ./src/server/scripts/index"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
"archiver": "^5.2.0", "archiver": "^5.2.0",
"chalk": "^4.1.0", "chalk": "^4.1.0",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"ora": "^5.3.0",
"os-utils": "0.0.14",
"puppeteer": "2.1.1" "puppeteer": "2.1.1"
} }
} }
...@@ -14,6 +14,7 @@ module.exports = class Archiver { ...@@ -14,6 +14,7 @@ module.exports = class Archiver {
// fileName : 年月日-type-campusName-className-stuName-stuId-random // fileName : 年月日-type-campusName-className-stuName-stuId-random
let resourcesPath = resolve(fileName) let resourcesPath = resolve(fileName)
// 相同地址路径下的文件将会被覆盖(同名)
this.output = fs.createWriteStream(resourcesPath) this.output = fs.createWriteStream(resourcesPath)
this.archive = archiver(archiverType, { this.archive = archiver(archiverType, {
zlib: {level: 1} // Sets the compression level. zlib: {level: 1} // Sets the compression level.
...@@ -73,12 +74,14 @@ module.exports = class Archiver { ...@@ -73,12 +74,14 @@ module.exports = class Archiver {
className = '班级', className = '班级',
stuName = '张三', stuName = '张三',
stuId = '001', stuId = '001',
archiverType = 'zip' archiverType = 'zip',
growthId = 'growth001'
} = conf } = conf
// = objectUtils.safeObject(conf) // = objectUtils.safeObject(conf)
// generate fileName // generate fileName
let zipFileName = `${time}-${growthType}-${campusName}-${className}-${stuName}-${stuId}-${random}.${archiverType}` let zipFileName = `${time}-${growthType}-${campusName}-${className}-${stuName}-${stuId}-${growthId}.${archiverType}`
// -${random}
return Object.assign( return Object.assign(
{ {
......
const path = require('path')
const pathResources = path.resolve(__dirname, '../../resources')
const resolve = p => path.resolve(pathResources, p)
// conf
const documentWidth = process.env.DOCUMENT_WIDTH - 0
const documentHeight = process.env.DOCUMENT_HEIGHT - 0
module.exports = async function generation(page, url, pageIndex) {
/**
脚步方式打开目标界面
*/
await page.setViewport({width: documentWidth, height: documentHeight})
await page.goto(url, {
timeout: 120000 // 请求超时时间
// waitUntil: []
})
/**
可以在页面中定义自己认为加载完的事件,在合适的时间点我们将该事件设置为 true
以下是在触发截图时的判断逻辑。
如果 renderdone 出现且为 true 那么就截图。
如果是 Object(null),说明页面加载出错了,我们可以捕获该异常进行提示
*/
// let renderdoneHandle = await page.waitForFunction('window.renderdone', {
// polling: '120' // 轮询时间间隔。 raf/mutation
// })
// const renderdone = await renderdoneHandle.jsonValue()
// if (renderdone === null) {
// throw new Error(
// `加载页面失败:报表${renderdone.componentId}出错 -- ${renderdone.message}`
// )
// } else {
// console.log('页面加载成功')
// }
/**
截图
文档:https://github.com/puppeteer/puppeteer/blob/v7.1.0/docs/api.md#pagescreenshotoptions
*/
return page.screenshot({
type: 'jpeg',
quality: 90,
fullPage: true
})
}
const generateImage = require('./image')
module.exports = {generateImage}
const EventEmitter = require('events')
const puppeteer = require('puppeteer')
const {infoLog, warnningLog} = require('../../utils/console')
const {logWithSpinner, stopSpinner} = require('../../utils/org')
const {generateImage} = require('./lib')
const Archiver = require('../compression/archiver')
const pageCount = process.env.BROWER_PAGE_COUNT - 0
class Screen extends EventEmitter {
constructor(urls) {
super()
this.urls = urls
}
async startGenerate() {
infoLog(`✨ Initialize the headless browser `)
await this.initBrowser() // create browser
await this.initPages() // create browser.page
// generate
logWithSpinner('📷 To start browsing interface and generates pictures')
// system - ready brower-page(记录打印1s后的os占用详情)
this.emit('os')
await this.generates()
stopSpinner()
// system - over
this.emit('os')
}
async initBrowser() {
// init(create) browser
this.browser = await puppeteer.launch({
headless: true, // false将有浏览器界面启动
// slowMo: 100, // 放慢浏览器执行速度,方便测试观察
args: [
// 启动 Chrome 的参数,
// https://peter.sh/experiments/chromium-command-line-switches/
'--no-sandbox',
'--disable-setuid-sandbox', // 关闭沙箱
'--disable-gpu',
'--disable-dev-shm-usage',
'--no-first-run',
'--no-zygote',
'--single-process'
],
// 是否将浏览器进程标准输出和标准错误输入到 process.stdout 和 process.stderr 中
dumpio: false
})
}
async initPages() {
// init(create) page
this.browserPages = []
for (let i = 0; i < pageCount; i++) {
let browerPage = await this.browser.newPage()
this.browserPages.push(browerPage)
}
}
async closePages() {
// 关闭 开启的 page
for (let i = 0; i < pageCount; i++) {
let browerPage = this.browserPages[i]
await browerPage.close()
}
}
async closeBrowser() {
// 关闭开启的 browser
await this.browser.close()
}
async generates() {
// generate image
let compression = new Archiver()
let length = this.urls.length
// 遍历生成图片(多page)
for (let i = 0; i < length; i += pageCount) {
let promiseGenerates = this.readyGeneratePromise(i)
let imgBufs = await Promise.all([...promiseGenerates]).catch(e => {
this.emit('error', {code: 'ERROR_GENERATE_IMAGE', error: e})
return []
})
imgBufs.forEach((buf, index) => {
compression.archiveAppend(buf, `${i + index + 1}.jpeg`)
})
}
// close
compression.archiveFinalize()
await this.closePages()
await this.closeBrowser()
}
readyGeneratePromise(starIndex) {
// 整理出 Promise list (多page generate)
let generatePromise = []
let generateUrls = []
for (let i = 0; i < pageCount; i++) {
let targetIndex = starIndex + i
// target url
let targetUrl = this.urls[targetIndex]
// target page
let targetPage = this.browserPages[i]
// url 存在为空的情况 跳过创建 generatePromise
if (!targetUrl) continue
generateUrls.push(targetUrl) // 标记记录
// set generate promise - item
generatePromise.push(generateImage(targetPage, targetUrl))
}
this.emit('info', {code: 'INFO_GENERATE_URLS', info: generateUrls})
return generatePromise
}
}
module.exports = Screen
...@@ -34,13 +34,10 @@ const Archiver = require('../compression/archiver') ...@@ -34,13 +34,10 @@ const Archiver = require('../compression/archiver')
try { try {
// 浏览目标地址并生成图片 // 浏览目标地址并生成图片
const generationTime = +new Date() let generationTime = +new Date()
warnningLog(`generate url:${targetUrl}`) warnningLog(`generate url:${targetUrl}`)
let imageBuf = await generation(browserPage, targetUrl) let imageBuf = await generation(browserPage, targetUrl)
// zip
compression.archiveAppend(imageBuf, `${i + i}.jpeg`) compression.archiveAppend(imageBuf, `${i + i}.jpeg`)
infoLog( infoLog(
`[time consuming - generation] :${+new Date() - generationTime} ms \n` `[time consuming - generation] :${+new Date() - generationTime} ms \n`
) )
......
require('dotenv').config()
const {successLog, warnningLog} = require('../../utils/console')
const event = require('../../utils/event')
const {urls} = require('../../test.response')
const Screen = require('../generation/puppeteer')
;(async function () {
let screen = new Screen(urls)
// add event
event(screen)
// start time
let generatesTime = +new Date()
try {
// generate
await screen.startGenerate()
// console generate times
successLog(
`🎉 Picture successfully generated total consumption of ${
+new Date() - generatesTime
} ms \n`
)
} catch (e) {
// error
warnningLog(`screen.startGenerate had error:${JSON.stringify(e)}`)
process.exit(0)
}
})()
// module.exports = generates
module.exports = { module.exports = {
urls: [ urls: [
'https://www.weixiaotong.com.cn/weixt/mportal/microportal/newsdetail/1017975/0', 'https://www.weixiaotong.com.cn/weixt/mportal/microportal/newsdetail/1017975/0',
'https://www.weixiaotong.com.cn/weixt/mportal/microportal/newsdetail/1028700/%E8%82%B2%E5%84%BF%E7%9F%A5%E8%AF%86' 'https://www.weixiaotong.com.cn/weixt/mportal/microportal/newsdetail/1028700/%E8%82%B2%E5%84%BF%E7%9F%A5%E8%AF%86',
'http://www.weixiaotong.com.cn/weixt/login#/login',
'http://www.weixiaotong.com.cn/',
'http://www.weixiaotong.com.cn/index.php?m=&c=Article&a=pageinfo&aid=284',
'http://www.weixiaotong.com.cn/index.php?m=&c=Join&a=joinus',
'http://www.weixiaotong.com.cn/index.php?m=&c=Aboutus&a=index'
] ]
} }
const {warnningLog, log} = require('./console')
const os = require('os-utils')
const isMonitoringSystem = process.env.OPEN_MONITORING_SYSTEM - 0 // 系统cpu 使用监控
module.exports = function eventLog(event) {
if (!event) {
warnningLog('❌ node.event(EventEmitter) object is null')
return
}
if (isMonitoringSystem) {
// 打印os资源使用情况(Usage/Free)
event.on('os', () => {
// cpu - 1s后
logCpuInfo()
// memory
setTimeout(() => {
logFreemem()
}, 1000)
})
}
}
logCpuInfo = () => {
os.cpuUsage(v => warnningLog('\nCPU Usage (%): ' + numberFix(v * 100)))
os.cpuFree(v => warnningLog('CPU Free(%): ' + numberFix(v * 100)))
}
logFreemem = () => {
let freememCout = numberFix(os.freemem())
warnningLog(`Free memory :${freememCout}`)
}
function numberFix(number) {
return Number(number).toFixed(3)
}
const ora = require('ora')
const chalk = require('chalk')
const spinner = ora()
let lastMsg = null
let isPaused = false
exports.logWithSpinner = (symbol, msg) => {
if (!msg) {
msg = symbol
symbol = chalk.green('✔')
}
if (lastMsg) {
spinner.stopAndPersist({
symbol: lastMsg.symbol,
text: lastMsg.text
})
}
spinner.text = ' ' + msg
lastMsg = {
symbol: symbol + ' ',
text: msg
}
spinner.start()
}
exports.stopSpinner = persist => {
if (lastMsg && persist !== false) {
spinner.stopAndPersist({
symbol: lastMsg.symbol,
text: lastMsg.text
})
} else {
spinner.stop()
}
lastMsg = null
}
exports.pauseSpinner = () => {
if (spinner.isSpinning) {
spinner.stop()
isPaused = true
}
}
exports.resumeSpinner = () => {
if (isPaused) {
spinner.start()
isPaused = false
}
}
exports.failSpinner = text => {
spinner.fail(text)
}
var os = require('os-utils')
os.cpuUsage(function (v) {
console.log('CPU Usage (%): ' + v)
})
os.cpuFree(function (v) {
console.log('CPU Free:' + v)
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment