이 판의 목적 · 계획 · 체크리스트
제품 한 통의 판매가로 표시된 단백질 파우더 가격을 단백질 1g당 가격으로 환산하는 도구를 개발한다. 순도와 용량, 배송비가 제품마다 달라 판매 가격으로는 제품 간 가격을 비교할 수 없기 때문이다.
계획
- 자료 수집. 다나와 검색 결과와 아마존 대한민국 배송가
- 유형 판정. 성분 항목으로 WPC·WPI·블렌드 분류
- 순도 산출. 1회 제공량과 1회 제공량당 단백질 함량으로 계산
- 단가 계산과 데이터셋 출력. CSV·XLSX·JSON 3종
- 차트 작성. 순위 막대 그래프·순도 대 단가 산점도·유형별 단가 분포
- 단일 파일 도구 HTML 작성. 필터와 정렬 기능 포함
체크리스트 7/10
| 상태 | 항목 |
|---|---|
| 완료 | 제품 51개 수집. WPC 17개·블렌드 9개·WPI 25개 |
| 완료 | 단가 산출. 중앙값 WPC 62원/g·블렌드 78원/g·WPI 95원/g |
| 완료 | 데이터셋 CSV·XLSX·JSON 3종 출력 |
| 완료 | 차트 2장 작성. 순위 막대 그래프와 분포·산점도 |
| 완료 | 단일 파일 도구 HTML 작성. 자료를 파일에 포함하여 인터넷 연결 없이 실행 |
| 완료 | 최저가 역전 1건 제외. 나우푸드 WPI 2268g 137,090원 대 4.54kg 107,400원 |
| 완료 | 차트 한글 글꼴 미적용 해결. .ttc 묶음에서 Noto Sans CJK JP를 후보에 추가 |
| 미완 | 쿠팡·네이버쇼핑 직접 수집 (브라우저 도구가 접속 거부, 다나와 집계값으로 대체) |
| 미완 | 수집 자동화 (한 시점에 수동 입력한 자료라 가격 변동 미반영, 다음 판 과제) |
| 미완 | 가격 이력·최저가 역전 자동 판정·류신 함량 항목·CSV 내보내기 (다음 판 과제) |
1. 개발 배경 및 목적
단백질 보충제의 판매 가격은 「2kg 62,200원」과 같이 제품 한 통의 값으로 표시된다. 그러나 같은 2kg 제품이라도 분말 100g에 포함된 단백질이 72g인 제품과 82g인 제품이 있어, 판매 가격만으로는 단백질 기준의 가격을 비교할 수 없다. 또한 시장의 제품은 WPC(농축유청단백)와 WPI(분리유청단백)로 구분되며 두 유형은 순도가 다르다.
따라서 본 도구는 모든 제품의 가격을 다음 산출식으로 환산하여 단백질 1g당 가격을 비교한다.
단백질 1g당 가격 = (판매가 + 배송비) ÷ [용량 × (1회 제공량당 단백질 ÷ 1회 제공량)]
대괄호 안의 값은 제품 한 개에 포함된 단백질 총량이다. 1회 제공량과 1회 제공량당 단백질 함량은 국내 제품의 경우 식품 등의 표시기준에 따라, 해외 제품의 경우 Supplement Facts에 표시되어 있다. 두 값으로 순도를 산출하고 순도에 용량을 곱하여 단백질 총량을 구하였다.
본 도구는 같은 금액으로 얻는 단백질량만을 계산한다. 맛과 용해도처럼 수치로 환산할 기준이 없는 항목은 산출에 포함하지 않았다.
1.1 WPC와 WPI의 구분 기준
두 유형은 제조 공정이 다르다. WPC는 유청을 한외여과로 농축한 원료로 단백질 함량이 통상 70~80%이며 유당과 지방이 일부 남는다. WPI는 WPC를 추가로 여과하여 단백질 함량을 90% 내외로 높인 원료로 유당이 거의 포함되지 않는다.
WPI는 유당 소화가 어려운 사용자가 주로 선택하므로, 본 도구는 WPI의 가격이 적정한지를 판정하지 않는다. WPI를 선택할 때 추가로 지불하는 금액을 수치로 제시하고, 구매 여부는 사용자가 판단하도록 하였다.
2. 기존 가격 비교 수단과의 차이
표 1은 기존 가격 비교 수단과 본 도구의 비교 기준을 나타낸다.
표 1 가격 비교 수단별 비교 기준과 한계
| 비교 대상 | 비교 기준 | 한계 |
|---|---|---|
| 쿠팡·네이버쇼핑 정렬 | 제품 판매가, 분말 100g당 가격 | 순도를 반영하지 않아 순도가 낮은 WPC가 앞에 표시됨 |
| 다나와 가격비교 | 제품 판매가의 최저가 | 유형 구분이 상품 속성으로만 제공되어 비교 기준으로 사용할 수 없음 |
| 해외 커뮤니티 표 | 1회 제공량당 가격($/serving) | 1회 제공량이 제품마다 달라 비교 단위로 사용할 수 없음 |
| GenealogyProtein | 단백질 1g당 가격(원/g) | 순도, 용량, 배송비를 단가에 반영하고 유형을 색으로 구분 |
본 도구는 1회 제공량당 가격 대신 단백질 1g당 가격을 비교 기준으로 사용한다. 1회 제공량은 제조사가 정하는 값이므로, 단백질 25g을 섭취하기 위한 분말량이 제품에 따라 28g에서 47g까지 차이가 있다. 단백질 1g은 제조사가 바꿀 수 없는 단위이므로 제품 간 비교 기준으로 사용할 수 있다.
3. 개발 절차
개발은 다음 순서로 진행하였다.
- 다나와 검색 결과에서 제품명, 최저가, 영양정보를 수집하고, 아마존에서 대한민국 배송 기준 원화 표시가와 1회 제공 횟수를 수집하였다.
- 상품 사양의 성분 항목을 기준으로 제품을 WPC, WPI, 블렌드로 분류하였다. 성분이 두 가지 이상인 제품은 블렌드로 분류하였다.
- 1회 제공량과 1회 제공량당 단백질 함량으로 순도를 산출하였다. 영양정보가 없는 제품은 유형별 통상 순도로 추정하고 추정값임을 표시하였다.
- 단백질 1g당 가격을 계산하여 CSV, XLSX, JSON 파일로 출력하였다.
- 단가 순위 막대 그래프, 순도 대 단가 산점도, 유형별 단가 분포 그래프를 작성하였다. 색은 WPI 파랑, WPC 주황, 블렌드 청록으로 지정하였다.
- 필터와 정렬 기능을 갖춘 단일 HTML 파일을 작성하였다. 자료를 파일 안에 포함하여 인터넷 연결 없이 실행된다.
4. 자료 수집 제약
4.1 쿠팡·네이버쇼핑 조회 차단
당초 쿠팡, 네이버쇼핑, 아마존에서 가격을 직접 수집할 계획이었으나, 쿠팡과 네이버쇼핑은 브라우저 도구의 접속이 거부되었다.
https://coupang.com is not allowed due to safety restrictions
https://search.shopping.naver.com is not allowed due to safety restrictions
대안으로 다나와 최저가를 사용하였다. 다나와 최저가는 네이버쇼핑, 11번가, 쿠팡 등 국내 판매처의 가격을 집계한 값이므로 개별 판매처를 조회하지 않아도 국내 최저 가격을 얻을 수 있다. 다만 이 값이 판매처별 가격을 모은 집계값임을 도구 화면에 표시하였다. 출처를 표시하지 않으면 이후 가격 차이가 생겼을 때 원인을 확인할 수 없기 때문이다.
4.2 아마존 수집 경로
아마존 제품 페이지를 웹 페이지 가져오기 도구로 요청하면 ROBOTS_DISALLOWED 응답이 반환되었으나, 같은 주소를 브라우저에서 열면 정상적으로 표시되었다. 자동 수집 도구와 브라우저에 서로 다른 접근 규칙이 적용되기 때문이다.
브라우저에서 수집한 가격은 대한민국 배송 기준 원화 표시가이다. 환율 환산이 필요하지 않은 대신 통관 및 배송 비용이 포함되어 미국 현지 가격보다 높으며, 이 사실을 표에 함께 표기하였다.
4.3 동일 제품의 최저가 역전
나우푸드 WPI는 2,268g 제품이 137,090원, 4.54kg 제품이 107,400원으로 수집되어 용량이 2배인 제품의 가격이 더 낮았다. 집계 최저가는 서로 다른 판매처의 가격을 모은 값이므로, 병행수입이나 해외직구 판매처의 가격이 섞이면 이러한 역전이 발생한다.
계산만으로는 원인을 판별할 수 없어 해당 제품은 데이터셋에서 제외하였다. 이 값을 포함하면 그래프에서 최저 단가로 표시되기 때문이다.
5. 오류 수정 내역
5.1 matplotlib 한글 글꼴 미적용
컨테이너에 Noto Sans CJK 글꼴이 설치되어 있었으나 matplotlib가 차트의 한글을 사각형으로 출력하였다.
UserWarning: Glyph 45800 (\N{HANGUL SYLLABLE DAN}) missing from font(s) DejaVu Sans.
원인은 .ttc 묶음 글꼴의 등록 방식이었다. NotoSansCJK-Regular.ttc 파일에는 JP, KR, SC, TC 네 가지 글꼴이 포함되어 있으나 matplotlib는 이 중 첫 번째 글꼴의 이름만 등록한다. 따라서 fc-list에는 「Noto Sans CJK KR」이 표시되었으나 matplotlib의 글꼴 목록에는 「Noto Sans CJK JP」만 있었다.
Noto Sans CJK는 한중일 공용 글꼴로 JP 글꼴에도 한글 자형이 포함되어 있다. 글꼴 후보 목록에 JP를 추가하여 해결하였다.
for c in ["Noto Sans CJK KR", "Noto Sans CJK JP", "NanumGothic", "Malgun Gothic"]:
if any(f.name == c for f in font_manager.fontManager.ttflist):
plt.rcParams["font.family"] = c
break
묶음 글꼴을 사용하는 경우 matplotlib에 등록된 이름을 먼저 확인해야 한다.
5.2 SVG 상단 여백 발생
도구 화면의 순위 막대 그래프 위쪽에 수백 픽셀의 여백이 생기고 그래프가 아래쪽으로 치우쳐 표시되었다. 원인은 SVG의 width, height 속성과 CSS max-width:100%의 충돌이었다.
CSS에 의해 폭은 줄었으나 높이는 속성값을 유지하였고, 남는 세로 공간에서 preserveAspectRatio가 그래프를 가운데로 정렬하여 위아래에 여백이 생겼다. CSS에 height:auto를 추가하여 해결하였다.
svg{display:block; max-width:100%; height:auto}
5.3 막대 이름 좌측 잘림
「원데이뉴트리션」으로 시작하는 제품 이름이 「이뉴트리션」부터 표시되었다. text-anchor="end"로 오른쪽 정렬한 텍스트가 왼쪽 여백을 넘어 viewBox 밖으로 나간 것이 원인이었다. 좌측 여백을 196에서 236으로 늘리고 이름 표시 길이를 26자에서 22자로 줄여 해결하였다.
5.4 차트 재생성 시 요소 소실
필터 조건을 변경하면 차트 영역에 아무것도 표시되지 않았다. 차트는 outerHTML로 요소 전체를 교체하는 구조였으나, 새로 생성한 SVG에 id 속성을 넣지 않아 두 번째 호출에서 getElementById가 요소를 찾지 못하였다. 새로 생성하는 SVG에 같은 id를 부여하여 해결하였다.
6. v1.0.0.0 결과
표 2는 유형별 단백질 1g당 가격을 나타낸다.
표 2 유형별 단백질 1g당 가격(원/g)
| 유형 | 제품 수 | 최저 | 중앙값 | 최고 |
|---|---|---|---|---|
| WPC 농축유청 | 17 | 39 | 62 | 131 |
| 블렌드 | 9 | 51 | 78 | 113 |
| WPI 분리유청 | 25 | 42 | 95 | 174 |
2026년 9월 16일에 수집한 가격이다.
6.1 결과 해석
WPI의 단가 중앙값은 WPC의 1.54배였으나 순도 중앙값은 83.3%와 74.9%로 1.11배 차이였다. 따라서 WPI의 가격에는 단백질 함량보다 유당 제거 공정의 비용이 더 크게 반영된 것으로 판단된다.
두 유형의 단가 범위는 크게 겹쳤다. WPC의 최고값은 131원/g, WPI의 최저값은 42원/g이므로 유형만으로 제품을 선택하면 WPI보다 단가가 약 3배 높은 WPC를 선택할 수 있다. 순도와 단가 사이에서도 뚜렷한 관계는 나타나지 않았다. 순도 80% 부근에 단가 40원대 제품과 130원대 제품이 함께 있었으며, 단가에는 순도보다 브랜드와 유통 경로의 영향이 큰 것으로 판단된다.
같은 판매처에서 같은 맛으로 판매되는 제품 5종은 모두 용량이 큰 제품의 단가가 낮았다. 단가 감소율은 3.8%에서 41.8%까지 제품에 따라 차이가 있었으며, 다이마타이즈 ISO100 1.3lb 제품의 단가는 5lb 제품의 1.72배였다.
7. 결과 그림


8. 다음 판 과제
v1.0.0.0의 자료는 한 시점에 수동으로 입력한 값이므로 가격 변동이 반영되지 않는다. 다음 판에서는 다나와 조회를 스크립트로 실행하여 날짜별 가격을 누적하는 수집 자동화를 먼저 진행한다. 날짜별 가격이 누적되면 동일 제품의 단가 변화를 확인할 수 있다.
이번 판에서 수동으로 제외한 최저가 역전 사례는 자동 판정 기능으로 대체한다. 동일 제품군에서 대용량 제품의 가격이 소용량 제품보다 낮은 경우를 검출하여 표시한다. 또한 단백질 총량만으로는 단백질의 품질을 비교할 수 없으므로 필수아미노산과 류신 함량을 비교 항목에 추가한다. 화면에서 필터링한 결과를 CSV 파일로 내보내는 기능도 추가한다.