From naver-blog-importer
Bulk-imports Naver Blog posts from blog.naver.com into local Markdown files with images downloaded to assets/ folders. For full blog exports to Obsidian or static sites.
npx claudepluginhub lazyyoyo/naver-blog-importer --plugin naver-blog-importerThis skill uses the workspace's default tool permissions.
Bulk-import a Naver Blog's posts into local Markdown files with images downloaded to an `assets/` folder alongside each post.
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Processes PDFs: extracts text/tables/images, merges/splits/rotates pages, adds watermarks, creates/fills forms, encrypts/decrypts, OCRs scans. Activates on PDF mentions or output requests.
Share bugs, ideas, or general feedback.
Bulk-import a Naver Blog's posts into local Markdown files with images downloaded to an assets/ folder alongside each post.
blog.naver.com/{blogId} URL and wants all posts pulled downweb_fetch with the m.blog.naver.com URL directlyBefore running the script for the first time, check that Python deps are installed:
python3 -c "import requests, bs4, markdownify" 2>/dev/null
If that exits non-zero, install them silently — do NOT ask the user, just install:
pip install -r "$(dirname "$0")/requirements.txt" \
|| python3 -m pip install --user requests beautifulsoup4 markdownify
(Use the requirements.txt shipped alongside this SKILL.md when possible. Fall back to --user install if pip lacks permissions.)
After install, re-check the import. If it still fails, surface the error to the user. Otherwise proceed silently — do not announce "installed deps", just continue with the actual task.
When invoked via slash (/naver-blog-importer <args>), the args are the same as the CLI flags below — pass them straight to scripts/import_blog.py. If the user gives a full URL (e.g. blog.naver.com/myblog or https://blog.naver.com/myblog/22312345), extract the blogId before calling the script.
When invoked via natural language ("내 네이버 블로그 백업해줘"), ask for the blogId if not provided, then choose flags based on what they said:
--limit N--list-only--category-no N (ask for N)--forceAfter the run, report counts (ok / skipped / failed) and the output directory path.
# List all posts first (dry run, no downloads)
python scripts/import_blog.py <blogId> --list-only
# Import everything
python scripts/import_blog.py <blogId> --out ./naver-import
# Import a specific category
python scripts/import_blog.py <blogId> --category-no 7 --out ./naver-import
# Import a range (skip already-imported, resume from N)
python scripts/import_blog.py <blogId> --start 0 --limit 50
blogId is the part after blog.naver.com/ — e.g. for blog.naver.com/myblog the id is myblog.
https://blog.naver.com/PostTitleListAsync.naver (the internal AJAX endpoint Naver itself uses for pagination) to enumerate every logNo on the blog. Paginates until exhausted.https://m.blog.naver.com/{blogId}/{logNo} which returns real HTML (the desktop URL wraps content in an iframe and returns an empty shell)..se-main-container) and the legacy editor (#postViewArea / .post_ct). Extracts title + body only.assets/{logNo}/img_NNN.{ext}, strips Naver's ?type=w80 resize params to get originals, rewrites markdown references to relative paths.markdownify for clean output. Preserves headings, bold/italic, lists, blockquotes, code blocks, links.{yyyy-mm-dd}-{slugified-title}.md (date comes from the post metadata in the listing response).<out-dir>/
├── 2024-03-15-포스트제목.md
├── 2024-03-18-다른글.md
└── assets/
├── 223123456789/
│ ├── img_001.jpg
│ └── img_002.png
└── 223123456790/
└── img_001.jpg
Filenames use the original Korean title slugified (spaces → -, special chars stripped). If two posts collide, logNo is appended.
The script is idempotent — if a .md file for a given logNo already exists in the output directory, it skips. To force re-import, delete the file or pass --force.
Progress is logged to stdout. On failure mid-run, re-running picks up where it stopped.
Default is 1 request/second with random 0.3–0.8s jitter. Naver tolerates this fine for a personal blog (~hundreds of posts). For larger blogs, lower concurrency not higher — don't add threading, you'll get soft-banned.
assets/*/sticker_*.gif after the fact if you want)https://m.blog.naver.com/{blogId}/{logNo} manually.PostTitleListAsync at ~30 pages sometimes. Use --category-no to iterate category-by-category instead.scripts/import_blog.py — main entry point, CLIscripts/fetch.py — URL normalization, listing pagination, post fetchingscripts/parse.py — SmartEditor / legacy editor parsing, markdown conversionscripts/images.py — image URL normalization + download