├── pdf ├── cover.pdf └── inside.pdf ├── .vscode └── settings.json ├── package.json ├── scrapers └── jobs1.js ├── .gitignore └── index.js /pdf/cover.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrahimAkar/Amazon-KDP-Automater/HEAD/pdf/cover.pdf -------------------------------------------------------------------------------- /pdf/inside.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BrahimAkar/Amazon-KDP-Automater/HEAD/pdf/inside.pdf -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "activityBar.background": "#4B220F", 4 | "titleBar.activeBackground": "#693014", 5 | "titleBar.activeForeground": "#FEFBF9" 6 | } 7 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "amazonKDP", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon index.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "express": "^4.17.1", 15 | "jsdom": "^16.2.2", 16 | "random-int": "^2.0.1", 17 | "unique-random-array": "^2.0.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scrapers/jobs1.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs").promises; 2 | const uniqueRandomArray = require("unique-random-array"); 3 | const puppeteer = require("puppeteer"); 4 | const randomInt = require("random-int"); 5 | const jsdom = require("jsdom"); 6 | const { JSDOM } = jsdom; 7 | async function GetJobs() { 8 | const browser = await puppeteer.launch({ 9 | headless: false, 10 | defaultViewport: null, 11 | }); 12 | const page = await browser.newPage(); 13 | 14 | await page.setDefaultTimeout(0); 15 | 16 | // ! Go to website 17 | await page.goto( 18 | // "https://kdp.amazon.com/en_US/title-setup/paperback/new/details?ref_=kdp_BS_D_cr_ti" 19 | "https://dot-job-descriptions.careerplanner.com/" 20 | ); 21 | await page.waitFor(randomInt(1298, 1419)); 22 | 23 | randomInt(298, 819); 24 | const xpath_expression = 25 | "//a[contains(@href,'https://DOT-Job-Descriptions.careerplanner.com')]"; 26 | await page.waitForXPath(xpath_expression); 27 | const links = await page.$x(xpath_expression); 28 | const link_urls = await page.evaluate((...links) => { 29 | return links.map((e) => e.textContent); 30 | }, ...links); 31 | 32 | jobsObj = []; 33 | link_urls.forEach((el) => { 34 | jobsObj.push({ 35 | JobName: el, 36 | }); 37 | }); 38 | 39 | console.log(jobsObj); 40 | fs.writeFile("./1.json", JSON.stringify(jobsObj)); 41 | } 42 | 43 | GetJobs(); 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/node 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=node 4 | 5 | ### Node ### 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # TypeScript v1 declaration files 50 | typings/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Microbundle cache 62 | .rpt2_cache/ 63 | .rts2_cache_cjs/ 64 | .rts2_cache_es/ 65 | .rts2_cache_umd/ 66 | 67 | # Optional REPL history 68 | .node_repl_history 69 | 70 | # Output of 'npm pack' 71 | *.tgz 72 | 73 | # Yarn Integrity file 74 | .yarn-integrity 75 | 76 | # dotenv environment variables file 77 | .env 78 | .env.test 79 | 80 | # parcel-bundler cache (https://parceljs.org/) 81 | .cache 82 | 83 | # Next.js build output 84 | .next 85 | 86 | # Nuxt.js build / generate output 87 | .nuxt 88 | dist 89 | 90 | # Gatsby files 91 | .cache/ 92 | # Comment in the public line in if your project uses Gatsby and not Next.js 93 | # https://nextjs.org/blog/next-9-1#public-directory-support 94 | # public 95 | 96 | # vuepress build output 97 | .vuepress/dist 98 | 99 | # Serverless directories 100 | .serverless/ 101 | 102 | # FuseBox cache 103 | .fusebox/ 104 | 105 | # DynamoDB Local files 106 | .dynamodb/ 107 | 108 | # TernJS port file 109 | .tern-port 110 | 111 | # Stores VSCode versions used for testing VSCode extensions 112 | .vscode-test 113 | 114 | # End of https://www.toptal.com/developers/gitignore/api/node 115 | cookies.json 116 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs").promises; 2 | const uniqueRandomArray = require("unique-random-array"); 3 | const puppeteer = require("puppeteer"); 4 | const randomInt = require("random-int"); 5 | const express = require("express"); 6 | const app = express(); 7 | 8 | async function runIt() { 9 | const browser = await puppeteer.launch({ 10 | headless: false, 11 | defaultViewport: null, 12 | }); 13 | const page = await browser.newPage(); 14 | 15 | // ! Import cookies 16 | const cookiesString = await fs.readFile("./cookies.json"); 17 | const cookies = JSON.parse(cookiesString); 18 | await page.setCookie(...cookies); 19 | await page.setDefaultTimeout(0); 20 | 21 | // ! Go to kdp dashboard 22 | await page.goto( 23 | // "https://kdp.amazon.com/en_US/title-setup/paperback/new/details?ref_=kdp_BS_D_cr_ti" 24 | "https://kdp.amazon.com/en_US/title-setup/paperback/new/details?ref_=kdp_BS_D_cr_ti" 25 | ); 26 | await page.waitFor(randomInt(1298, 1419)); 27 | 28 | // ! Title 29 | await page.click("#data-print-book-title"); 30 | randomInt(1298, 2419); 31 | await page.type("#data-print-book-title", "Hi I'M TITLE", { 32 | delay: 120, 33 | }); 34 | 35 | // ! Subtitle 36 | randomInt(1298, 1419); 37 | await page.click("#data-print-book-subtitle"); 38 | randomInt(298, 419); 39 | await page.type("#data-print-book-subtitle", "Hi I'M A SUBTITLE", { 40 | delay: 120, 41 | }); 42 | 43 | // ! First name 44 | randomInt(298, 519); 45 | await page.click("#data-print-book-primary-author-first-name"); 46 | randomInt(28, 191); 47 | await page.type( 48 | "#data-print-book-primary-author-first-name", 49 | "Hi I'M A FIRST NAME", 50 | { delay: 120 } 51 | ); 52 | 53 | // ! Last name 54 | randomInt(298, 419); 55 | await page.click("#data-print-book-primary-author-last-name"); 56 | 57 | randomInt(298, 819); 58 | await page.type( 59 | "#data-print-book-primary-author-last-name", 60 | "HY I'M A LAST NAME", 61 | { 62 | delay: 120, 63 | } 64 | ); 65 | 66 | // ! Description 67 | randomInt(118, 719); 68 | await page.click("#data-print-book-description"); 69 | randomInt(192, 619); 70 | await page.type("#data-print-book-description", "Hi I'M A DESCRIPTION", { 71 | delay: 120, 72 | }); 73 | 74 | // ! Select no public domain 75 | await page.waitFor(randomInt(1298, 8419)); 76 | await page.click("#non-public-domain", { 77 | delay: 25, 78 | }); 79 | 80 | // ! SUBTITLE 1 81 | await page.waitFor(randomInt(2000, 3555)); 82 | await page.click("#data-print-book-keywords-0"); 83 | await page.type("#data-print-book-keywords-0", "HY I'M A SUBTITLE 1", { 84 | delay: randomInt(150, 250), 85 | }); 86 | 87 | // ! SUBTITLE 2 88 | await page.waitFor(randomInt(2000, 3555)); 89 | await page.click("#data-print-book-keywords-1"); 90 | await page.type("#data-print-book-keywords-1", "HY I'M A SUBTITLE 2", { 91 | delay: randomInt(150, 250), 92 | }); 93 | 94 | // ! SUBTITLE 3 95 | await page.waitFor(randomInt(2000, 3555)); 96 | await page.click("#data-print-book-keywords-2"); 97 | await page.type("#data-print-book-keywords-2", "HY I'M A SUBTITLE 3", { 98 | delay: randomInt(150, 250), 99 | }); 100 | 101 | // ! SUBTITLE 4 102 | await page.waitFor(randomInt(2000, 3555)); 103 | await page.click("#data-print-book-keywords-3"); 104 | await page.type("#data-print-book-keywords-3", "HY I'M A SUBTITLE 4", { 105 | delay: randomInt(150, 250), 106 | }); 107 | 108 | // ! SUBTITLE 5 109 | await page.waitFor(randomInt(2000, 3555)); 110 | await page.click("#data-print-book-keywords-4"); 111 | await page.type("#data-print-book-keywords-4", "HY I'M A SUBTITLE 5", { 112 | delay: randomInt(150, 250), 113 | }); 114 | 115 | // ! SUBTITLE 6 116 | await page.waitFor(randomInt(2000, 3555)); 117 | await page.click("#data-print-book-keywords-5"); 118 | await page.type("#data-print-book-keywords-5", "HY I'M A SUBTITLE 6", { 119 | delay: randomInt(150, 250), 120 | }); 121 | 122 | // ! SUBTITLE 7 123 | await page.waitFor(randomInt(2000, 3555)); 124 | await page.click("#data-print-book-keywords-6"); 125 | await page.type("#data-print-book-keywords-6", "HY I'M A SUBTITLE 7", { 126 | delay: randomInt(150, 250), 127 | }); 128 | 129 | // ! Categories 130 | await page.click("#data-print-book-categories-button-proto-announce"); 131 | await page.waitFor(5000); 132 | await page.waitFor(randomInt(5000, 5222)); 133 | 134 | // ! Expand all links 135 | await page.$$eval("#category-chooser-popover .a-link-normal", (links) => 136 | links.forEach((link) => link.click()) 137 | ); 138 | await page.waitFor(2000); 139 | await page.click("#data-print-book-categories-button-proto-announce"); 140 | await page.click("#unsaved-changes-cancel-announce"); 141 | await page.waitFor(25000); 142 | 143 | // ! Select the excact categories 144 | await page.$$eval(".a-label", (links) => 145 | links.forEach((el) => { 146 | el.textContent === "Global Warming & Climate Change" ? el.click() : true; 147 | el.textContent === "Meteorology & Climatology" ? el.click() : true; 148 | }) 149 | ); 150 | // * Click save 151 | await page.waitFor(5000); 152 | await page.$$eval(".a-button-input", (elements) => elements[4].click()); 153 | 154 | // ! Adult RadioButton 155 | await page.waitFor(randomInt(2000, 3000)); 156 | await page.$$eval(".jele-override-input-width-radio input", (elements) => 157 | elements[0].click() 158 | ); 159 | 160 | // ! Save first page and continue 161 | await page.waitFor(randomInt(2000, 3000)); 162 | await page.click("#save-and-continue-announce"); 163 | 164 | // ! Get Free ISBN 165 | await page 166 | .waitForFunction( 167 | "document.querySelector('#free-print-isbn-btn-announce') && document.querySelector('#free-print-isbn-btn-announce').clientHeight != 0" 168 | ) 169 | .then(() => console.log("got it!")); 170 | await page.click("#free-print-isbn-btn-announce"); 171 | await page.waitFor(randomInt(1000, 2000)); 172 | await page.click("#print-isbn-confirm-button-announce"); 173 | await page.waitFor(randomInt(4000, 5000)); 174 | 175 | // ! Upload Interior 176 | const inputUploadHandle = await page.$( 177 | "#data-print-book-publisher-interior-file-upload-AjaxInput" 178 | ); 179 | let fileToUpload = "./pdf/inside.pdf"; 180 | inputUploadHandle.uploadFile(fileToUpload); 181 | 182 | // ! Check if interior uploading is started 183 | await page 184 | .waitForXPath("//*[@class='success-header' and contains(., 'inside.pdf')]") 185 | .then((res) => console.log("Upload your interior process is started ✅")); 186 | 187 | // ! Check if interior processing is started 188 | await page 189 | .waitForXPath( 190 | "//*[@id='data-print-book-publisher-interior-file-upload-success' and contains(., 'Processing your file...')]" 191 | ) 192 | .then((res) => console.log("Processing your interior is started... ✅")); 193 | 194 | // ! Check if interior processing is finished 195 | await page 196 | .waitForFunction( 197 | () => 198 | document.querySelector( 199 | "#data-print-book-publisher-interior-file-upload-success > div > div" 200 | ).innerHTML === "" 201 | ) 202 | .then((res) => console.log("your interior processing is finished ✅")); 203 | await page.waitFor(randomInt(2512, 3211)); 204 | 205 | // ! Upload Cover 206 | await page 207 | .$$eval( 208 | "#data-print-book-publisher-cover-choice-accordion > div.a-box.a-last > div > div.a-accordion-row-a11y > a > i", 209 | (elements) => elements[0].click() 210 | ) 211 | .then((el) => console.log("Upload your cover process is started ✅")); 212 | const CoverUploadHandle = await page.$( 213 | "#data-print-book-publisher-cover-file-upload-AjaxInput" 214 | ); 215 | let coverFile = "./pdf/cover.pdf"; 216 | CoverUploadHandle.uploadFile(coverFile); 217 | 218 | // ! Check if interior processing is started 219 | await page 220 | .waitForXPath( 221 | "//*[@id='data-print-book-publisher-cover-file-upload-success' and contains(., 'Processing your file...')]" 222 | ) 223 | .then((res) => console.log("Processing your cover is started... ✅")); 224 | 225 | // ! Check if interior processing is finished 226 | await page 227 | .waitForFunction( 228 | () => 229 | document.querySelector( 230 | "#data-print-book-publisher-cover-file-upload-success > div > div" 231 | ).innerHTML === "" 232 | ) 233 | .then((res) => console.log("Your cover processing is finished 😎")); 234 | await page.waitFor(randomInt(5900, 6211)); 235 | 236 | // ! Click Preview 237 | await page 238 | .click("#print-preview-noconfirm-announce") 239 | .then((res) => console.log("Click Preview")); 240 | await page 241 | .waitForFunction(() => document.querySelector(".coverSpine")) 242 | .then((res) => console.log("Your cover preview is fully loaded 😎")); 243 | 244 | await page.waitFor(randomInt(5500, 6500)); 245 | 246 | // ! Click Save 247 | await page 248 | .click(" #printpreview_approve_button_enabled a") 249 | .then((res) => console.log("Click Save")); 250 | 251 | // ! Go to third page 252 | await page 253 | .waitForFunction( 254 | "document.querySelector('#save-and-continue-announce') && document.querySelector('#save-and-continue-announce').clientHeight != 0" 255 | ) 256 | .then(() => console.log("got it 2!")); 257 | 258 | await page 259 | .click("#save-and-continue-announce") 260 | .then((res) => console.log("Going to third page ")); 261 | 262 | // ! Type a Price 263 | await page 264 | .waitForFunction( 265 | "document.querySelector('#data-pricing-print-us-price-input > input') && document.querySelector('#data-pricing-print-us-price-input > input').clientHeight != 0" 266 | ) 267 | .then(() => console.log("got it 3!")); 268 | await page.evaluate( 269 | () => 270 | (document.querySelector( 271 | "#data-pricing-print-us-price-input > input" 272 | ).value = "") 273 | ); 274 | await page.type("#data-pricing-print-us-price-input > input", "99.99", { 275 | delay: 120, 276 | }); 277 | await page.waitFor(5000); 278 | 279 | // ! Click Expanded Distribution 280 | await page.click("#data-pricing-print label > i"); 281 | 282 | // ! Click save to draft 283 | await page.waitFor(2000); 284 | await page.click("#save-announce"); 285 | 286 | await page 287 | .waitForFunction(() => 288 | document.querySelector( 289 | "#data-pricing-print div.a-column.a-span3.a-span-last > div > div > span" 290 | ) 291 | ) 292 | .then((res) => console.log("Prices are okay!")); 293 | // 294 | } 295 | 296 | app.get("/kdp", async (req, res) => { 297 | try { 298 | res.send({ message: "OK" }); 299 | await runIt(); 300 | } catch (error) { 301 | res.send({ message: "NOT OK" }); 302 | } 303 | }); 304 | 305 | app.listen(4666, () => { 306 | console.log("SERVER STARTED WITH SUCCESS"); 307 | }); 308 | --------------------------------------------------------------------------------