googlesheet
This commit is contained in:
6
cafe24/accounts.txt
Normal file
6
cafe24/accounts.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
# 아이디 비번 그룹넘버 구분
|
||||
# 공백, 탭, 콤마, | 구분자를 지원합니다.
|
||||
# 구분이 2 또는 shop2 처럼 숫자로 해석되면 해당 shop 번호로 요청합니다.
|
||||
geonuk0901 7@rkdhsflqld 2 롱맨카페
|
||||
geonuk0901 7@rkdhsflqld 1 룰루뷰카페
|
||||
bluemaxwith 7@rkdhsflqld 1 블루맥스카페
|
||||
710
cafe24/cafe24.ts
Normal file
710
cafe24/cafe24.ts
Normal file
@@ -0,0 +1,710 @@
|
||||
import axios from "axios";
|
||||
import { take } from "es-toolkit";
|
||||
import { mkdir } from "node:fs/promises";
|
||||
import { HyundaiCustomerVerifier } from "../hyundai/hyundaiCustomerVerifier";
|
||||
import { appendRowsToDailySheet } from "../sheet/googlesheetapi";
|
||||
|
||||
type MallUseAuthResponse = {
|
||||
STATUS: string;
|
||||
sEncData: string;
|
||||
sEncKey: string;
|
||||
sActionPath: string;
|
||||
};
|
||||
|
||||
type Account = {
|
||||
mallId: string;
|
||||
password: string;
|
||||
groupNo: string;
|
||||
division: string;
|
||||
shopNo: string;
|
||||
};
|
||||
|
||||
// const INITIAL_COOKIE =
|
||||
// "login_mode=1; PHPSESSID=df4dcdbed2d5be411d1ba57b28fe0572; _fwb=238EQK8z8Dup2CWqAOV9GHr.1777057879401; _gcl_au=1.1.1767964142.1777057879; _fbp=fb.1.1777057879522.988692189750068964; CUK45=cuk45_eckorea24_gkemvii10ntc5fghtaaqf9mg42vscrj4; CUK2Y=cuk2y_eckorea24_gkemvii10ntc5fghtaaqf9mg42vscrj4; CID=CIDR737c085badb1ba6805354e1bed9081de; CIDR737c085badb1ba6805354e1bed9081de=41a12ffaeb4b4614beaf5774fb1aaa15%3A%3A%3A%3A%3A%3A%3A%3A%3A%3A%3A%3A%3A%3A%3A%3A%3A%3A%3A%3A%2F%3A%3A1777057879%3A%3A%3A%3Appdp%3A%3A1777057879%3A%3A%3A%3A%3A%3A%3A%3A; basketcount_1=0; basketprice_1=0%EC%9B%90; wish_id=a6e247fd0eed9199543ec057cb0caf9e; wishcount_1=0; isviewtype=pc; _clck=1eo5hbc%5E2%5Eg5h%5E0%5E2305; analytics_session_id=analytics_session_id.eckorea24_1.E32D67B.1777057879666; analytics_longterm=analytics_longterm.eckorea24_1.B29FF1A.1775390402832; _hjSession_2368957=eyJpZCI6IjBmM2VkMzY4LTk1ZDItNGE3OS1hYjUyLTI2MDNjODhlZTg0YyIsImMiOjE3NzcwNTc4Nzk5MjcsInMiOjAsInIiOjAsInNiIjowLCJzciI6MCwic2UiOjAsImZzIjoxLCJzcCI6MX0=; vt=1777057880; _hjSessionUser_2368957=eyJpZCI6IjQzNmEwOGM5LWY0YmQtNTA3ZS05NTY5LTU2NTk1YjRkZjUwOSIsImNyZWF0ZWQiOjE3NzcwNTc4Nzk5MjYsImV4aXN0aW5nIjp0cnVlfQ==; CVID=CVID.54515f5b4a50510b076f05.1777057880748; CVID_Y=CVID_Y.54515f5b4a50510b076f05.1777057880748; ch-veil-id=5170f9b3-9125-4fa5-bc25-5a0588aa0193; ch-session-193477=eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzZXMiLCJleHAiOjE3Nzk2NDk4ODEsImlhdCI6MTc3NzA1Nzg4MSwia2V5IjoiMTkzNDc3LTY5ZDQ1MmI1NDc3NjYxODRmZmY4In0.ubvM5Ul3_5n32fs3Zc5oQHAmrVOClz7CFFczwD5Wt-o; _ga_12RF674XCD=GS2.2.s1777057881$o1$g0$t1777057881$j60$l0$h0; _ga_JC3MGH4M4T=GS2.2.s1777057880$o1$g1$t1777057880$j59$l0$h0; _ga=GA1.1.1282638454.1777057025; cto_bundle=Pm-nMl9OcHp0eWh3dmlOSUV0UGV0eHI2cEZ5R0J1c1J0bG1oUDdzdDNISjl3ZHc3ZmVQc215REpDYVFRd0IyZFYlMkZseW9lQ0kxY0NBM2NwJTJGU1RNZ21DR3pITm90TlZCaVlXd0I4JTJCOU9EaGZ6Mkk0TEhURFFiUklsVzJTaDc4OGN4c045eCUyQldOUkluaFdUVGhCaHdJbWl5RCUyQnh3JTNEJTNE; _clsk=49y69s%5E1777057881420%5E1%5E1%5Ee.clarity.ms%2Fcollect; _ga_ZTM1Z99BLE=GS2.2.s1777057880$o1$g1$t1777057882$j57$l0$h0; _ga_Z6CSBGDNRT=GS2.1.s1777057880$o1$g0$t1777057882$j58$l0$h0; GMCC=1dpUipix8zMJMXeWxnayh6U2Z%252Bwn64de5%252BGBE9t8ecAjkaNREGa5nViF811clijfk1asqmTpCYYgWGkGUVnYYiZloR4ksXOD8yT5BB%252FeAxw%253D; _ga_TW9JR58492=GS2.1.s1777057025$o1$g1$t1777057921$j21$l0$h0";
|
||||
const INITIAL_COOKIE = "";
|
||||
|
||||
const RESULT_DIR = "result";
|
||||
|
||||
export let cookie = INITIAL_COOKIE;
|
||||
export let dynamicHiddenFieldName = "";
|
||||
export let dynamicHiddenFieldValue = "";
|
||||
|
||||
let activeAccount: Account = {
|
||||
mallId: "",
|
||||
password: "",
|
||||
groupNo: "",
|
||||
division: "",
|
||||
shopNo: "",
|
||||
};
|
||||
|
||||
function getTodayKstDateString() {
|
||||
const parts = new Intl.DateTimeFormat("en-CA", {
|
||||
timeZone: "Asia/Seoul",
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
})
|
||||
.formatToParts(new Date())
|
||||
.reduce<Record<string, string>>((acc, part) => {
|
||||
if (part.type !== "literal") {
|
||||
acc[part.type] = part.value;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return `${parts.year}-${parts.month}-${parts.day}`;
|
||||
}
|
||||
|
||||
function isIsoDateString(value: string) {
|
||||
return /^\d{4}-\d{2}-\d{2}$/.test(value);
|
||||
}
|
||||
|
||||
function parseCliOptions() {
|
||||
const firstArg = Bun.argv[2]?.trim();
|
||||
const secondArg = Bun.argv[3]?.trim();
|
||||
|
||||
if (firstArg && isIsoDateString(firstArg)) {
|
||||
return {
|
||||
regDate: firstArg,
|
||||
accountsPath: secondArg || "./cafe24/accounts.txt",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
regDate: getTodayKstDateString(),
|
||||
accountsPath: firstArg || "./cafe24/accounts.txt",
|
||||
};
|
||||
}
|
||||
|
||||
const { regDate, accountsPath } = parseCliOptions();
|
||||
|
||||
function getAdminBaseUrl() {
|
||||
return `https://${activeAccount.mallId}.cafe24.com`;
|
||||
}
|
||||
|
||||
function getShopPath(path: string, shopNo = activeAccount.groupNo) {
|
||||
return `/admin/php/shop${shopNo}${path}`;
|
||||
}
|
||||
|
||||
function sanitizeFilePart(value: string) {
|
||||
return value.replace(/[^a-zA-Z0-9._-]+/g, "_");
|
||||
}
|
||||
|
||||
function getResultPrefix() {
|
||||
return [
|
||||
sanitizeFilePart(activeAccount.mallId),
|
||||
`shop${sanitizeFilePart(activeAccount.shopNo)}`,
|
||||
`group${sanitizeFilePart(activeAccount.groupNo)}`,
|
||||
sanitizeFilePart(activeAccount.division),
|
||||
].join("-");
|
||||
}
|
||||
|
||||
function getResultPath(fileName: string) {
|
||||
return `${RESULT_DIR}/${fileName}`;
|
||||
}
|
||||
|
||||
function appendCookie(setCookie: string | string[] | undefined) {
|
||||
const setCookieList = typeof setCookie === "string" ? [setCookie] : setCookie;
|
||||
|
||||
if (!setCookieList?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cookieMap = new Map(
|
||||
cookie
|
||||
.split(";")
|
||||
.map((part) => part.trim())
|
||||
.filter(Boolean)
|
||||
.map((part) => {
|
||||
const equalIndex = part.indexOf("=");
|
||||
return [part.slice(0, equalIndex), part.slice(equalIndex + 1)] as const;
|
||||
})
|
||||
);
|
||||
|
||||
for (const header of setCookieList) {
|
||||
const nameValue = header.split(";")[0]?.trim();
|
||||
if (!nameValue) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const equalIndex = nameValue.indexOf("=");
|
||||
if (equalIndex === -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cookieMap.set(
|
||||
nameValue.slice(0, equalIndex),
|
||||
nameValue.slice(equalIndex + 1)
|
||||
);
|
||||
}
|
||||
|
||||
cookie = [...cookieMap.entries()]
|
||||
.map(([name, value]) => `${name}=${value}`)
|
||||
.join("; ");
|
||||
}
|
||||
|
||||
function extractDynamicHiddenField(html: string) {
|
||||
const hiddenInputs =
|
||||
html.match(/<input\b[^>]*\btype=["']hidden["'][^>]*>/gi) ?? [];
|
||||
|
||||
for (const input of hiddenInputs) {
|
||||
const nameMatch = input.match(/\bname=["']([^"']*)["']/i);
|
||||
const valueMatch = input.match(/\bvalue=["']([^"']*)["']/i);
|
||||
const name = nameMatch?.[1] ?? "";
|
||||
const value = valueMatch?.[1] ?? "";
|
||||
if (
|
||||
name &&
|
||||
/^eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value)
|
||||
) {
|
||||
return { name, value };
|
||||
}
|
||||
}
|
||||
|
||||
return { name: "", value: "" };
|
||||
}
|
||||
|
||||
function extractUserIdCheckUrl(html: string) {
|
||||
const escapedMallId = activeAccount.mallId.replace(
|
||||
/[.*+?^${}()|[\]\\]/g,
|
||||
"\\$&"
|
||||
);
|
||||
const urlMatch = html.match(
|
||||
new RegExp(
|
||||
`https?:\\/\\/${escapedMallId}\\.cafe24\\.com\\/admin\\/php\\/user_id_check\\.php[^"'\\\`\\s<>]*`,
|
||||
"i"
|
||||
)
|
||||
);
|
||||
return urlMatch?.[0].replaceAll("&", "&") ?? "";
|
||||
}
|
||||
|
||||
function mergeRedirectSetCookie(responseDetails: {
|
||||
headers?: Record<string, string | string[]>;
|
||||
}) {
|
||||
appendCookie(responseDetails.headers?.["set-cookie"]);
|
||||
}
|
||||
|
||||
export async function requestShopLoginPage() {
|
||||
const response = await axios.get("https://eclogin.cafe24.com/Shop/", {
|
||||
headers: {
|
||||
accept:
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"accept-language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
"cache-control": "no-cache",
|
||||
cookie,
|
||||
pragma: "no-cache",
|
||||
priority: "u=0, i",
|
||||
referer: "https://www.cafe24.com/",
|
||||
"sec-ch-ua":
|
||||
'"Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Linux"',
|
||||
"sec-fetch-dest": "document",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-site": "same-site",
|
||||
"sec-fetch-user": "?1",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent":
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
|
||||
},
|
||||
});
|
||||
|
||||
appendCookie(response.headers["set-cookie"]);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function requestMallUseAuth() {
|
||||
const form = new URLSearchParams();
|
||||
form.set("url", "MallUseAuth");
|
||||
form.set("login_mode", "1");
|
||||
form.set("mobile", "F");
|
||||
form.set("onnode", "");
|
||||
form.set("menu", "");
|
||||
form.set("submenu", "");
|
||||
form.set("mode", "");
|
||||
form.set("c_name", "");
|
||||
form.set("loan_type", "");
|
||||
form.set("addsvc_suburl", "");
|
||||
form.set("appID", "");
|
||||
form.set("userid", activeAccount.mallId);
|
||||
form.set("EncData", "");
|
||||
form.set("EncKey", "");
|
||||
form.set("loginId", activeAccount.mallId);
|
||||
form.set("loginPasswd", activeAccount.password);
|
||||
|
||||
const response = await axios.post<MallUseAuthResponse>(
|
||||
"https://eclogin.cafe24.com/Shop/",
|
||||
form,
|
||||
{
|
||||
params: {
|
||||
url: "MallUseAuth",
|
||||
},
|
||||
headers: {
|
||||
accept: "application/json, text/javascript, */*; q=0.01",
|
||||
"accept-language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
"cache-control": "no-cache",
|
||||
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
cookie,
|
||||
origin: "https://eclogin.cafe24.com",
|
||||
pragma: "no-cache",
|
||||
priority: "u=1, i",
|
||||
referer: "https://eclogin.cafe24.com/Shop/",
|
||||
"sec-ch-ua":
|
||||
'"Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Linux"',
|
||||
"sec-fetch-dest": "empty",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"user-agent":
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
|
||||
"x-requested-with": "XMLHttpRequest",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
appendCookie(response.headers["set-cookie"]);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function requestComLogin(auth: MallUseAuthResponse) {
|
||||
const form = new URLSearchParams();
|
||||
form.set("url", "Run");
|
||||
form.set("login_mode", "1");
|
||||
form.set("mobile", "F");
|
||||
form.set("onnode", "");
|
||||
form.set("menu", "");
|
||||
form.set("submenu", "");
|
||||
form.set("mode", "");
|
||||
form.set("c_name", "");
|
||||
form.set("loan_type", "");
|
||||
form.set("addsvc_suburl", "");
|
||||
form.set("appID", "");
|
||||
form.set("userid", activeAccount.mallId);
|
||||
form.set("EncData", auth.sEncData);
|
||||
form.set("EncKey", auth.sEncKey);
|
||||
form.set("loginId", activeAccount.mallId);
|
||||
form.set("loginPasswd", activeAccount.password);
|
||||
|
||||
const response = await axios.post(auth.sActionPath, form, {
|
||||
maxRedirects: 0,
|
||||
validateStatus: (status) => status >= 200 && status < 400,
|
||||
headers: {
|
||||
accept:
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"accept-language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
"cache-control": "no-cache",
|
||||
"content-type": "application/x-www-form-urlencoded",
|
||||
cookie,
|
||||
origin: "https://eclogin.cafe24.com",
|
||||
pragma: "no-cache",
|
||||
priority: "u=0, i",
|
||||
referer: "https://eclogin.cafe24.com/",
|
||||
"sec-ch-ua":
|
||||
'"Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Linux"',
|
||||
"sec-fetch-dest": "document",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-site": "same-site",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent":
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
|
||||
},
|
||||
});
|
||||
|
||||
appendCookie(response.headers["set-cookie"]);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function requestUserIdCheck(html: string) {
|
||||
const userIdCheckUrl = extractUserIdCheckUrl(html);
|
||||
if (!userIdCheckUrl) {
|
||||
throw new Error("user_id_check.php URL을 찾지 못했습니다.");
|
||||
}
|
||||
|
||||
const response = await axios.get<string>(userIdCheckUrl, {
|
||||
beforeRedirect: (_options, responseDetails) => {
|
||||
mergeRedirectSetCookie(responseDetails);
|
||||
_options.headers.cookie = cookie;
|
||||
},
|
||||
headers: {
|
||||
accept:
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"accept-language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
"cache-control": "no-cache",
|
||||
cookie,
|
||||
pragma: "no-cache",
|
||||
priority: "u=0, i",
|
||||
referer: "https://user.cafe24.com/",
|
||||
"sec-ch-ua":
|
||||
'"Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Linux"',
|
||||
"sec-fetch-dest": "document",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-site": "same-site",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent":
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
|
||||
},
|
||||
});
|
||||
|
||||
appendCookie(response.headers["set-cookie"]);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function requestMemberAdminList() {
|
||||
const response = await axios.get<string>(
|
||||
`${getAdminBaseUrl()}${getShopPath("/c/member_admin_l.php", "1")}`,
|
||||
{
|
||||
validateStatus: (status) => status >= 200 && status < 500,
|
||||
headers: {
|
||||
accept:
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"accept-language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
"cache-control": "no-cache",
|
||||
cookie,
|
||||
pragma: "no-cache",
|
||||
priority: "u=0, i",
|
||||
referer: `${getAdminBaseUrl()}${getShopPath("/c/center.php", "1")}`,
|
||||
"sec-ch-ua":
|
||||
'"Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Linux"',
|
||||
"sec-fetch-dest": "document",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-user": "?1",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent":
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const dynamicHiddenField = extractDynamicHiddenField(response.data);
|
||||
dynamicHiddenFieldName = dynamicHiddenField.name;
|
||||
dynamicHiddenFieldValue = dynamicHiddenField.value;
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function requestShop2MemberAdminList() {
|
||||
const response = await axios.get<string>(
|
||||
`${getAdminBaseUrl()}${getShopPath("/c/member_admin_l.php")}`,
|
||||
{
|
||||
validateStatus: (status) => status >= 200 && status < 500,
|
||||
headers: {
|
||||
accept:
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"accept-language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
"cache-control": "no-cache",
|
||||
cookie,
|
||||
pragma: "no-cache",
|
||||
priority: "u=0, i",
|
||||
referer: `${getAdminBaseUrl()}${getShopPath("/c/center.php")}`,
|
||||
"sec-ch-ua":
|
||||
'"Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Linux"',
|
||||
"sec-fetch-dest": "document",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-user": "?1",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent":
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
appendCookie(response.headers["set-cookie"]);
|
||||
|
||||
const dynamicHiddenField = extractDynamicHiddenField(response.data);
|
||||
dynamicHiddenFieldName = dynamicHiddenField.name;
|
||||
dynamicHiddenFieldValue = dynamicHiddenField.value;
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function requestShop2MemberAdminSearch() {
|
||||
const form = new URLSearchParams();
|
||||
form.set("mode", "search");
|
||||
form.set("isStandardMode", "");
|
||||
form.set("m_mode", "");
|
||||
form.set("is_cti", "");
|
||||
form.set("ord", "regist_date");
|
||||
form.set("sort", "ASC");
|
||||
form.set("page", "1");
|
||||
form.set("rows", "1000");
|
||||
form.set("excel_private_auth", "T");
|
||||
form.set("mg_mode", "");
|
||||
form.set("is_change_membergrade_sms", "F");
|
||||
form.set("sSmsMemberGradeManualAuthCustomer", "T");
|
||||
form.set("mg_group_no_fix_flag", "");
|
||||
form.set(dynamicHiddenFieldName, dynamicHiddenFieldValue);
|
||||
form.set("search_type", "member_id");
|
||||
form.set("type", "");
|
||||
form.set("grp_sel", "0");
|
||||
form.set("group_no", "");
|
||||
form.set("is_member_auth", "0");
|
||||
form.set("input_channel", "");
|
||||
form.set("entry_path_group", "");
|
||||
form.set("entry_path", "");
|
||||
form.set("day_type", "1");
|
||||
form.set("regist_start_date", regDate);
|
||||
form.set("regist_end_date", regDate);
|
||||
form.set("mem_start_date", "04-25");
|
||||
form.set("mem_end_date", "04-25");
|
||||
form.set("age1", "");
|
||||
form.set("age2", "");
|
||||
form.set("gender", "1");
|
||||
form.set("sales_amount", "1");
|
||||
form.set("sales_type", "");
|
||||
form.set("min_sales_amount", "");
|
||||
form.set("max_sales_amount", "");
|
||||
form.set("ord_date_kind", "order_date");
|
||||
form.set("ord_start_date", "");
|
||||
form.set("ord_end_date", "");
|
||||
form.set("iOrderPrdtNo", "");
|
||||
form.set("sOrderPrdtName", "");
|
||||
form.set("login_start_date", "");
|
||||
form.set("login_end_date", "");
|
||||
form.set("visit_ip", "");
|
||||
form.set("s_join_cnt", "");
|
||||
form.set("e_join_cnt", "");
|
||||
form.set("s_attend_cnt", "");
|
||||
form.set("e_attend_cnt", "");
|
||||
form.set("is_marry", "1");
|
||||
form.set("child", "1");
|
||||
form.set("is_sms", "1");
|
||||
form.set("is_news_mail", "1");
|
||||
form.set("phone", "");
|
||||
form.set("mobile", "");
|
||||
form.set("region", "region_00");
|
||||
form.set("mileage_type", "avail_mileage");
|
||||
form.set("mileage1", "");
|
||||
form.set("mileage2", "");
|
||||
form.set("start_restore_datetime", "");
|
||||
form.set("end_restore_datetime", "");
|
||||
form.set("mid_list[]", "");
|
||||
form.set("group_list[]", "");
|
||||
form.set("member_name[]", "");
|
||||
form.set("mg_group_no", activeAccount.groupNo);
|
||||
form.set("group_no_b", activeAccount.groupNo);
|
||||
|
||||
await Bun.write(
|
||||
getResultPath(`${getResultPrefix()}-request.txt`),
|
||||
form.toString()
|
||||
);
|
||||
|
||||
const response = await axios.post<string>(
|
||||
`${getAdminBaseUrl()}${getShopPath("/c/member_admin_l.php")}`,
|
||||
form,
|
||||
{
|
||||
validateStatus: (status) => status >= 200 && status < 500,
|
||||
headers: {
|
||||
accept:
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"accept-language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
"cache-control": "no-cache",
|
||||
"content-type": "application/x-www-form-urlencoded",
|
||||
cookie,
|
||||
origin: getAdminBaseUrl(),
|
||||
pragma: "no-cache",
|
||||
priority: "u=0, i",
|
||||
referer: `${getAdminBaseUrl()}${getShopPath("/c/member_admin_l.php")}`,
|
||||
"sec-ch-ua":
|
||||
'"Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Linux"',
|
||||
"sec-fetch-dest": "document",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-user": "?1",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent":
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
appendCookie(response.headers["set-cookie"]);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
function parseAccountLine(line: string, lineNo: number): Account {
|
||||
const values = line.includes("\t")
|
||||
? line.split("\t")
|
||||
: line.includes("|")
|
||||
? line.split("|")
|
||||
: line.includes(",")
|
||||
? line.split(",")
|
||||
: line.trim().split(/\s+/);
|
||||
|
||||
const [mallId, password, groupNo, division] = values.map((value) =>
|
||||
value.trim()
|
||||
);
|
||||
|
||||
if (!mallId || !password || !groupNo || !division) {
|
||||
throw new Error(
|
||||
`${lineNo}번째 줄 형식이 잘못됐습니다. 아이디, 비번, 그룹넘버, 구분 순서로 넣어주세요.`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
mallId,
|
||||
password,
|
||||
groupNo,
|
||||
division,
|
||||
shopNo: groupNo,
|
||||
};
|
||||
}
|
||||
|
||||
async function readAccounts(path: string) {
|
||||
const text = await Bun.file(path).text();
|
||||
|
||||
return text
|
||||
.split(/\r?\n/)
|
||||
.map((line, index) => ({ line: line.trim(), lineNo: index + 1 }))
|
||||
.filter(({ line }) => line && !line.startsWith("#"))
|
||||
.map(({ line, lineNo }) => parseAccountLine(line, lineNo));
|
||||
}
|
||||
|
||||
async function runAccount(account: Account) {
|
||||
activeAccount = account;
|
||||
cookie = INITIAL_COOKIE;
|
||||
dynamicHiddenFieldName = "";
|
||||
dynamicHiddenFieldValue = "";
|
||||
|
||||
await requestShopLoginPage();
|
||||
const authResponse = await requestMallUseAuth();
|
||||
const loginResponse = await requestComLogin(authResponse.data);
|
||||
await requestUserIdCheck(loginResponse.data);
|
||||
const memberAdminResponse = await requestMemberAdminList();
|
||||
await requestShop2MemberAdminList();
|
||||
const shop2MemberAdminResponse = await requestShop2MemberAdminSearch();
|
||||
const shop2ResponsePath = getResultPath(`${getResultPrefix()}-response.html`);
|
||||
let members: any = extractMembers(shop2MemberAdminResponse.data);
|
||||
|
||||
console.log("추출행:", members.length);
|
||||
if (members.length === 0) {
|
||||
return;
|
||||
}
|
||||
const cafe24 = new HyundaiCustomerVerifier({});
|
||||
await cafe24.init();
|
||||
|
||||
// members = take(members, 5);
|
||||
|
||||
members = await cafe24.lookupPhones(members);
|
||||
|
||||
console.log("작업행:", members.length);
|
||||
|
||||
const appendResult = await appendRowsToDailySheet({
|
||||
rows: members,
|
||||
sheetName: account.division,
|
||||
baseDate: regDate,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`구글 시트 추가 완료: ${appendResult.targetSheetTitle} / ${appendResult.appendedRows}행`
|
||||
);
|
||||
|
||||
await Bun.write(shop2ResponsePath, shop2MemberAdminResponse.data);
|
||||
|
||||
return {
|
||||
mallId: account.mallId,
|
||||
groupNo: account.groupNo,
|
||||
division: account.division,
|
||||
shopNo: account.shopNo,
|
||||
status: memberAdminResponse.status,
|
||||
shopStatus: shop2MemberAdminResponse.status,
|
||||
responsePath: shop2ResponsePath,
|
||||
requestPath: getResultPath(`${getResultPrefix()}-request.txt`),
|
||||
dynamicHiddenFieldName,
|
||||
};
|
||||
}
|
||||
|
||||
await mkdir(RESULT_DIR, { recursive: true });
|
||||
const accounts = await readAccounts(accountsPath);
|
||||
const results = [];
|
||||
|
||||
for (const account of accounts) {
|
||||
console.log(
|
||||
`${account.mallId} / shop${account.shopNo} / group ${account.groupNo} 시작`
|
||||
);
|
||||
results.push(await runAccount(account));
|
||||
}
|
||||
|
||||
await Bun.write(
|
||||
getResultPath("results.json"),
|
||||
JSON.stringify(results, null, 2)
|
||||
);
|
||||
|
||||
console.log(results);
|
||||
|
||||
function decodeHtml(value: string) {
|
||||
return value
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, "'")
|
||||
.replace(/&#(\d+);/g, (_, code) => String.fromCharCode(Number(code)))
|
||||
.replace(/&#x([0-9a-f]+);/gi, (_, code) =>
|
||||
String.fromCharCode(parseInt(code, 16))
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeText(value: string) {
|
||||
return decodeHtml(value.replace(/<[^>]*>/g, " "))
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
function getInputValue(rowHtml: string, name: string) {
|
||||
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
const pattern = new RegExp(
|
||||
`<input\\b(?=[^>]*\\bname=["']${escapedName}["'])[^>]*\\bvalue=["']([^"']*)["'][^>]*>`,
|
||||
"i"
|
||||
);
|
||||
return decodeHtml(rowHtml.match(pattern)?.[1] ?? "").trim();
|
||||
}
|
||||
|
||||
function getCellText(rowHtml: string, index: number) {
|
||||
const cells = [...rowHtml.matchAll(/<td\b[^>]*>([\s\S]*?)<\/td>/gi)];
|
||||
return normalizeText(cells[index]?.[1] ?? "");
|
||||
}
|
||||
|
||||
export function extractMembers(html: string): MemberRow[] {
|
||||
const tbodyHtml =
|
||||
html.match(/<tbody class=["']center["'][^>]*>([\s\S]*?)<\/tbody>/i)?.[1] ??
|
||||
"";
|
||||
const rows = tbodyHtml.match(/<tr\b[\s\S]*?(?=<tr\b|$)/gi) ?? [];
|
||||
|
||||
return rows
|
||||
.filter((rowHtml) => rowHtml.includes('name="mid_list[]"'))
|
||||
.map((rowHtml) => {
|
||||
const landline = getCellText(rowHtml, 5);
|
||||
const mobile = getCellText(rowHtml, 6);
|
||||
|
||||
return {
|
||||
id: getInputValue(rowHtml, "mid_list[]"),
|
||||
full_name: getInputValue(rowHtml, "member_name[]"),
|
||||
created_time: getCellText(rowHtml, 1),
|
||||
phone_number: mobile || landline,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
type MemberRow = {
|
||||
id: string;
|
||||
full_name: string;
|
||||
created_time: string;
|
||||
phone_number: string;
|
||||
};
|
||||
Reference in New Issue
Block a user