1
0
Code Issues Pull Requests Projects Releases Wiki Activity GitHub Gitee
tools/财智Aisino微信小程序音频课程下载/index.js

240 lines
7.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var https = require('follow-redirects').https;
var fs = require('fs');
const path = require('path');
const base64Utils = require('../utils/base64Utils')
const { token, userId } = require('./config')
const outputDir = './output/' // 以 / 结尾
const courseDetailDir = 'courseDetail/' // 以 / 结尾
const downloadMediaDir = 'downloadMedia/' // 以 / 结尾
main()
async function main() {
// /**
// * Step 1 课程列表
// */
await getCourseList(1594)
// /**
// * Step 2 课程详情
// */
let courseListJson = fs.readFileSync(outputDir + 'courseList.json', 'utf8')
let courseList = JSON.parse(courseListJson).data.childs
await getCourseDetail(courseList)
/**
* Step 3 解析数据
*/
await parseCourseDetailJson()
/**
* Step 3 下载音频,保存课件
*/
await downloadMedia()
console.log('完成')
}
async function getCourseList(courseId) {
var options = {
'method': 'POST',
'hostname': 'wx.hxdkfp.com',
'path': '/czw-api/api-hypt-product/hypt/product/getProductInfo?id=' + courseId + '&serviceType=3&userId=' + userId,
'headers': {
'token': token
},
// 'maxRedirects': 20,
'rejectUnauthorized': false
};
await httpsRequest(options, outputDir + 'courseList.json')
}
async function getCourseDetail(courseList) {
// console.log(courseList)
for (let i = 0; i < courseList.length; i++) {
const courseDetail = courseList[i]
/*
{
id: 2662,
serviceType: '1',
imgUrl: 'e41f693bbfe4442d8c611633644802fc.jpg',
publishTime: '2023-09-11 00:00:00',
serviceName: '【第559期】关于耕地占用税的那些事儿',
serviceOrder: 1,
serviceStatus: '0',
isCard: '0',
isFree: '1',
realPrice: '5',
labelNum: '1',
labelName: '音频',
verificationCodeFlag: false,
serviceStatusName: '上架',
downButtonFlag: true,
agreementString: ''
},
*/
const courseDetailId = courseDetail.id
const courseDetailName = courseDetail.serviceName
console.log(`${i}\t| ${courseDetailId} | ${courseDetailName}`)
try {
let options = {
'method': 'POST',
'hostname': 'wx.hxdkfp.com',
'path': '/czw-api/api-hypt-product/hypt/product/getProductInfo?id=' + courseDetailId + '&serviceType=1&userId=' + userId,
'headers': {
'token': token
},
// 'maxRedirects': 20,
'rejectUnauthorized': false
};
await httpsRequest(options, outputDir + courseDetailDir + courseDetailId + '.json')
console.log('\t完成')
await waitAMinute()
} catch (err) {
console.error(err)
}
}
}
async function parseCourseDetailJson() {
const dirPath = outputDir + courseDetailDir
var infoDir = [
// {
// name: '',
// audioUrl: '',
// publishTime: '',
// brief: '',
// detail: '',
// }
]
// 读取目录下的所有文件名
const files = fs.readdirSync(dirPath);
for (let file of files) {
// 拼接文件的完整路径
const filePath = path.join(dirPath, file);
// 读取文件的内容
let fileContent = fs.readFileSync(filePath, 'utf8');
const jsonObj = JSON.parse(fileContent);
const data = jsonObj.data
const brief = base64Utils.base64_decode(data.briefString)
const detail = base64Utils.base64_decode(data.detailString)
const filename = deleteFilenameUnsupportChar(data.serviceName)
// 打印文件名和文件内容
console.log(file);
infoDir.push({
name: filename,
audioUrl: data.audioUrl,
// publishTime: data.publishTime,
// brief: brief,
// detail: detail,
})
fs.writeFileSync(outputDir + downloadMediaDir + filename + '-简介.html', brief, 'utf8')
fs.writeFileSync(outputDir + downloadMediaDir + filename + '-详情.html', detail, 'utf8')
}
fs.writeFileSync(outputDir + 'parsedCourseDetails.json', JSON.stringify(infoDir, null, 4), 'utf8')
}
async function downloadMedia() {
const parsedCourseDetails = JSON.parse(fs.readFileSync(outputDir + 'parsedCourseDetails.json', 'utf8'))
for (let i = 0; i < parsedCourseDetails.length; i++) {
const item = parsedCourseDetails[i]
const audioUrl = item.audioUrl
const filename = item.name
const fileNameWithExt = audioUrl.lastIndexOf('.') != -1
? filename + audioUrl.substring(audioUrl.lastIndexOf('.'))
: filename
console.log(`${i}\t| ${fileNameWithExt} | ${item.audioUrl}`)
try {
await downloadFile(audioUrl, outputDir + downloadMediaDir + fileNameWithExt)
} catch (err) {
console.error(err)
}
await waitAMinute()
}
}
// 公共请求方法
async function httpsRequest(options, fileneme) {
return await new Promise((resolve) => {
var req = https.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function (chunk) {
var body = Buffer.concat(chunks);
var result = body.toString()
// console.log(result);
fs.writeFileSync(fileneme, result, 'utf8')
resolve(result)
});
res.on("error", function (error) {
console.error(error);
});
});
req.end();
})
}
async function waitAMinute() {
return await new Promise((resolve) => {
setTimeout(resolve, 100)
})
}
function deleteFilenameUnsupportChar(name) {
return name
.replace(/\?/g, "")
.replace(/\:/g, "")
.replace(/\t/g, " ")
.replace(/"/g, "''")
}
/**
*
* @param {*} fileUrl 要下载的文件的 url
* @param {*} downloadPath 要保存的文件的路径
*/
async function downloadFile(fileUrl, downloadPath) {
return await new Promise((resolve, reject) => {
// 创建一个可写的文件流
const file = fs.createWriteStream(downloadPath);
// 发起 https 请求,获取响应流
const request = https.request(fileUrl, response => {
// 将响应流写入文件流
response.pipe(file);
// 监听文件流的 finish 事件,表示下载完成
file.on("finish", () => {
// 关闭文件流
file.close();
// 打印下载成功的消息
console.log("\t文件下载完毕");
resolve()
});
});
// 监听请求的 error 事件,表示下载失败
request.on("error", err => {
// 删除已下载的文件
fs.unlink(downloadPath, () => {
// 打印下载失败的消息
console.error(`\t下载失败: ${err.message}`);
reject()
});
});
// 结束请求
request.end();
})
}