Skip to content

Instantly share code, notes, and snippets.

@listly-io
Created May 28, 2026 23:48
Show Gist options
  • Select an option

  • Save listly-io/dcca6c4540cedc849fa984ad88ab12d4 to your computer and use it in GitHub Desktop.

Select an option

Save listly-io/dcca6c4540cedc849fa984ad88ab12d4 to your computer and use it in GitHub Desktop.
daiso_review_2026-05-29
// test page: https://www.daisomall.co.kr/pd/pdr/SCR_PDR_0001?pdNo=B202505133965&recmYn=N
// ============================================================
// ▶ 사용자 설정 영역 (필요에 따라 수정하세요)
// ============================================================
const MAX_PAGE_COUNT = 10; // 수집할 페이지 수 (1 = 현재 페이지만)
const WAIT_AFTER_CLICK = 5000; // 다음 페이지 클릭 후 대기 시간 (ms)
const WAIT_BEFORE_CLICK = 1000; // 스크롤 후 클릭 전 대기 시간 (ms)
const REVIEW_LIST_SELECTOR = 'ul.review-list > li.review-detail'; // 개별 리뷰 항목 셀렉터
const PAGINATION_SELECTOR = '.el-pagination'; // 페이지네이션 영역 셀렉터
const NEXT_BTN_SELECTOR = `${PAGINATION_SELECTOR} .btn-next`; // 다음 버튼 셀렉터
const CONTAINER_ID = '__review_collector'; // 수집 컨테이너 ID
// ============================================================
// ▶ 내부 로직 (수정 불필요)
// ============================================================
(async () => {
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
// 1. 수집 컨테이너 생성 (이미 있으면 재사용)
let container = document.getElementById(CONTAINER_ID);
if (!container) {
container = document.createElement('div');
container.id = CONTAINER_ID;
Object.assign(container.style, {
position: 'fixed',
right: '200px',
bottom: '200px',
zIndex: '999999',
background: 'rgba(0, 0, 0, 0.85)',
color: '#0f0',
fontSize: '18px',
fontWeight: 'bold',
fontFamily: 'monospace',
padding: '16px 24px',
borderRadius: '12px',
border: '2px solid #0f0',
boxShadow: '0 4px 20px rgba(0,255,0,.3)',
cursor: 'default',
userSelect: 'none',
overflow: 'hidden',
});
document.body.appendChild(container);
}
// 수집 저장소 (숨김 영역) — 컨테이너 내부에 display:none 인 래퍼
let store = container.querySelector('#__review_store');
if (!store) {
store = document.createElement('div');
store.id = '__review_store';
store.style.display = 'none';
container.appendChild(store);
}
// 카운트 표시 라벨
let label = container.querySelector('#__review_label');
if (!label) {
label = document.createElement('div');
label.id = '__review_label';
container.appendChild(label);
}
const updateLabel = () => {
const count = store.children.length;
label.textContent = `수집된 리뷰: ${count}개`;
};
// 2. 현재 페이지 리뷰 수집 함수
const collectCurrentPage = () => {
const reviews = document.querySelectorAll(
`${REVIEW_LIST_SELECTOR}:not(#${CONTAINER_ID} *)`
);
let added = 0;
reviews.forEach((el) => {
const clone = el.cloneNode(true);
store.appendChild(clone);
added++;
});
console.log(`[Scraper] ${added}개 리뷰 수집 (누적 ${store.children.length}개)`);
updateLabel();
};
// 3. 다음 페이지 버튼 클릭 함수 (스크롤 → 대기 → 클릭)
// 반환: true = 클릭 성공, false = 버튼 없음/비활성
const isDisabled = (b) =>
!b ||
b.disabled ||
b.classList.contains('is-disabled') ||
b.getAttribute('aria-disabled') === 'true';
const goNextPage = async () => {
const btn = document.querySelector(NEXT_BTN_SELECTOR);
if (isDisabled(btn)) return false;
// 페이지네이션 영역으로 스크롤
const paginationArea = document.querySelector(PAGINATION_SELECTOR);
if (paginationArea) {
paginationArea.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
await sleep(WAIT_BEFORE_CLICK);
// 다시 한번 버튼 상태 확인 (스크롤 중 상태 변경 가능)
const btnAgain = document.querySelector(NEXT_BTN_SELECTOR);
if (isDisabled(btnAgain)) return false;
btnAgain.click();
return true;
};
// 4. 메인 루프
console.log(`[Scraper] 수집 시작 — 최대 ${MAX_PAGE_COUNT}페이지`);
for (let page = 1; page <= MAX_PAGE_COUNT; page++) {
// 현재 페이지 수집
collectCurrentPage();
console.log(`[Scraper] ${page}/${MAX_PAGE_COUNT} 페이지 수집 완료`);
// 마지막 페이지면 종료
if (page === MAX_PAGE_COUNT) break;
// 다음 페이지로 이동
const moved = await goNextPage();
if (!moved) {
console.log('[Scraper] 다음 페이지 없음 — 수집 종료');
break;
}
// 페이지 로딩 대기
await sleep(WAIT_AFTER_CLICK);
}
console.log(`[Scraper] 수집 완료! 총 ${store.children.length}개 리뷰`);
updateLabel();
// ▶ 나중에 수집된 HTML을 꺼내려면 콘솔에서:
// document.getElementById('__review_store').innerHTML
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment