Automasi max.ai converter PDF to HTML
Tech : Node.js (common), Socket.io, Puppeteer
target : https://www.maxai.co/pdf-tools/pdf-to-html/
selector :
1. input = <input type="file" title="" accept="application/pdf" multiple="" class="css-1gcv6dl">
2. finish button = <button class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeLarge MuiButton-containedSizeLarge MuiButton-colorPrimary MuiButton-disableElevation MuiButton-fullWidth MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeLarge MuiButton-containedSizeLarge MuiButton-colorPrimary MuiButton-disableElevation MuiButton-fullWidth css-y450x3" tabindex="0" type="button"><p class="MuiTypography-root MuiTypography-body1 css-1ncveae">Finish</p><svg class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-10lx4aw" focusable="false" aria-hidden="true" viewBox="0 0 24 24" data-testid="EastIcon"><path d="m15 5-1.41 1.41L18.17 11H2v2h16.17l-4.59 4.59L15 19l7-7z"></path></svg><span class="MuiTouchRipple-root css-w0pj6f"></span></button>
3. download button = <button class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButton-colorPrimary MuiButton-disableElevation MuiButton-fullWidth MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButton-colorPrimary MuiButton-disableElevation MuiButton-fullWidth css-1kwztf9" tabindex="0" type="button"><div class="MuiBox-root css-axw7ok"><svg class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-wbvhrc" focusable="false" aria-hidden="true" viewBox="0 0 24 24" data-testid="FileDownloadOutlinedIcon"><path d="M18 15v3H6v-3H4v3c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2v-3zm-1-4-1.41-1.41L13 12.17V4h-2v8.17L8.41 9.59 7 11l5 5z"></path></svg><p class="MuiTypography-root MuiTypography-body1 css-ww1t3z">Download</p></div><span class="MuiTouchRipple-root css-w0pj6f"></span></button>
4. new upload = <button class="MuiButtonBase-root MuiButton-root MuiButton-outlined MuiButton-outlinedPrimary MuiButton-sizeMedium MuiButton-outlinedSizeMedium MuiButton-colorPrimary MuiButton-disableElevation MuiButton-fullWidth MuiButton-root MuiButton-outlined MuiButton-outlinedPrimary MuiButton-sizeMedium MuiButton-outlinedSizeMedium MuiButton-colorPrimary MuiButton-disableElevation MuiButton-fullWidth css-bty1zy" tabindex="0" type="button"><div class="MuiBox-root css-axw7ok"><svg class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-wbvhrc" focusable="false" aria-hidden="true" viewBox="0 0 24 24" data-testid="RestartAltOutlinedIcon"><path d="M6 13c0-1.65.67-3.15 1.76-4.24L6.34 7.34C4.9 8.79 4 10.79 4 13c0 4.08 3.05 7.44 7 7.93v-2.02c-2.83-.48-5-2.94-5-5.91m14 0c0-4.42-3.58-8-8-8-.06 0-.12.01-.18.01l1.09-1.09L11.5 2.5 8 6l3.5 3.5 1.41-1.41-1.08-1.08c.06 0 .12-.01.17-.01 3.31 0 6 2.69 6 6 0 2.97-2.17 5.43-5 5.91v2.02c3.95-.49 7-3.85 7-7.93"></path></svg><p class="MuiTypography-root MuiTypography-body1 css-ww1t3z">Start over</p></div><span class="MuiTouchRipple-root css-w0pj6f"></span></button>
Puppeteernya buatkan safe/stealth
berikut existing project structurenya:
pacakge.json
{
"name": "pdftohtml_cvgen",
"version": "1.0.0",
"description": "",
"homepage": "https://github.com/refkinscallv/pdftohtml_cvgen#readme",
"bugs": {
"url": "https://github.com/refkinscallv/pdftohtml_cvgen/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/refkinscallv/pdftohtml_cvgen.git"
},
"license": "MIT",
"author": "Refkinscallv <refkinscallv@gmail.com>",
"type": "commonjs",
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node src/index.js",
"dev": "nodemon",
"format": "prettier --ignore-path .prettierignore --write src/**/*.js"
},
"dependencies": {
"@refkinscallv/express-routing": "^1.2.1",
"dotenv": "^17.2.1",
"puppeteer-extra": "^3.3.6",
"puppeteer-extra-plugin-stealth": "^2.11.2",
"socket.io": "^4.8.1"
},
"devDependencies": {
"nodemon": "^3.1.10",
"prettier": "^3.6.2"
}
}
nodemon.json
{
"watch": ["src"],
"ext": "js",
"exec": "node ./src/index.js"
}
src/index.js
const Boot = require('./boot')
Boot.run({
server: {
url: 'http://localhost:3456',
port: 3456,
},
})
src/boot.js
const Boot = require('./boot')
Boot.run({
server: {
url: 'http://localhost:3456',
port: 3456,
},
})
src/server.js
const http = require('http')
module.exports = class Server {
static server = null
static init(data) {
const { port, url } = data
this.server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html' })
res.end('Server is running\n')
})
this.server.listen(port, () => {
console.log([SERVER] Application already running : ${url || http://localhost:${port}})
})
this.server.on('error', (err) => {
console.error('[SERVER] Error:', err.message)
})
}
}
src/socket.js
const { Server: SocketIO } = require('socket.io')
const Server = require('./server')
module.exports = class Socket {
static io = null
static init() {
this.io = new SocketIO(Server.server, {
cors: { origin: '*' }
})
this.io.on('connection', (socket) => {
console.log('[SOCKET] Client connected:', socket.id)
socket.on('disconnect', () => {
console.log('[SOCKET] Client disconnected:', socket.id)
})
})
}
}
tinggal puppeteer yang belum