Skip to content

Instantly share code, notes, and snippets.

@listly-io
Last active January 4, 2026 19:23
Show Gist options
  • Select an option

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

Select an option

Save listly-io/4330fe5ade2b50d79e5becd3cda3489b to your computer and use it in GitHub Desktop.
amazon_review_2026-01-05
// test page 1: https://www.amazon.com/product-reviews/B0FPDWZ5X2/ref=cm_cr_dp_d_show_all_btm?ie=UTF8&reviewerType=all_reviews
// test page 2: https://www.amazon.com/product-reviews/B08KT2Z93D/ref=cm_cr_getr_d_show_all?reviewerType=all_reviews#reviews-filter-bar
// You must sign in to Amazon. The pages require sign-in.
// ==================== 사용자 설정 영역 ====================
const MAX_PAGE_COUNT = 10; // 최대 수집 횟수 (페이지 수)
const PAGE_LOAD_WAIT_MS = 5000; // 페이지 로드 대기 시간 (ms)
const SCROLL_WAIT_MS = 1000; // 스크롤 후 대기 시간 (ms)
const CONTAINER_OFFSET_RIGHT = 200; // 컨테이너 오른쪽 여백 (px)
const CONTAINER_OFFSET_BOTTOM = 200; // 컨테이너 아래쪽 여백 (px)
const CONTAINER_WIDTH = 250; // 컨테이너 너비 (px)
const CONTAINER_HEIGHT = 80; // 컨테이너 높이 (px)
const CONTAINER_FONT_SIZE = 16; // 폰트 크기 (px)
// CSS Selectors
const REVIEW_SELECTOR = 'LI[data-hook="review"][class="review aok-relative"]:not(#review-collector-storage *)';
const NEXT_BUTTON_SELECTOR = '.a-last a';
const PAGINATION_SELECTOR = '.a-pagination';
// ==========================================================
(async function() {
// 수집 컨테이너 생성
const container = document.createElement('div');
container.id = 'review-collector-container';
container.style.cssText = `
position: fixed;
right: ${CONTAINER_OFFSET_RIGHT}px;
bottom: ${CONTAINER_OFFSET_BOTTOM}px;
width: ${CONTAINER_WIDTH}px;
height: ${CONTAINER_HEIGHT}px;
background: #333;
color: #fff;
padding: 15px 20px;
border-radius: 10px;
font-size: ${CONTAINER_FONT_SIZE}px;
font-weight: bold;
z-index: 99999;
box-shadow: 0 4px 15px rgba(0,0,0,0.4);
display: flex;
align-items: center;
justify-content: center;
`;
// 카운터 표시 영역
const counter = document.createElement('span');
counter.id = 'review-collector-counter';
counter.textContent = '수집된 리뷰: 0개';
container.appendChild(counter);
// 리뷰 저장 영역 (숨김)
const storage = document.createElement('div');
storage.id = 'review-collector-storage';
storage.style.display = 'none';
container.appendChild(storage);
document.body.appendChild(container);
let totalCollected = 0;
let collectCount = 0;
// 리뷰 수집 함수
function collectReviews() {
const reviews = document.querySelectorAll(REVIEW_SELECTOR);
reviews.forEach(review => {
const clone = review.cloneNode(true);
storage.appendChild(clone);
totalCollected++;
});
counter.textContent = `수집된 리뷰: ${totalCollected}개`;
console.log(`[수집 완료] 현재 페이지 리뷰 ${reviews.length}개 추가, 총 ${totalCollected}개`);
}
// 대기 함수
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 다음 페이지로 이동 함수
async function goToNextPage() {
const nextButton = document.querySelector(NEXT_BUTTON_SELECTOR);
if (!nextButton) {
console.log('[종료] 다음 페이지 버튼이 없습니다.');
return false;
}
// pagination 영역으로 스크롤
const pagination = document.querySelector(PAGINATION_SELECTOR);
if (pagination) {
pagination.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
await wait(SCROLL_WAIT_MS);
nextButton.click();
console.log('[이동] 다음 페이지로 이동 중...');
await wait(PAGE_LOAD_WAIT_MS);
return true;
}
// 메인 수집 루프
console.log(`[시작] 리뷰 수집 시작 (최대 ${MAX_PAGE_COUNT}회)`);
while (collectCount < MAX_PAGE_COUNT) {
collectCount++;
console.log(`[진행] ${collectCount}/${MAX_PAGE_COUNT} 페이지 수집 중...`);
collectReviews();
if (collectCount >= MAX_PAGE_COUNT) {
console.log('[완료] 최대 수집 횟수에 도달했습니다.');
break;
}
const hasNext = await goToNextPage();
if (!hasNext) {
console.log('[완료] 마지막 페이지입니다.');
break;
}
}
console.log(`[최종 결과] 총 ${totalCollected}개의 리뷰가 수집되었습니다.`);
console.log('[안내] 수집된 HTML을 가져오려면 다음 명령어를 실행하세요:');
console.log('document.getElementById("review-collector-storage").innerHTML');
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment