Function bodies 131 total
scrapeCross function · javascript · L209-L227 (19 LOC)scraper/run-thb.js
async function scrapeCross(browser) {
const page = await browser.newPage();
try {
await page.goto('https://crossenf.com/remittance', { waitUntil: 'load', timeout: 30000 });
await page.waitForTimeout(2000);
// THB is already the default receiving currency — no country change needed
const receiveInput = page.locator('input[inputmode="numeric"]').nth(1);
await receiveInput.click({ clickCount: 3 });
await receiveInput.fill(String(AMOUNT));
await receiveInput.press('Tab');
await page.waitForTimeout(3000);
const totalRaw = await page.locator('input[inputmode="numeric"]').nth(0).inputValue();
const total = extractNumber(totalRaw);
if (!total) throw new Error('총 송금액 추출 실패');
const fee = 5000;
return { operator: 'Cross', receiving_country: COUNTRY, receive_amount: AMOUNT,
send_amount_krw: total, service_fee: fee, total_sending_amount: total + fee };
} finally { await page.close(); }
}scrapeCoinshot function · javascript · L230-L253 (24 LOC)scraper/run-thb.js
async function scrapeCoinshot(browser) {
const page = await browser.newPage();
try {
await page.goto('https://coinshot.org/main', { waitUntil: 'load', timeout: 30000 });
await page.waitForTimeout(2000);
await page.waitForSelector('button.lang-btn[value="ko"]', { timeout: 10000 });
await page.click('button.lang-btn[value="ko"]');
await page.waitForTimeout(1000);
await page.click('#current-receiving-currency');
await page.waitForTimeout(500);
await page.click('#select-receiving-currency a[data-currency="THB"]');
await page.waitForTimeout(1000);
await page.click('#receiving-input', { clickCount: 3 });
await page.fill('#receiving-input', String(AMOUNT));
await page.press('#receiving-input', 'Enter');
await page.waitForTimeout(3000);
const sendAmtRaw = await page.inputValue('#sending-input');
const sendAmt = extractNumber(sendAmtRaw);
if (!sendAmt) throw new Error('총 송금액 추출 실패');
const fee = 5000; // Thailand: 5,000원 고정scrapeJrf function · javascript · L256-L278 (23 LOC)scraper/run-thb.js
async function scrapeJrf(browser) {
const context = await browser.newContext({ ignoreHTTPSErrors: true });
const page = await context.newPage();
try {
await page.goto('https://www.jpremit.co.kr/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(3000);
await page.click('#div_curr', { force: true });
await page.waitForSelector('li#THB', { state: 'visible', timeout: 10000 });
await page.click('li#THB');
await page.waitForTimeout(1500);
await page.click('#rec_money', { clickCount: 3 });
await page.fill('#rec_money', String(AMOUNT));
await page.dispatchEvent('#rec_money', 'keyup');
await page.waitForTimeout(3000);
const sendAmtRaw = await page.inputValue('#send_money');
const sendAmt = extractNumber(sendAmtRaw);
if (!sendAmt) throw new Error('총 송금액 추출 실패');
const feeRaw = await page.textContent('#servicefee').catch(() => null);
const fee = extractNumber(feeRaw) ?? 5000;
return { operator: 'JRscrapeE9pay function · javascript · L281-L310 (30 LOC)scraper/run-thb.js
async function scrapeE9pay(browser) {
const page = await browser.newPage();
try {
await page.goto('https://www.e9pay.co.kr/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(3000);
await page.waitForSelector('#TH_THB', { state: 'attached', timeout: 10000 });
await page.evaluate(() => {
const radio = document.querySelector('#TH_THB');
radio.checked = true;
radio.dispatchEvent(new Event('change', { bubbles: true }));
radio.dispatchEvent(new Event('click', { bubbles: true }));
});
await page.waitForTimeout(1000);
await page.waitForSelector('#reverse', { timeout: 5000 });
await page.click('#reverse');
await page.waitForTimeout(500);
await page.waitForSelector('#receive-money', { timeout: 5000 });
await page.click('#receive-money', { clickCount: 3 });
await page.fill('#receive-money', String(AMOUNT));
await page.dispatchEvent('#receive-money', 'blur');
await page.waitForTimeout(main function · javascript · L327-L411 (85 LOC)scraper/run-thb.js
async function main() {
const runHour = getRunHour();
console.log(`\n[${new Date().toISOString()}] Thailand THB 스크래핑 시작 — run_hour: ${runHour}\n`);
const browser = await chromium.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
const results = [];
const errors = [];
console.log(` 모든 스크래퍼 병렬 실행 중... (${SCRAPERS.length}개)\n`);
const settled = await Promise.allSettled(
SCRAPERS.map(({ fn, needsBrowser }) => (needsBrowser ? fn(browser) : fn()))
);
for (let i = 0; i < settled.length; i++) {
const { name } = SCRAPERS[i];
const result = settled[i];
if (result.status === 'fulfilled') {
results.push(result.value);
console.log(` ✓ ${name}: 송금액 ${result.value.send_amount_krw?.toLocaleString()}원 수수료 ${result.value.service_fee?.toLocaleString()}원 합계 ${result.value.total_sending_amount?.toLocaleString()}원`);
} else {
console.error(` ✗ ${name} 실패: ${result.reason?.message}`);
errors.push(scrapeGme function · javascript · L15-L34 (20 LOC)scraper/run-vnd.js
async function scrapeGme(browser) {
const page = await browser.newPage();
try {
await page.goto('https://online.gmeremit.com/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForSelector('#nCountry', { timeout: 10000 });
await page.click('#nCountry'); await page.waitForTimeout(500);
await page.fill('#CountryValue', 'Vietnam'); await page.waitForTimeout(300);
await page.click('#toCurrUl li[data-countrycode="VND"]');
await page.waitForTimeout(1000);
await page.click('#recAmt', { clickCount: 3 });
await page.fill('#recAmt', String(AMOUNT));
await page.dispatchEvent('#recAmt', 'change');
await page.waitForTimeout(3000);
const raw = await page.$eval('#numAmount', el => el.value || el.textContent).catch(() => null);
const total = extractNumber(raw);
if (!total) throw new Error('총 송금액 추출 실패');
return { operator: 'GME', receiving_country: COUNTRY, receive_amount: AMOUNT,
send_amount_krw: total, service_fee: 0scrapeSentbe function · javascript · L37-L64 (28 LOC)scraper/run-vnd.js
async function scrapeSentbe(browser) {
const context = await browser.newContext({
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
locale: 'ko-KR',
});
const page = await context.newPage();
try {
await page.goto('https://www.sentbe.com/ko', { waitUntil: 'networkidle', timeout: 30000 });
await page.click('button.close').catch(() => null);
await page.waitForTimeout(300);
await page.click('article.app-download-popup .dim').catch(() => null);
await page.waitForTimeout(500);
await page.waitForSelector('.receiveAmountInput .el-input-group__append', { timeout: 10000 });
await page.click('.receiveAmountInput .el-input-group__append'); await page.waitForTimeout(500);
// "베트남 / 동 - VND" 선택 (USD 제외)
await page.click('.receiveAmountInput .el-select-dropdown__item:has-text("베트남 / 동")');
await page.waitForTimeout(1000);
await page.click('#receiveAmount', { clickCouRepobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
scrapeSbi function · javascript · L67-L89 (23 LOC)scraper/run-vnd.js
async function scrapeSbi(browser) {
const context = await browser.newContext({
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
locale: 'ko-KR',
});
const page = await context.newPage();
try {
await page.goto('https://www.sbicosmoney.com/', { waitUntil: 'load', timeout: 30000 });
await page.waitForTimeout(2000);
await page.click('button:has-text("Close")').catch(() => null); await page.waitForTimeout(500);
await page.click('.dest-country'); await page.waitForTimeout(500);
await page.click('a[data-currency="VND"]'); await page.waitForTimeout(1500);
await page.click('#targetAmount', { clickCount: 3 });
await page.fill('#targetAmount', String(AMOUNT));
await page.dispatchEvent('#targetAmount', 'input'); await page.waitForTimeout(2000);
const raw = await page.inputValue('#krwAmount');
const sendAmt = extractNumber(raw);
if (!sendAmt) throw new Error('총 송금scrapeGmoneytrans function · javascript · L92-L108 (17 LOC)scraper/run-vnd.js
async function scrapeGmoneytrans() {
const url = 'https://mapi.gmoneytrans.net/exratenew1/ajx_calcRate.asp'
+ `?receive_amount=${AMOUNT}`
+ '&payout_country=Viet+Nam'
+ '&total_collected=0'
+ '&payment_type=Bank+Account'
+ '¤cyType=VND';
const res = await fetch(url, { signal: AbortSignal.timeout(15000) });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const text = await res.text();
const serviceCharge = parseField(text, 'serviceCharge') ?? 2500;
const sendAmount = parseField(text, 'sendAmount');
if (!sendAmount) throw new Error(`파싱 실패: ${text.slice(0, 200)}`);
return { operator: 'GMoneyTrans', receiving_country: COUNTRY, receive_amount: AMOUNT,
send_amount_krw: sendAmount, service_fee: serviceCharge,
total_sending_amount: sendAmount + serviceCharge };
}parseField function · javascript · L109-L112 (4 LOC)scraper/run-vnd.js
function parseField(text, field) {
const m = text.match(new RegExp(`${field}--td_clm--([\\d.]+)--td_end--`));
return m ? parseFloat(m[1]) : null;
}scrapeE9pay function · javascript · L115-L141 (27 LOC)scraper/run-vnd.js
async function scrapeE9pay(browser) {
const page = await browser.newPage();
try {
await page.goto('https://www.e9pay.co.kr/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(3000);
await page.waitForSelector('#VN_VND', { state: 'attached', timeout: 10000 });
await page.evaluate(() => {
const radio = document.querySelector('#VN_VND');
radio.checked = true;
radio.dispatchEvent(new Event('change', { bubbles: true }));
radio.dispatchEvent(new Event('click', { bubbles: true }));
});
await page.waitForTimeout(1000);
await page.click('#reverse'); await page.waitForTimeout(500);
await page.waitForSelector('#receive-money', { timeout: 5000 });
await page.click('#receive-money', { clickCount: 3 });
await page.fill('#receive-money', String(AMOUNT));
await page.dispatchEvent('#receive-money', 'blur'); await page.waitForTimeout(3000);
const raw = await page.$eval('#send-money', el => el.value).scrapeHanpass function · javascript · L144-L161 (18 LOC)scraper/run-vnd.js
async function scrapeHanpass() {
const res = await fetch('https://app.hanpass.com/app/v1/remittance/get-cost', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ inputAmount: String(AMOUNT), inputCurrencyCode: 'VND',
fromCurrencyCode: 'KRW', toCurrencyCode: 'VND', toCountryCode: 'VN',
memberSeq: '1', lang: 'en' }),
signal: AbortSignal.timeout(15000),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
if (data.resultCode !== '0') throw new Error(`Hanpass API 오류: ${data.resultMessage}`);
const total = data.depositAmountIncludingFee;
const fee = data.transferFee ?? 0;
if (!total) throw new Error('총 송금액 추출 실패');
return { operator: 'Hanpass', receiving_country: COUNTRY, receive_amount: AMOUNT,
send_amount_krw: total - fee, service_fee: fee, total_sending_amount: total };
}scrapeCross function · javascript · L164-L184 (21 LOC)scraper/run-vnd.js
async function scrapeCross(browser) {
const page = await browser.newPage();
try {
await page.goto('https://crossenf.com/remittance', { waitUntil: 'load', timeout: 30000 });
await page.waitForTimeout(2000);
await page.locator('div.relative:has(span:text("THB"))').click();
await page.waitForSelector('#aside-root ul', { timeout: 10000 });
await page.locator('#aside-root li:has(img[alt="VN flag"])').click();
await page.waitForTimeout(1000);
const receiveInput = page.locator('input[inputmode="numeric"]').nth(1);
await receiveInput.click({ clickCount: 3 });
await receiveInput.fill(String(AMOUNT));
await receiveInput.press('Tab'); await page.waitForTimeout(3000);
const totalRaw = await page.locator('input[inputmode="numeric"]').nth(0).inputValue();
const total = extractNumber(totalRaw);
if (!total) throw new Error('총 송금액 추출 실패');
const fee = 5000;
return { operator: 'Cross', receiving_country: COUNTRY, receive_amount: AMOUNT,
scrapeJrf function · javascript · L187-L206 (20 LOC)scraper/run-vnd.js
async function scrapeJrf(browser) {
const context = await browser.newContext({ ignoreHTTPSErrors: true });
const page = await context.newPage();
try {
await page.goto('https://www.jpremit.co.kr/', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(3000);
await page.click('#div_curr', { force: true });
await page.waitForSelector('li#VND', { state: 'visible', timeout: 10000 });
await page.click('li#VND'); await page.waitForTimeout(1500);
await page.click('#rec_money', { clickCount: 3 });
await page.fill('#rec_money', String(AMOUNT));
await page.dispatchEvent('#rec_money', 'keyup'); await page.waitForTimeout(3000);
const raw = await page.inputValue('#send_money');
const sendAmt = extractNumber(raw);
if (!sendAmt) throw new Error('총 송금액 추출 실패');
const fee = 4500;
return { operator: 'JRF', receiving_country: COUNTRY, receive_amount: AMOUNT,
send_amount_krw: sendAmt, service_fee: fee, total_sending_amomain function · javascript · L221-L302 (82 LOC)scraper/run-vnd.js
async function main() {
const runHour = getRunHour();
console.log(`\n[${new Date().toISOString()}] Vietnam VND 스크래핑 시작 — run_hour: ${runHour}\n`);
const browser = await chromium.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
const results = [];
const errors = [];
console.log(` 모든 스크래퍼 병렬 실행 중... (${SCRAPERS.length}개)\n`);
const settled = await Promise.allSettled(
SCRAPERS.map(({ fn, needsBrowser }) => (needsBrowser ? fn(browser) : fn()))
);
for (let i = 0; i < settled.length; i++) {
const { name } = SCRAPERS[i];
const result = settled[i];
if (result.status === 'fulfilled') {
results.push(result.value);
console.log(` ✓ ${name}: 송금액 ${result.value.send_amount_krw?.toLocaleString()}원 수수료 ${result.value.service_fee?.toLocaleString()}원 합계 ${result.value.total_sending_amount?.toLocaleString()}원`);
} else {
console.error(` ✗ ${name} 실패: ${result.reason?.message}`);
errors.push({Repobility · code-quality intelligence platform · https://repobility.com
scrapeGme function · javascript · L15-L33 (19 LOC)scraper/run-xaf.js
async function scrapeGme() {
const body = new URLSearchParams({
method: 'GetExRate', pCurr: 'XAF', pCountryName: 'Cameroon',
collCurr: 'KRW', deliveryMethod: '2', cAmt: '', pAmt: String(AMOUNT),
cardOnline: 'false', calBy: 'P',
}).toString();
const res = await fetch('https://online.gmeremit.com/Default.aspx', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body, signal: AbortSignal.timeout(15000),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
if (data.errorCode !== '0') throw new Error(`GME API 오류: ${data.msg}`);
const total = parseFloat(data.collAmt?.toString().replace(/,/g, '') ?? '');
if (!total) throw new Error('총 송금액 추출 실패');
return { operator: 'GME', receiving_country: COUNTRY, receive_amount: AMOUNT,
send_amount_krw: total, service_fee: 0, total_sending_amount: total };
}scrapeGmoneytrans function · javascript · L36-L52 (17 LOC)scraper/run-xaf.js
async function scrapeGmoneytrans() {
const url = 'https://mapi.gmoneytrans.net/exratenew1/ajx_calcRate.asp'
+ `?receive_amount=${AMOUNT}`
+ '&payout_country=Cameroon'
+ '&total_collected=0'
+ '&payment_type=MTN'
+ '¤cyType=XAF';
const res = await fetch(url, { signal: AbortSignal.timeout(15000) });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const text = await res.text();
const serviceCharge = parseField(text, 'serviceCharge') ?? 5000;
const sendAmount = parseField(text, 'sendAmount');
if (!sendAmount) throw new Error(`파싱 실패: ${text.slice(0, 200)}`);
return { operator: 'GMoneyTrans', receiving_country: COUNTRY, receive_amount: AMOUNT,
send_amount_krw: sendAmount, service_fee: serviceCharge,
total_sending_amount: sendAmount + serviceCharge };
}parseField function · javascript · L53-L56 (4 LOC)scraper/run-xaf.js
function parseField(text, field) {
const m = text.match(new RegExp(`${field}--td_clm--([\\d.]+)--td_end--`));
return m ? parseFloat(m[1]) : null;
}main function · javascript · L65-L137 (73 LOC)scraper/run-xaf.js
async function main() {
const runHour = getRunHour();
console.log(`\n[${new Date().toISOString()}] Cameroon XAF 스크래핑 시작 — run_hour: ${runHour}\n`);
const results = [];
const errors = [];
console.log(` 모든 스크래퍼 병렬 실행 중... (${SCRAPERS.length}개)\n`);
const settled = await Promise.allSettled(SCRAPERS.map(({ fn }) => fn()));
for (let i = 0; i < settled.length; i++) {
const { name } = SCRAPERS[i];
const result = settled[i];
if (result.status === 'fulfilled') {
results.push(result.value);
console.log(` ✓ ${name}: 송금액 ${result.value.send_amount_krw?.toLocaleString()}원 수수료 ${result.value.service_fee?.toLocaleString()}원 합계 ${result.value.total_sending_amount?.toLocaleString()}원`);
} else {
console.error(` ✗ ${name} 실패: ${result.reason?.message}`);
errors.push({ name, error: result.reason?.message });
}
}
if (results.length === 0) {
console.error('\n모든 스크래퍼 실패. 종료합니다.');
process.exit(1);
}
const gmeRecord = resuscrape function · javascript · L9-L55 (47 LOC)scraper/scrapers/coinshot.js
export async function scrape(browser) {
const page = await browser.newPage();
try {
await page.goto('https://coinshot.org/main', {
waitUntil: 'load',
timeout: 30000,
});
await page.waitForTimeout(2000);
// ── 언어 선택 모달 닫기 ────────────────────────────────────────────
await page.waitForSelector('button.lang-btn[value="ko"]', { timeout: 10000 });
await page.click('button.lang-btn[value="ko"]');
await page.waitForTimeout(1000);
// ── 수신 국가: Indonesia (IDR) 선택 ────────────────────────────────
await page.click('#current-receiving-currency');
await page.waitForTimeout(500);
await page.click('#select-receiving-currency a[data-currency="IDR"]');
await page.waitForTimeout(1000);
// ── 수령액 입력: 13,000,000 IDR ────────────────────────────────────
await page.click('#receiving-input', { clickCount: 3 });
await page.fill('#receiving-input', '13000000');
await page.press('#receiving-input', 'Enter');
await page.waitFoscrape function · javascript · L9-L53 (45 LOC)scraper/scrapers/cross.js
export async function scrape(browser) {
const page = await browser.newPage();
try {
// networkidle 미달성 사이트 — load 사용
await page.goto('https://crossenf.com/remittance', {
waitUntil: 'load',
timeout: 30000,
});
await page.waitForTimeout(2000);
// ── 수신 국가: Indonesia (IDR) 선택 ────────────────────────────────
// 수신 통화 드롭다운 열기 (기본값 THB)
await page.locator('div.relative:has(span:text("THB"))').click();
await page.waitForSelector('#aside-root ul', { timeout: 10000 });
// Indonesia 국기(ID flag) 이미지로 li 선택
await page.locator('#aside-root li:has(img[alt="ID flag"])').click();
await page.waitForTimeout(1000);
// ── 수령액 입력: 13,000,000 IDR ────────────────────────────────────
const receiveInput = page.locator('input[inputmode="numeric"]').nth(1);
await receiveInput.click({ clickCount: 3 });
await receiveInput.fill('13000000');
await receiveInput.press('Tab');
await page.waitForTimeout(3000);
// ── 총 송금액(KRW) scrape function · javascript · L9-L60 (52 LOC)scraper/scrapers/e9pay.js
export async function scrape(browser) {
const page = await browser.newPage();
try {
await page.goto('https://www.e9pay.co.kr/', {
waitUntil: 'domcontentloaded',
timeout: 30000,
});
await page.waitForTimeout(3000);
// ── 수신 국가: Indonesia (IDR) 선택 (라디오가 CSS로 숨겨져 있어 JS로 트리거) ──
await page.waitForSelector('#ID_IDR', { state: 'attached', timeout: 10000 });
await page.evaluate(() => {
const radio = document.querySelector('#ID_IDR');
radio.checked = true;
radio.dispatchEvent(new Event('change', { bubbles: true }));
radio.dispatchEvent(new Event('click', { bubbles: true }));
});
await page.waitForTimeout(1000);
// ── reverse 버튼 클릭 → 수령액 입력 모드로 전환 ────────────────────
await page.waitForSelector('#reverse', { timeout: 5000 });
await page.click('#reverse');
await page.waitForTimeout(500);
// ── 수령액 입력: 13,000,000 IDR ────────────────────────────────────
await page.waitForSelector('#receive-money', {scrape function · javascript · L9-L62 (54 LOC)scraper/scrapers/gme.js
export async function scrape(browser) {
const page = await browser.newPage();
try {
await page.goto('https://online.gmeremit.com/', {
waitUntil: 'domcontentloaded',
timeout: 30000,
});
// ── 수신 국가: Indonesia (IDR) 선택 ────────────────────────────────
// #nCountry 클릭 → 드롭다운 열기
await page.waitForSelector('#nCountry', { timeout: 10000 });
await page.click('#nCountry');
await page.waitForTimeout(500);
// 검색창에 "Indonesia" 입력해 필터링
await page.waitForSelector('#CountryValue', { timeout: 5000 });
await page.fill('#CountryValue', 'Indonesia');
await page.waitForTimeout(300);
// Indonesia (IDR) 항목 클릭
await page.click('#toCurrUl li[data-countrycode="IDR"]');
await page.waitForTimeout(1000);
// ── 수령액 입력: 13,000,000 IDR ────────────────────────────────────
await page.waitForSelector('#recAmt', { timeout: 10000 });
await page.click('#recAmt', { clickCount: 3 });
await page.fill('#recAmt', '13000000');
// Repobility — same analyzer, your code, free for public repos · /scan/
scrape function · javascript · L9-L36 (28 LOC)scraper/scrapers/gmoneytrans.js
export async function scrape() {
const url =
'https://mapi.gmoneytrans.net/exratenew1/ajx_calcRate.asp' +
'?receive_amount=13000000' +
'&payout_country=Indonesia' +
'&total_collected=0' +
'&payment_type=Bank+Account' +
'¤cyType=IDR';
const res = await fetch(url, { signal: AbortSignal.timeout(15000) });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const text = await res.text();
const serviceCharge = parseField(text, 'serviceCharge') ?? 2500;
const sendAmount = parseField(text, 'sendAmount');
if (!sendAmount) throw new Error(`파싱 실패: ${text.slice(0, 200)}`);
return {
operator: OPERATOR,
receiving_country: 'Indonesia',
receive_amount: 13_000_000,
send_amount_krw: sendAmount,
service_fee: serviceCharge,
total_sending_amount: sendAmount + serviceCharge,
};
}parseField function · javascript · L38-L41 (4 LOC)scraper/scrapers/gmoneytrans.js
function parseField(text, field) {
const m = text.match(new RegExp(`${field}--td_clm--([\\d.]+)--td_end--`));
return m ? parseFloat(m[1]) : null;
}scrape function · javascript · L8-L37 (30 LOC)scraper/scrapers/hanpass.js
export async function scrape() {
const res = await fetch('https://app.hanpass.com/app/v1/remittance/get-cost', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
inputAmount: '13000000',
inputCurrencyCode: 'IDR',
fromCurrencyCode: 'KRW',
toCurrencyCode: 'IDR',
toCountryCode: 'ID',
memberSeq: '1',
lang: 'en',
}),
signal: AbortSignal.timeout(15000),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
if (data.resultCode !== '0') throw new Error(`Hanpass API 오류: ${data.resultMessage}`);
const total = data.depositAmountIncludingFee;
const fee = data.transferFee ?? 0;
if (!total) throw new Error('총 송금액 추출 실패');
return {
operator: OPERATOR,
receiving_country: 'Indonesia',
receive_amount: 13_000_000,
send_amount_krw: total - fee,
service_fee: fee,
total_sending_amount: total,
};
}scrape function · javascript · L9-L52 (44 LOC)scraper/scrapers/jrf.js
export async function scrape(browser) {
const context = await browser.newContext({ ignoreHTTPSErrors: true });
const page = await context.newPage();
try {
await page.goto('https://www.jpremit.co.kr/', {
waitUntil: 'domcontentloaded',
timeout: 30000,
});
await page.waitForTimeout(3000);
// ── 수신 통화: IDR 선택 ─────────────────────────────────────────────
await page.click('#div_curr', { force: true });
await page.waitForSelector('li#IDR', { state: 'visible', timeout: 10000 });
await page.click('li#IDR');
await page.waitForTimeout(1500);
// ── 수령액 입력: 13,000,000 IDR ────────────────────────────────────
await page.click('#rec_money', { clickCount: 3 });
await page.fill('#rec_money', '13000000');
await page.dispatchEvent('#rec_money', 'keyup');
await page.waitForTimeout(3000);
// ── 총 송금액(KRW) 추출 — fee 미포함 ──────────────────────────────
const sendAmtRaw = await page.inputValue('#send_money');
const sendAmt = escrape function · javascript · L12-L61 (50 LOC)scraper/scrapers/sbi.js
export async function scrape(browser) {
const context = await browser.newContext({
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
locale: 'ko-KR',
});
const page = await context.newPage();
try {
await page.goto('https://www.sbicosmoney.com/', {
waitUntil: 'load',
timeout: 30000,
});
await page.waitForTimeout(2000);
// ── 팝업 닫기 ──────────────────────────────────────────────────────
await page.click('button:has-text("Close")').catch(() => null);
await page.waitForTimeout(500);
// ── 수신 국가: Indonesia (IDR) 선택 ────────────────────────────────
await page.click('.dest-country');
await page.waitForTimeout(500);
await page.click('a[data-currency="IDR"]');
await page.waitForTimeout(1500);
// ── 수령액 입력: 13,000,000 IDR ────────────────────────────────────
await page.click('#targetAmount', { clickCount: 3 });
await page.fill('#targetAscrape function · javascript · L9-L60 (52 LOC)scraper/scrapers/sentbe.js
export async function scrape(browser) {
const context = await browser.newContext({
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
locale: 'ko-KR',
});
const page = await context.newPage();
try {
await page.goto('https://www.sentbe.com/ko', {
waitUntil: 'networkidle',
timeout: 30000,
});
// ── 팝업 닫기 ──────────────────────────────────────────────────────
await page.click('button.close').catch(() => null);
await page.waitForTimeout(300);
// app-download 팝업이 오버레이를 가리는 경우 dim 클릭으로 닫기
await page.click('article.app-download-popup .dim').catch(() => null);
await page.waitForTimeout(500);
// ── 수신 국가: 인도네시아 / 루피아 - IDR 선택 ──────────────────────
await page.waitForSelector('.receiveAmountInput .el-input-group__append', { timeout: 10000 });
await page.click('.receiveAmountInput .el-input-group__append');
await page.waitForTimeout(500);
awascrape function · javascript · L9-L48 (40 LOC)scraper/scrapers/utransfer.js
export async function scrape(browser) {
const page = await browser.newPage();
try {
await page.goto('https://www.utransfer.com', {
waitUntil: 'networkidle',
timeout: 30000,
});
await page.waitForTimeout(2000);
// ── 수신 통화: IDR 선택 (두 번째 select) ───────────────────────────
await page.locator('select').nth(1).selectOption('IDR');
await page.waitForTimeout(1000);
// ── 수령액 입력: 13,000,000 IDR ────────────────────────────────────
await page.click('input[name="toAmount"]', { clickCount: 3 });
await page.fill('input[name="toAmount"]', '13000000');
await page.dispatchEvent('input[name="toAmount"]', 'change');
await page.waitForTimeout(3000);
// ── 총 송금액(KRW) 추출 ────────────────────────────────────────────
const sendAmtRaw = await page.inputValue('input[name="fromAmount"]').catch(() => null);
const sendAmt = extractNumber(sendAmtRaw);
if (!sendAmt) throw new Error('총 송금액을 추출할 수 없습니다.');
// ── 수수료 추출 ─────────────scrape function · javascript · L9-L74 (66 LOC)scraper/scrapers/wirebarley.js
export async function scrape(browser) {
const context = await browser.newContext({
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
locale: 'ko-KR',
});
const page = await context.newPage();
try {
await page.goto('https://www.wirebarley.com/ko', {
waitUntil: 'networkidle',
timeout: 30000,
});
await page.waitForTimeout(3000);
// ── 광고 팝업 닫기 ─────────────────────────────────────────────────
await page.locator('#lafc-popup button').click().catch(() => null);
await page.waitForTimeout(1000);
// ── 수신 통화 드롭다운 열기 (기본값: USD) ──────────────────────────
await page.locator('[data-title="currencyToMoneyBox"]').nth(1)
.locator('img[alt="드롭 다운"]').click();
await page.waitForTimeout(2000);
// ── 수신 국가: Indonesia (IDR) 선택 ────────────────────────────────
await page.locator('button:has(img[alt="ID"])').click();
await page.waitForTimeout(2000)‹ prevpage 3 / 3