Playwright를 이용한 슈퍼마켓 가격 추적
(sakisv.net)- 2022년 12월 높은 인플레이션 속에서 그리스 3대 슈퍼마켓의 가격 변화를 매일 추적하려고 pricewatcher.gr 파이프라인을 구축함
- 상품 목록이 JavaScript 렌더링과 무한 스크롤 뒤에 있어
curl이나requests.get()대신 Playwright로 브라우저를 제어해 DOM에서 데이터를 추출함 - 실행 환경은 오래된 노트북만으로는 느리고 AWS EC2는 비싸서, Hetzner 서버를 필요할 때만 생성해 3개 스크래퍼를 병렬 실행한 뒤 종료하는 방식으로 바뀜
- Akamai가 비주거용 IP를 막는 슈퍼마켓은 Tailscale exit node로 집 IP를 통하게 했고, 이메일 알림·엄격한 변환·상품 수 휴리스틱으로 실패를 감지함
- 8vCPU 서버와 이미지 요청 차단으로 실행 시간을 줄였으며, 최근 31회 실행 비용은 Hetzner 서버 €4.94와 IPv4 €0.09, Cloudflare R2 저장 비용 €0.00 수준임
JavaScript 기반 슈퍼마켓 사이트 스크래핑
- 2022년 12월 높은 인플레이션 상황에서 그리스 3대 슈퍼마켓의 가격 변화를 추적하는 pricewatcher.gr를 구축함
- 세 슈퍼마켓 e-shop은 모두 JavaScript 렌더링을 사용했고, 일부 영역은 소셜 미디어의 무한 스크롤처럼 스크롤할 때 상품을 추가로 로드함
- 단순한
curl이나requests.get()로는 상품 데이터를 가져올 수 없어 Playwright를 사용함 - Playwright는 브라우저를 프로그래밍 방식으로 제어하며 다음 작업을 API로 처리함
- 새 탭 열기와 URL 이동
- DOM 검사
- 요소 세부 정보 조회
- 요청 가로채기와 검사
- Playwright는 Chromium, Safari, Firefox를 지원하고 Node, Java, .NET, Python에서 사용할 수 있음
- 스크래퍼는 무한 스크롤의
load more요소를 찾아 계속 스크롤한 뒤,li.product-item목록에서 품절 표시가 있는 상품을 제외함 - 최종적으로 각 상품
<div>에서 상품명·가격·사진·링크 등을 파싱하고, 같은 작업을 다음 상품 카테고리에 반복함
매일 돌릴 실행 환경 고르기
- M1 MacBook Pro에서 슈퍼마켓 하나를 전부 처리하는 데 50분에서 2시간 30분이 걸렸고, 3개 스크래퍼를 병렬 실행해도 눈에 띄는 차이는 없었음
- 개발과 테스트에는 노트북이 충분했지만, 매일 실행할 영구적인 환경이 필요했음
-
오래된 노트북 단독 실행
- 첫 시도는 2013년식 오래된 노트북이었음
- 사양은 2.20GHz 듀얼코어 M 계열 프로세서와 4GB RAM이었고, 이후 RAM을 12GB로 늘림
- 하지만 “빠른” 슈퍼마켓도 처리 시간이 2시간 이상 걸려 기대한 성능에 미치지 못함
-
클라우드 실행
- AWS에서 4코어·8GB RAM 수준의 EC2 인스턴스를 검토했지만, 사이드 프로젝트 비용으로는 부담이 컸음
- 작성 시점 기준
eu-north-1의c5a.xlarge는 시간당 $0.1640이고, 월 $118.08 또는 연 $1,416.96 수준임 - Hetzner의 동급 서버
cpx31은 월 $17.22(€15.72), 연 $206.64로 AWS보다 약 7배 저렴했음 - 최종 실행 환경은 Hetzner로 선택함
Concourse로 구성한 일일 파이프라인
- 오래된 노트북은 스크래핑을 직접 수행하지 않고, Hetzner 서버에 작업을 위임하는 CI 서버 역할을 맡음
- CI 도구는 Concourse를 사용함
- Concourse는 자신을 “a continuous thing-doer”라고 소개함
- 선언형 파이프라인 모델과 입력 버전 관리를 통해 재현 가능한 빌드를 지향함
- 파이프라인은 매일 밤 다음 순서로 실행됨
- 스크래핑 서버 생성
- 3개 슈퍼마켓 스크래핑 작업 병렬 실행
- 모든 작업 완료 후 비용 절감을 위해 서버 종료
- 각 스크래퍼의 원시 출력을 변환 작업으로 전달
- 변환된 데이터를 pricewatcher.gr에 로드
- 어느 단계든 실패하면 이메일 알림 발송
IP 제한 우회와 Tailscale exit node
- 테스트에 사용한 슈퍼마켓은 정상 동작했지만, 다른 슈퍼마켓 하나는 Akamai 뒤에 있었고 비주거용 IP 요청을 차단하는 방화벽 규칙이 켜져 있었음
- 필요한 구조는 일반 VPN과 반대로, 실제 집 IP에서 요청이 나가는 것처럼 만드는 방식이었음
- Tailscale로 여러 장치를 같은 네트워크에 있는 것처럼 묶음
- Tailscale에서 한 장치를 exit node로 지정하면, 다른 장치의 요청이 해당 노드를 통해 나가도록 설정할 수 있음
- 오래된 노트북은 스크래핑 트래픽의 exit node 역할도 함께 맡음
- 사용 중인 ISP가 CGNAT을 사용해 공인 IP가 특정 개인에게만 묶이지 않고 ISP의 다른 고객과 공유되는 점도 변수로 남아 있음
실패 유형과 감지 방식
- 이 구성은 1년 반 동안 운영됐고, 전반적으로 신뢰할 만하게 동작함
- 스크래핑 프로젝트는 대상 웹사이트 개발자의 변경에 영향을 받을 수밖에 없음
- 실패는 크게 두 가지로 나뉨
-
깨지는 변경
- 사이트 변경으로 스크래퍼가 바로 실패하는 경우임
- 예시는 다음과 같음
- 설문조사가 추가돼 버튼을 한 번 더 눌러야 하는 경우
- 레이아웃이 완전히 바뀌어 스크래퍼를 크게 리팩터링해야 하는 경우
-
깨지지 않는 변경
- 스크래퍼는 계속 정상 실행되지만, 데이터 해석이 틀어지는 경우가 더 까다로움
- 예를 들어 가격 표기 방식이 바뀌어 소수점 부분을
<sup>로 분리하면, €1.99인 감자칩이 €199처럼 파싱될 수 있음 - 이런 변경을 잡기 위해 변환 단계가 입력을 가능한 한 엄격하게 검증하도록 구성함
- 매일 실행되므로 문제를 확인할 시간은 있지만, 휴가 중에 깨지면 불안 요소가 될 수 있음
실행 시간과 안정성 최적화
- 전체 아키텍처는 처음부터 거의 유지됐지만, 신뢰성을 높이고 수작업을 줄이기 위해 여러 부분을 바꿈
- 적용한 개선에는 다음이 포함됨
- 실패 시 이메일 알림
- 특정 슈퍼마켓에서 상품 수가 너무 많거나 적을 때 알림을 보내는 휴리스틱
- 타임아웃
- 처음부터 다시 시작하지 않는 재시도
- 가장 큰 병목은 스크래핑 실행 시간이었음
- 오래 걸릴수록 비용이 늘어남
- 실패 후 처음부터 재시도해야 할 때 불편함이 커짐
-
더 큰 서버 사용
- 서버를 4vCPU·16GB RAM에서 8vCPU·16GB RAM으로 변경함
- 실행 시간이 약 20% 감소했고, MBP에서 얻는 성능과 비슷한 수준이 됨
- 스크래핑 서버는 약 2시간만 사용하므로 가격 차이는 무시할 만한 수준이었음
-
더 적게 가져오기
- Playwright의
page.route를 사용해 이미지 요청을 차단함 .png,.jpg요청을 abort 처리해 상품 로딩 중 이미지를 가져오지 않음- 이 방식은 스크래핑을 더 빠르게 만들고, 대역폭과 대상 웹사이트의 비용도 약간 줄일 수 있음
- Playwright의
31회 실행 기준 비용
- 최근 Hetzner 청구서 기준 비용은 다음과 같음
- 생성한 서버 31개: €4.94
- 해당 서버가 받은 IPv4 주소 31개: €0.09
- 스크래핑 데이터는 Cloudflare R2에 저장함
- Cloudflare R2의 10GB 무료 티어를 아직 넘지 않아 저장 비용은 €0.00임
- 전체 파이프라인은 Playwright, Hetzner, Concourse, Tailscale, Cloudflare R2를 조합해 슈퍼마켓 가격 변화를 매일 추적하는 구조로 동작함
댓글과 토론
Hacker News 의견들
-
올해 초부터 New Zealand 대상으로 비슷한 일을 하고 있음. Playwright/Typescript로 데이터를 긁어 Parquet 파일로 클라우드 스토리지에 저장하고 있고, 아직 화면에 보여주지는 않았음
작업의 대부분은 Akamai, Cloudflare 같은 리버스 프록시 서비스를 우회하는 데 들어감. 처음 만들 때는 아무도 안 하는 줄 알았는데, 지금은 NZ에서 최소 3개 스타트업이 같은 일을 하는 걸 알고 있음. 인플레이션이 여기서 꽤 많은 혁신을 촉발한 듯함
패턴은 예상대로임. 슈퍼마켓들은 가격을 최대한 복잡하게 만드는 평소 수법을 쓰고, ‘톱니형’ 가격 변동으로 시간이 부족한 사람과 돈이 부족한 사람을 가름함. 브랜드 충성 고객과 가격 민감 고객을 나누는 경우도 많고, 인기 초콜릿 브랜드가 3개 있으면 매주 그중 하나만 적정가에 파는 식임- 슈퍼마켓이 가격 갱신으로 고객 세분화를 어떻게 악용하는지 궁금함. 시간이 부족한 사람과 정말 돈이 부족한 사람은 보통 어떻게 반응하는지도 알고 싶음
“브랜드 충성 고객과 가격 민감 고객을 나눈다. 인기 초콜릿 브랜드가 3개 있으면 매주 그중 하나만 적정가에 팔린다”는 부분이 특히 궁금함 - Australia에서는 이런 방식의 합법성이 애매함. NZ도 비슷하지 않을까 싶음
AU에는 이런 스크래퍼가 많이 생겼다가 사라지지만, 보통 대형 슈퍼마켓들이 막아버림. 유용함과 “왜 이런 게 없지?”가 반복되는 순환인데, 사실 이미 여러 번 존재했었음 - India용으로 https://bbdeals.in/를 만들었음. 주로 과일 살 때 쓰는데, 지출을 약 20% 절약해 줘서 요즘 같은 시기에는 나쁘지 않음
크롤러와 이를 받치는 인프라를 만드는 데는 20시간도 안 걸렸음 - Kiwi로서 이런 프로젝트나 본인 프로젝트를 공개할 수 있는지 궁금함. 꽤 관심 있음
- 온라인으로 식료품 배달을 주문하는 사람은 가격 비교의 이득을 볼 수 있음. 동시에 여러 가게에서 주문할 수 있기 때문임
게다가 여러 가게의 가격을 모두 갖고 있는 장터가 하나뿐이라 더 유용함
- 슈퍼마켓이 가격 갱신으로 고객 세분화를 어떻게 악용하는지 궁금함. 시간이 부족한 사람과 정말 돈이 부족한 사람은 보통 어떻게 반응하는지도 알고 싶음
-
좋은 글임. 내가 운영하는 콘택트렌즈 가격 비교 사이트 https://lenspricer.com/에서도 비슷한 문제를 겪었고, 약 30개국에서 운영 중임. 웹사이트가 HTML을 바꾸는 건 정말 골칫거리라는 점에 공감함
초기에 가장 큰 장애물 중 하나는 100개 넘는 웹사이트에서 같은 제품을 매칭하는 일이었음. 제품명이 고유할 것 같아도 모두가 자기식으로 살짝 바꿔 적음. 대부분은 정규식으로 처리되지만, 상당수는 수동으로 매핑해야 했고 일부는 AI를 썼지만 전부 직접 검증했음
스크래퍼와 인프라를 만드는 건 비교적 쉬운 편임. 어려운 건 모든 스크래퍼를 유지보수하고, 제품이 사이트에서 사라졌을 때 그게 스크래퍼 오류인지, 차단인지, 사이트 변경인지, 크롤링 시점에 사이트가 점검 중이었는지를 가려내는 일임
재미있는 프로젝트지만 때로는 어렵고, 고치기 짜증나는 문제가 많음- 필요한 일을 해주고 있음. 매년 기본적인 물건인 콘택트렌즈를 살 때 보험사 때문에 고생함
가격은 제각각이고, 보장도 보통 우편 환급으로 30%쯤 처리되는 식임 - 일할 때 콘택트렌즈를 낄 수 있는지 궁금함. 모니터를 오래 보면 눈이 피곤해지는 걸 느끼는데, 해결책을 찾은 게 있는지 알고 싶음
- Germany 페이지에서는 가격 아래에 “일부 링크는 후원 링크일 수 있음”이라고 되어 있는데, 어떤 링크인지 표시하지 않음. 이게 합법인지 의문임
상점 수도 매우 적어 보이는데, 어쩌면 모든 링크가 후원 링크일 수도 있음. idealo.de에서는 더 낮은 가격도 찾음 - 미국에서는 적어도 대형 소매업체들이 가격 비교를 어렵게 만들려고 공급업체에게 살짝 다른 SKU를 만들게 함
Costco가 이런 걸로 꽤 유명한데, 매장에서 파는 전자제품 거의 전부와 많은 다른 제품이 맞춤 SKU임. 종종 제품 구성도 약간 다름 - 이런 경우야말로 LLM이 정말 도움이 될 수 있는 활용 사례 아닌가 싶음
- 필요한 일을 해주고 있음. 매년 기본적인 물건인 콘택트렌즈를 살 때 보험사 때문에 고생함
-
내 도시에서 꽤 관심을 받은 비슷한 웹사이트를 만들었음. 앱과 웹사이트 데이터까지 긁고, Linode의 RAM 2GB 단일 서버에 IPv4 5개와 무료 IPv6 1000개를 붙여 사용함
모든 제품은 최대 40분 간격으로 수집하고, 평균은 25분 정도임. curl-impersonate를 쓰고 가능한 한 JSON을 긁음. 시장의 90%는 Ajax 호출로 가격을 제공하고, 나머지 10%는 정규식으로 HTML을 쉽게 파싱함
https://www.economizafloripa.com.br에서 볼 수 있음- 앱과 웹사이트 데이터를 긁은 다음 그걸 다시 사업자에게 팔려고 하고, 심지어 그 데이터를 AI 학습에 쓰라고 제안하기도 함. 마치 팀이 수작업으로 전부 처리하는 것처럼 보이게도 함
https://www.economizafloripa.com.br/?q=parceria-comercial
그 페이지를 보니 프로젝트가 “생활필수품을 파는 기업들로부터 통제권을 되찾는 사람들을 위한 유용한 도구”에서 “또 하나의 돈벌이 시도”로 보이게 됨. 물론 그건 본인 자유지만, 홈페이지를 읽었을 때는 더 윤리적인 동기를 기대했음 - 이 흐름에서 IPv6 순환은 어떻게 동작하는지 궁금함
- 앱과 웹사이트 데이터를 긁은 다음 그걸 다시 사업자에게 팔려고 하고, 심지어 그 데이터를 AI 학습에 쓰라고 제안하기도 함. 마치 팀이 수작업으로 전부 처리하는 것처럼 보이게도 함
-
좋은 글임
스크래핑과 파싱을 별도 프로세스로 나누는 편이 가장 좋다고 봄. 원본 JSON이나 HTML을 저장해두면 언제든 돌아가서 파서를 고쳐 다시 적용할 수 있음
석사 프로젝트의 일부로 Netherlands용 비슷한 시스템과 웹사이트를 만들었음: https://www.superprijsvergelijker.nl/
내 프로젝트의 스크래핑 대부분은 JSON API에 단순 HTTP 호출을 보내는 방식임. 일부 웹사이트는 유효한 세션 쿠키를 얻고 봇 방지와 CAPTCHA를 우회하려고 Playwright 인스턴스를 사용함. 나머지 크롤러/스크래퍼, 파서, API는 Haskell로 만들고 AWS ECS에서 돌림. 웹사이트는 NextJS임
계속 풀려고 하는 주요 과제는 서로 다른 슈퍼마켓의 제품을 연결해서 한 화면에 가격을 나열하는 것임. 예시는 여기 있음: https://www.superprijsvergelijker.nl/supermarkt-aanbieding/6...
제품에 올바른 바코드 번호가 하나라도 제공되면 대부분 잘 동작함- 맞음, 나도 정확히 그렇게 하고 있고, 인정하기 민망할 만큼 여러 번 도움을 받았음. 원본 JSON/HTML 저장은 정말 유용함
- 멋짐. 이런 걸 찾고 있었음
-
Australia의 두 대형 슈퍼마켓은 양쪽에서 가격 분석 AI 알고리즘만 운용해도 반경쟁적 가격 책정의 복점 구조를 만들 수 있다고 봄. 알고리즘은 결국 이익을 극대화하기 위해 협력하는 방향으로 갈 가능성이 큼
공개적으로 얻은 가격만으로도 합법적으로 할 수 있고, 공급 원가나 제품별 이익 데이터를 공유하면 불법적으로도 가능함. 결과는 비슷할 듯함
학습된 AI 둘은 다차원, 어쩌면 초다차원 회귀분석으로 이상한 방식의 이익 극대화를 할 것이고, 소비자는 겉으로는 경쟁자인 업체들의 극대화된 이익을 부담하게 됨. 이런 식으로 가격 데이터를 얻을 수 있다면, 복점에 초점을 둔 기계학습 구현 두 개를 굴리는 데 필요한 것은 많지 않음- Norway의 “경쟁 당국”(https://konkurransetilsynet.no/norwegian-competition-authori...)은 바로 그 이유로 공개적이고 투명한 식품 가격 정보에 자주 비판적임
모든 가격이 공개되면 소비자가 오히려 더 높은 가격을 내게 된다는 논리임. 슈퍼마켓들이 모두가 최대 이익을 내는 지점으로 가격을 맞추게 된다는 것임
이곳 슈퍼마켓들은 수년간 “가격 사냥꾼”을 고용해 왔는데, 경쟁 매장에 가서 모든 물건의 가격을 기록하는 사람들임
Norway에서는 슈퍼마켓 A가 한 주 특정 품목을 할인하면, 다음 주나 그다음 주에 슈퍼마켓 B가 비슷한 할인을 해서 고객을 끌어들이는 모습을 자주 볼 수 있음 - 찾고 있던 단어는 담합이었음. 다만 사람끼리 담합하는 게 아니라 소프트웨어로 하는 담합임
- Norway의 “경쟁 당국”(https://konkurransetilsynet.no/norwegian-competition-authori...)은 바로 그 이유로 공개적이고 투명한 식품 가격 정보에 자주 비판적임
-
이런 변경을 잡으려면 자동 검사를 추가할 수 있을 것 같음. 예를 들어 상식 검증이 실패하면 가격/제품 변경을 동기화하지 않는 식임
각 가격은 100% 넘게 변하면 안 되고, 활성 제품 수는 20% 넘게 변하면 안 된다는 기준을 둘 수 있음- 프로그래밍에서 상식 검증은 과소평가됨. 성능 비용도 낮고, 그냥 두면 상태를 오염시킬 버그를 일찍 잡아줌
- 나도 생각해봤지만 제품 가격이 100% 넘게 뛰는 경우를 봤음
대신 이런 휴리스틱은 스크래핑 성공 여부를 확인하는 데 썼음. 예를 들어 오늘 긁은 제품 수가 최근 7일 평균의 약 10% 범위 안에 있는지 확인하는 방식임
-
어려운 건 스크래핑 자체가 아니라 점점 정교해지는 차단 장치 우회임
주거용 프록시를 계속 순환해야 하고, 평점 높은 것을 써야 하며, 데이터 스크래핑 패턴을 드러내지 않도록 해야 함. 어떤 슈퍼마켓은 네트워크 탭에 네트워크 요청을 보여주지 않아서 API 응답만 가져오는 식으로는 안 됨
그래도 모바일 앱에 중간자 공격을 걸어 네트워크 요청과 데이터를 보려 해도, 제대로 위장하지 않으면 차단됨
시도해봤지만 비용과 지속적인 개발 작업 때문에 가치가 없다고 판단했음. 실제로 일부 슈퍼마켓 가격 비교 서비스는 그냥 저임금 인력을 써서 긁게 함- 아예 법으로 가격 데이터를 API로 공개하도록 요구할 수 있으면 좋겠음. 그러면 차단 장치와 씨름할 필요가 없어짐
- 다행히 아직 그 단계까지는 안 갔음
이건 사이드 프로젝트라서 시간 요구가 너무 잦아지면 그냥 중단하고 코드와 데이터를 모두 공개할 생각임
그런데 네트워크 요청이 네트워크 탭에 안 나타나는 건 어떻게 가능한지 궁금함
내게 가장 어려운 부분은 슈퍼마켓들 사이에서 제품을 연결하고 비교하는 일임 - OCR을 써서 제품 목록 이미지만 찍는 방식은 안 됐을까? 이상적이진 않지만 방법에 따라 추적이 어렵거나 불가능할 수 있음
- 브라우저 확장으로 크라우드소싱하면 됨
-
상품의 가격 투명성이 있으면 좋겠음. 매장과 지역별로 이런 과정을 훨씬 쉽게 추적할 수 있음
예를 들어 우유 대체품인 오트 밀크 가격을 우편번호와 식료품점별로 비교할 수 있음. 또 같은 가격이지만 용량이 줄어드는 “슈링크플레이션”도 추적할 수 있음
그런 의미에서 가격은 추적하는 것 같은데, 그램당 또는 온스당 비용도 확인하는지 궁금함. 제조사나 매장이 가격은 그대로 두고 소비자에게 더 적은 양을 줄 수 있는데, 도구가 이걸 잡아낼 수 있을지 궁금함- kg, L 같은 단위당 가격도 추적함. 이 숫자를 보여주고 그래프로 그릴지, 아니면 결제대에서 실제로 내는 가격을 보여줄지 고민했지만, 사람들이 보는 가격에 더 “익숙하게” 맞추려고 후자를 선택했음
그래도 충분히 추가할 수 있는 기능이고, 슈링크플레이션이 있었다면 발생 시점을 보여줄 수 있음 - 식료품점이 라벨에 단위 가격을 안 적는 건 개인적으로 정말 거슬림. 고객에게 적대적이지 않은 목적이 있다고는 상상하기 어려움
- 상품 원가 가격 공개를 의무화한다고 상상해보면 좋겠음. 농부가 X를 받고, 제조사가 Y를 받고, 식료품점이 Z를 더했다는 걸 보고 싶음
- kg, L 같은 단위당 가격도 추적함. 이 숫자를 보여주고 그래프로 그릴지, 아니면 결제대에서 실제로 내는 가격을 보여줄지 고민했지만, 사람들이 보는 가격에 더 “익숙하게” 맞추려고 후자를 선택했음
-
Swedish 시장에서는 8년 넘게 이 일을 해오고 있음. https://www.matspar.se/라는 웹사이트가 있고, 고객은 주요 온라인 매장의 모든 상품을 둘러보고 가격을 비교한 뒤 원하는 상품을 장바구니에 담을 수 있음
마지막에는 배송비까지 포함한 장바구니 총액을 비교하고, 원하는 매장으로 장바구니를 내보내 주문할 수 있음
공동창업자이자 현 CTO라서 그동안 스크래핑과 유지보수를 많이 해왔음. 매일 3천만 개 넘는 가격을 긁고 있음- 사업 측면에서 비즈니스 모델이 궁금함. 어떻게 매출을 만들고, 장기 목표는 무엇인지 알고 싶음
공개 데이터상 회사 매출은 약 40만 달러이고 직원은 6명임: https://www.allabolag.se/5590076351/matspar-i-sverige-ab - 스크래핑 접근법에 대한 기술 글이 있는지 궁금함. 어떤 어려움이 있었고 어떻게 풀었는지 더 읽어보고 싶음
- 사업 측면에서 비즈니스 모델이 궁금함. 어떻게 매출을 만들고, 장기 목표는 무엇인지 알고 싶음
-
새 지역으로 이사했을 때는 가격 추적을 했지만, 지금은 항상 낮은 가격을 유지하는 시장이나 대형 매장 2곳에서 쇼핑하는 게 훨씬 쉽다고 느낌
Europe이라면 아마 Aldi/Lidl일 것임
미국이라면 Costco/Trader Joe's일 수 있음
온라인은 CamelCamelCamel/Amazon이 있음. 식품은 아니고 건강/미용/일부 전자제품 쪽임
제조사에서 직접 살 수 있으면 때로는 그게 더 낫기도 함. 예를 들어 좋아하는 특정 비누 브랜드를 도매 사이트에서 대량 구매했더니 소매가의 절반 이하였음. 샴푸도 갤런 단위로 직접 사는 게 어떤 소매점보다 훨씬 쌌음- 내 경험으로 미국에서는 Costco/Walmart/Aldi임
Trader Joe's는 품질은 더 높지만 대체로 더 비쌈 - 미국에도 ALDI가 있지만 지역별로 있음. Trader Joe’s는 ALDI와 같은 가문이 소유하고 있고, 최근 10년 전까지만 해도 같은 지역에서 둘을 함께 보긴 어려웠음
- 내 경험으로 미국에서는 Costco/Walmart/Aldi임