평생 책을 읽어온(그리고 앞으로도 읽을) 사람을 위한, 클라우드 위에 존재하는 나만의 3D 가상 서재.
| # | 기능 | 설명 |
|---|---|---|
| 1 | 블로그 자동 수집 | 네이버 블로그 ‘독서,책’ 카테고리 글을 가져와 책으로 변환 (아래 §3 검증 완료) |
| 2 | 책 등록(텍스트) | 제목만 입력 → 책 메타데이터 API로 저자/출판사/표지/출간연도 자동 조회·매칭 |
| 3 | 책 등록(사진) | 실물 책 촬영 → 바코드(ISBN) 인식으로 자동 등록 |
| 4 | 3D 가상 서재 | 여러 테마의 3D 책장/공간. 책 클릭 시 상세 패널(표지·저자·독후감·구절) |
| 5 | 인생 시기 분류 | 초/중/고/대/사회초년/현재 등 시기별 책장 구분 |
| 6 | 추천 엔진 | 읽은 책 기반 추천 + 베스트셀러 연동 |
| 7 | 독후감/구절 | 책별 감상, 인상 깊은 구절 저장 |
| 8 | 검색/필터 | 제목/저자/카테고리/시기별 탐색 |
대상: blog.naver.com/joekang (토리아빠의 50플러스 인사이트, 전체 2,516편)
‘독서,책’ 카테고리 = categoryNo 3, 총 168편 (예상했던 100여 편보다 많음)
data/blog_posts.json에 168편 전체 목록을 이미 수집해 두었다. (scripts/fetch_blog_posts.py)
모두 로그인 없이 호출 가능. Referer: https://blog.naver.com/ 헤더가 없으면 csrf 에러가 난다.
| 용도 | 엔드포인트 |
|---|---|
| 카테고리 목록 | m.blog.naver.com/rego/CategoryList.naver?blogId={id} |
| 글 목록(페이징) | blog.naver.com/PostTitleListAsync.naver?blogId={id}&categoryNo={no}¤tPage={p}&countPerPage=30 |
| 글 본문 | m.blog.naver.com/{id}/{logNo} → se-main-container 영역 파싱 |
| 최신글 RSS | rss.blog.naver.com/{id}.xml (증분 동기화용) |
주의: 글 목록 응답 JSON에 잘못된 escape가 섞여 있어 json.loads가 실패한다. 정규식으로 필요한 필드만 추출해야 한다. 제목은 URL 인코딩되어 있다.
(1) 23년치 기록이다. 글 작성 연도가 2003년부터 2026년까지 분포한다.
2003:1 2004:2 2006:2 2007:12 2008:9 2011:2 2012:7 2014:5 2015:5
2016:17 2017:12 2018:2 2019:5 2021:1 2022:22 2023:20 2024:26 2025:13 2026:5
→ 블로그만으로 사회생활 이후 독서 이력이 자동 복원된다. 수동 입력은 초/중/고/대 시절(블로그 이전)에 집중하면 된다. 서재를 “연도별 타임라인”으로 보여주는 뷰가 자연스럽게 나온다.
(2) 제목 규칙만으로는 책을 못 뽑는다. 168편 중 [독서노트] 류 접두어가 붙은 건 77편뿐이고, 70편은 아무 패턴이 없다.
성공하는 사람들의 7가지 습관_스티븐 코비 ← 책 (제목_저자)
주역(周易), 우주의 이치를 담은 동양 최고의 철학서 ← 책이지만 형식이 다름
106세 철학자 김형석 교수님의 강연에서 ← 책 아님 (강연 후기)
1년에 책 한권도 읽지 않는 당신에게... 교보문고가 박물관으로 ← 책 아님 (서점 이야기)
‘하얀 전쟁’ 소설가 안정효작가님 별세 소식에... ← 책 아님 (부고)
→ 정규식이 아니라 LLM으로 처리해야 한다. 파이프라인:
이 글이 특정 책에 대한 독후감인가? 판정 → 아니면 제외책 제목 / 저자 추출집에 있는 책장 사진 14장(pictures/)을 처리해 80권을 추출했다.
파이프라인: scripts/prepare_photos.py로 긴 변을 1600px로 축소(원본 4000px·2.5MB는 그대로 넣기엔 크다. EXIF 회전 보정 필수) → 비전 모델이 책등을 읽어 제목·저자 추출 → data/extracted/photos.json에 신뢰도와 함께 기록.
정확도의 한계가 분명하다. 책등은 세로쓰기에 글씨가 작고, 일부는 거꾸로 꽂혀 있거나 다른 책에 가려진다. 그래서 각 항목에 confidence(high/medium/low)를 붙였고, 사진에만 있으면서 확신이 낮은 30권은 needsReview 플래그가 붙는다. 실제 앱에서는 이 단계에 반드시 사용자 확인 화면이 필요하고, 정확도가 중요한 책은 바코드(ISBN) 스캔이 훨씬 신뢰할 만하다. 사진 인식은 “책장을 통째로 빠르게 훑는 용도”, 바코드는 “정확히 한 권을 넣는 용도”로 역할을 나누는 게 맞다.
사진에는 EMBA 교재·문제집·성경 필사 노트·동창회 명부처럼 서재에 꽂기 애매한 것도 섞여 있어 type: textbook 등으로 구분해 두었다.
다시 읽기(2026-09-19): 같은 14장을 한 장씩 잘라 확대해 다시 읽었더니 첫 추출이 절반도 못 건졌다(80 → 151권, 새 책 74권).
| 항목 | 수치 |
|---|---|
| 블로그 글 수집 | 168편 |
| 그중 책 독후감으로 판정 | 128편 (40편 제외) |
| 블로그에서 나온 책 | 124권 |
| 책장 사진에서 나온 책 | 80권 |
| 중복 제거 후 총 장서 | 196권 |
| 양쪽 모두에 있는 책 | 8권 |
| 확인 필요 | 30권 |
블로그와 사진 양쪽에 다 있는 8권(『세계는 평평하다』 『기브앤테이크』 『꾸뻬씨의 행복 여행』 등)은 독후감도 있고 실물도 집에 있는 책이다. 서재에서 특별하게 보여줄 만한 가치가 있다.
User
└─ UserBook (상태: 읽음/읽는중/읽고싶음, 시기: 초/중/고/대/성인, 평점,
출처: 수동입력 | 사진 | 블로그, 읽은시점)
├─ Book (마스터: 제목, 저자, 출판사, 표지, ISBN, 카테고리, 출간연도)
├─ Review (독후감 본문 — 직접작성 또는 블로그에서 수집, 원본 URL, 작성일)
└─ Quote[] (인상 깊은 구절, 페이지)
ImportCandidate (블로그에서 뽑았지만 아직 사용자 승인 전인 후보)
Shelf/Theme (3D 공간 테마 설정, 시기별 책장 매핑)
기존 계획은 블로그 연동을 후반부에 뒀지만, 검증 결과 168편이 즉시 확보되므로 순서를 바꾼다. 수동 입력부터 시작하면 서재가 텅 빈 채로 몇 주가 가지만, 블로그 수집을 먼저 하면 첫날부터 100권 이상 꽂힌 서재가 나온다. 3D 서재는 책이 어느 정도 차 있어야 감동이 생긴다.
app/, 아티팩트로 배포)data/categories.json) → 넷플릭스식 가로 줄 UIneedsReview 30권을 여기서 정리한다db 기능(문서 library/user). 실패하면 브라우저 저장으로 자동 대체data/memory_books.json에 기억으로 복원한 66권(초등 13 · 중·고 11 · 대학 42)을 넣고 빌드 때 합친다.
서명까지 기억나는 책은 확정, 저자·분야만 기억나는 30건은 ‘확인 필요’로 꽂혀 앱에서 제목을 고치면 풀린다.
기존 책 id(b0…b195)가 밀리지 않도록 반드시 배열 맨 뒤에 붙인다data/book_ids.json (2026-09-19): 사용자가 고친 내용은 id("b"+번호)에 저장되는데, 예전에는 번호가 곧 배열 순번이라
사진 책을 새로 넣으면(제목순 정렬) 뒤쪽 책과 기억 목록 66권의 id가 모두 밀렸다. 이제 빌드가 제목→번호 대장을 두고 새 책에만 끝 번호를 준다.
빠진 책의 번호는 다시 쓰지 않는다. 제목을 바로잡을 때는 대장의 키도 함께 바꿔야 그 책의 수정 기록이 따라간다.scripts/book_info.py가 카카오 책 검색으로 책마다 data/book_info/<제목>.json(저자·출판사·ISBN·소개글 등)과 <제목>.jpg(120x174 썸네일)를 저장한다.
python scripts/book_info.py --all: 등록된 모든 책(books.json + 기억 목록 중 제목이 있는 책). 받은 책은 건너뛴다. 223/232권 확보.python scripts/book_info.py "제목 / 저자" (또는 파일·직접 입력): 텍스트로 책을 추가한다. books.json에 sources: ["input"]로 들어가고 앱에서는 “텍스트로 직접 추가한 책”으로 보인다. 앱 id가 밀리지 않도록 빌드 때 맨 끝에 붙인다.scripts/build_app.py가 표지를 data URI로, 소개글을 상세 패널의 “책 소개”로 넣는다(아티팩트 CSP가 외부 이미지를 막으므로).python scripts/test_book_info.py책 API 선택 경위 — 중요
KAKAO_REST_API_KEY 사용자 환경변수. 첫 검색 결과는 소개글이 빈 판본이 많아 20개를 받아 고른다./search/v1/book 경로가 없다(404).
4-1. 첫 화면: 왼쪽 메뉴 + 서고 (three.js, 2D/3D, 2026-09-19)