-
-
Save listly-io/80ed3fcf79464ab2a69c98d8dbcf91c2 to your computer and use it in GitHub Desktop.
lottedfs_review_2026-08-07
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // test page: https://kor.lottedfs.com/kr/product/productDetail?prdNo=20000840341&prdOptNo=20001083560&adltPrdYn=N | |
| // ============================================================ | |
| // ▶ 사용자 설정 영역 (필요에 따라 수정하세요) | |
| // ============================================================ | |
| const MAX_PAGE_COUNT = 10; // 수집할 페이지 수 (1 = 현재 페이지) | |
| const WAIT_AFTER_CLICK = 5000; // 다음 페이지 클릭 후 대기 시간 (ms) | |
| const WAIT_BEFORE_CLICK = 1000; // 스크롤 후 클릭 전 대기 시간 (ms) | |
| const REVIEW_LIST_SELECTOR = '#prdasBtmList > li'; // 개별 리뷰 항목 셀렉터 | |
| const PAGINATION_SELECTOR = '.pagingBtn'; // 페이지네이션 영역 셀렉터 | |
| const NEXT_BTN_SELECTOR = `${PAGINATION_SELECTOR} .pagination a`; // 다음 버튼 셀렉터 | |
| const CONTAINER_ID = '__review_collector'; // 수집 컨테이너 ID | |
| // ============================================================ | |
| // ▶ 내부 로직 (수정 불필요) | |
| // ============================================================ | |
| (async () => { | |
| const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); | |
| // 수집 컨테이너 생성 | |
| 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}개`; | |
| }; | |
| // 현재 페이지 리뷰 수집 | |
| 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(); | |
| }; | |
| // 다음 페이지 버튼 클릭 (스크롤 → 대기 → 클릭) | |
| // true = 클릭 성공, false = 버튼 없음/비활성 | |
| // ※ 이 사이트는 페이지네이션이 숫자/번호 형식(javascript:prdasPaging(n))이므로 | |
| // 순차 수집을 위해 prdasPaging(다음페이지)를 직접 호출합니다. | |
| const goNextPage = async (nextPage) => { | |
| // 다음 페이지 번호 링크가 존재하는지 확인 | |
| const findPageLink = () => | |
| Array.from(document.querySelectorAll(NEXT_BTN_SELECTOR)) | |
| .find((a) => a.textContent.trim() === String(nextPage)); | |
| const btn = findPageLink(); | |
| if (!btn || btn.disabled) return false; | |
| // 페이지네이션 영역으로 스크롤 | |
| const paginationArea = document.querySelector(PAGINATION_SELECTOR); | |
| if (paginationArea) { | |
| paginationArea.scrollIntoView({ behavior: 'smooth', block: 'center' }); | |
| } | |
| await sleep(WAIT_BEFORE_CLICK); | |
| // 다시 한번 버튼 상태 확인 (스크롤 중 상태 변경 가능) | |
| const btnAgain = findPageLink(); | |
| if (!btnAgain || btnAgain.disabled) return false; | |
| if (typeof prdasPaging !== 'function') return false; | |
| prdasPaging(String(nextPage)); | |
| return true; | |
| }; | |
| // 메인 | |
| 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(page + 1); | |
| 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