temu-labels-crawler/download-shipping-labels.js

369 lines
12 KiB
JavaScript

const puppeteer = require("puppeteer");
const axios = require("axios");
const luxon = require("luxon");
const { exit } = require("process");
const fs = require("fs");
const path = require("path");
const dotenv = require("dotenv").config({ path: __dirname + "/.env" });
const utils = require("./utils");
(async function () {
console.log(
`===========< STARTED --- DOWNLOAD SHIPPING LABELS ${luxon.DateTime.now()} >=========`
);
const syncDate = luxon.DateTime.now().toFormat("yyyy-MM-dd");
/**
* loading config data
*/
const config = JSON.parse(fs.readFileSync(__dirname + "/config.json"));
const environment = process.env["ENVIRONMENT"];
const cryptoConfig = utils.getCryptoConfig();
let rates = [];
const email = utils.decryptString(
process.env["temu-email"],
cryptoConfig.algo,
cryptoConfig.key,
cryptoConfig.iv
);
const password = utils.decryptString(
process.env["temu-password"],
cryptoConfig.algo,
cryptoConfig.key,
cryptoConfig.iv
);
/*
* load cookies
*/
const loadPageCookies = async function (page) {
const cookiesFileName = `cookies.json`;
if (fs.existsSync(__dirname + `/cookies/${cookiesFileName}`)) {
const cookiesStr = fs.readFileSync(
__dirname + `/cookies/${cookiesFileName}`
);
const cookies = JSON.parse(cookiesStr);
await page.setCookie(...cookies);
}
};
// launch browser and open page
const chromeProfilePath = path.resolve(
__dirname,
config[environment]["chrome_profile_path"]
);
const browser = await puppeteer.launch(
utils.getBrowserConfig(chromeProfilePath, environment)
);
const page = await browser.newPage();
await loadPageCookies(page);
await page.setViewport({
width: 1600,
height: 900,
});
// Inject CSS to show the cursor
await page.evaluate(() => {
const style = document.createElement("style");
style.innerHTML = "* { cursor: auto !important; }";
document.head.appendChild(style);
});
// save cookies on page load
const cookiesFileName = `cookies.json`;
page.on("load", async function () {
// save cookies
const cookies = await page.cookies();
fs.writeFileSync(
__dirname + `/cookies/${cookiesFileName}`,
JSON.stringify(cookies, null, 2)
);
});
/*
* goto login page
*/
const loginPage = config[environment]["temuLoginPage"];
await page.goto(loginPage, {
waitUntil: ["domcontentloaded"],
});
await utils.tryTemuLogin(page, email, password, loginPage);
await new Promise((resolve) => setTimeout(resolve, 7000));
// goto orders request page
const shippedOrdersRequestPage = config[environment]["temuShippedOrdersPage"];
await page.goto(shippedOrdersRequestPage, {
waitUntil: ["domcontentloaded"],
});
/*
* configure download path of excel report
*/
const generateTheDownloadPath = async function (page, downloadPath) {
// create client session for configuration
const client = await page.target().createCDPSession();
// set the download path
await client.send("Page.setDownloadBehavior", {
behavior: "allow",
downloadPath: downloadPath, // Change this to your desired download path.
});
};
/*
* data
*/
const pagination = 100;
let total_items = 0;
let currentPage = 1;
let maxPage = 10;
/**
* Capture response
*/
const checkShippingLabelResponse = async (page, timer) => {
return new Promise((resolve, reject) => {
// Timeout mechanism to resolve with an empty list after 5 seconds
const timeout = setTimeout(() => {
page.off("response", handleResponse); // Remove listener on timeout
resolve([]); // Resolve with an empty list
}, timer);
const handleResponse = async (res) => {
try {
const req = res.request();
if (req.url().includes("/batch_print_shipping_label")) {
const resJson = await res.json();
// Remove listener and clear timeout once response is captured
clearTimeout(timeout);
page.off("response", handleResponse);
resolve(resJson || []);
}
} catch (ex) {
// Remove listener and clear timeout on error
clearTimeout(timeout);
page.off("response", handleResponse);
reject(ex);
}
};
page.on("response", handleResponse);
});
};
const downloadFolderPath = path.resolve(
config[environment].temu_order_shipping_labels_path,
`unprocessed/`
);
const processedFolderPath = path.resolve(
config[environment].temu_order_shipping_labels_path,
`processed/`
);
/*
* download labels
*/
const downloadAndUploadShippingLabels = async (page) => {
try {
let bIndex = 0;
// PO Selector
const orderPOSelector = "div._3GLf87F3";
const orderPoList = await page.$$(orderPOSelector);
// select all print buttons
const buttonSelector = "div._37Oz7wUV";
const buttons = await page.$$(buttonSelector);
for (const button of buttons) {
try {
const text = await page.evaluate(
(el) => el.textContent.trim(),
button
);
if (text === "Print documents") {
console.log(`Button : ${bIndex}`);
await button.click(); // Click the button
await new Promise((resolve) => setTimeout(resolve, 2000));
try {
// check modal apears
await page.waitForSelector("div._1sNAa0oS.r4S9S0F2", {
timeout: 3000,
});
} catch (ex) {
console.log(`label Not present for Index : ${bIndex}`);
bIndex++;
continue;
}
await new Promise((resolve) => setTimeout(resolve, 2000));
const responsePromise = checkShippingLabelResponse(page, 5_000);
// click on download document tab
const downloadDocumentSelector =
"body > div.MDL_outerWrapper_123.MDL_modal_123 > div > div > div > div.MDL_body_123.MDL_noHeader_123 > div._1sNAa0oS.r4S9S0F2 > div._1zajAtWr > div > div > div.TAB_topWrapper_123.TAB_lineWrapper_123.TAB_topLineBelow_123.TAB_top_123 > div > div:nth-child(2) > div > span";
await page.waitForSelector(downloadDocumentSelector);
await page.click(downloadDocumentSelector);
await new Promise((resolve) => setTimeout(resolve, 1_000));
// click on radio buttin
const radioButtonSelector =
"#downloadMethod > div > div.Grid_row_123.Grid_rowHorizontal_123.Grid_rowJustifyStart_123.Form_itemContent_123.Form_itemContentCenter_123 > div > div > label.RD_outerWrapper_123.RDG_OrOuterWrapper_123.RDG_radio_123.RDG_large_123.RDG_active_123.bc-HocRadio_outerWrapper_123.RD_large_123.RD_active_123.undefined.bc-HocRadio_active_123.RD_radio_123 > div.RD_textWrapper_123.RD_prevRadio_123";
await page.waitForSelector(radioButtonSelector);
await page.click(downloadDocumentSelector);
await new Promise((resolve) => setTimeout(resolve, 1_000));
// click on select
// const selectSelector =
// "#downLoadPreferredName > div > div.Grid_row_123.Grid_rowHorizontal_123.Grid_rowJustifyStart_123.Form_itemContent_123.Form_itemContentCenter_123 > div > div > div > div > div > div > div > div > div.IPT_inputBlockCell_123.ST_inputBlockCell_123";
// await page.waitForSelector(selectSelector);
// await page.click(selectSelector);
// await new Promise((resolve) => setTimeout(resolve, 1_000));
// // click on order option
// const optionSelector =
// "body > div.PT_outerWrapper_123.PP_outerWrapper_123.ST_dropdown_123.ST_largeDropdown_123.ST_customItem_123.PT_dropdown_123.PT_portalBottomLeft_123.PT_inCustom_123.PP_dropdown_123 > div > div > div > div > ul > div > div > li.cIL_item_123.cIL_large_123.cIL_active_123.ST_itemRendererLabel_123.ST_itemRendererLabelChecked_123 > div > span";
// await page.waitForSelector(optionSelector);
// await page.click(optionSelector);
// await new Promise((resolve) => setTimeout(resolve, 1_000));
generateTheDownloadPath(page, downloadFolderPath);
// click on Print button
const downloadDocumentBtnSelector =
"body > div.MDL_outerWrapper_123.MDL_modal_123 > div > div > div > div.MDL_body_123.MDL_noHeader_123 > div._1sNAa0oS.r4S9S0F2 > div.gpBGty5E._4PfVmBF- > div > div > div._2bhVasgL > div._3yOxLjm0._2pgGmJ7w._1eT_m6dA._2IBCXPHH > span._2ISpB3A2";
await page.waitForSelector(downloadDocumentBtnSelector);
// click on add dimension
await page.click(downloadDocumentBtnSelector);
console.log(`Click on download Document Btn`);
await new Promise((resolve) => setTimeout(resolve, 1_000));
// listen for api call
let labelResponse = await responsePromise;
// close modal
await new Promise((resolve) => setTimeout(resolve, 2_000));
const closeBtnSelector = "div._2hT9O4-z.Y9rEd1VR";
await page.waitForSelector(closeBtnSelector);
await page.click(closeBtnSelector);
console.log(bIndex);
const orderNumber = await page.evaluate(
(el) => el.textContent.trim(),
orderPoList[bIndex]
);
// Rename the file after download
const files = fs.readdirSync(downloadFolderPath);
console.log(`Order Number : ${orderNumber}`);
if (files.length > 0) {
const downloadedFilePath = path.join(
downloadFolderPath,
files[files.length - 1]
);
const renamedFilePath = path.join(
processedFolderPath,
`${orderNumber}.pdf`
);
fs.renameSync(downloadedFilePath, renamedFilePath);
console.log(`File downloaded and renamed to: ${renamedFilePath}`);
} else {
console.log("No file downloaded.");
}
bIndex++;
// extract the url and save in s3
// await s3Utils.downloadAndUploadToS3(labelUrl, poNumber);
}
} catch (e) {
console.log(e);
}
}
} catch (e) {
console.log(e);
}
};
try {
// get total items
await page
.waitForSelector("li.PGT_totalText_123", { timeout: 5000 })
.catch(() => {});
const liText = await page.evaluate(() => {
const liElement = document.querySelector("li.PGT_totalText_123");
return liElement ? liElement.textContent : null;
});
if (liText === null) {
total_items = 10;
} else {
total_items = parseInt(liText.split(" ")[1]);
console.log(`Total Items count : ${total_items}`);
}
let total_pages = Math.ceil(total_items / pagination);
console.log(`Total Pages count : ${total_pages}`);
// crawl next pages
while (true) {
try {
console.log(`Crawling for page ${currentPage}`);
await utils.tryTemuLogin(page, email, password, loginPage);
await new Promise((resolve) => setTimeout(resolve, 4_000));
// load cookies
await loadPageCookies(page);
// get labels from page
await downloadAndUploadShippingLabels(page);
await new Promise((resolve) => setTimeout(resolve, 20_000));
// increment page
++currentPage;
// Evaluate the presence of both classes in the <li> element
const hasNextBtn = await page.evaluate(() => {
const liElement = document.querySelector(
"li.PGT_next_123.PGT_disabled_123"
);
return liElement == null;
});
// break if doesn't have next button
if (!hasNextBtn) {
console.log("No next button");
break;
}
if (currentPage > maxPage || currentPage > total_pages) {
console.log("Last Page Reached");
break;
}
// goto next page
if (hasNextBtn) {
await page.evaluate(() => {
const liElement = document.querySelector("li.PGT_next_123");
if (liElement) {
liElement.click();
}
});
}
// wait
await new Promise((r) => setTimeout(r, 5000));
} catch (e) {
console.log(e);
}
}
} catch (e) {
console.log(e);
}
console.log(
`==========< ENDED --- DOWNLOAD SHIPPING LABELS ${luxon.DateTime.now()} >==========`
);
await page.close();
await browser.close();
})();