     [Blog](https://scrapfly.io/blog)   /  [beautifulsoup](https://scrapfly.io/blog/tag/beautifulsoup)   /  [How to Scrape Naver.com: Search, Images, News, Blog, Shopping &amp; APIs (Update 2026)](https://scrapfly.io/blog/posts/how-to-scrape-naver)   # How to Scrape Naver.com: Search, Images, News, Blog, Shopping &amp; APIs (Update 2026)

 by [Ziad Shamndy](https://scrapfly.io/blog/author/ziad) Apr 28, 2026 27 min read [\#beautifulsoup](https://scrapfly.io/blog/tag/beautifulsoup) [\#python](https://scrapfly.io/blog/tag/python) [\#requests](https://scrapfly.io/blog/tag/requests) [\#scrapeguide](https://scrapfly.io/blog/tag/scrapeguide) 

 [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-naver "Share on LinkedIn")    

 

 

         

   **Web Scraping API — Anti-Bot Bypass**Bypass any anti-scraper system and automatically resolve JavaScript and fingerprint challenges.

 

 [ Learn More  ](https://scrapfly.io/products/web-scraping-api#features) [  Docs ](https://scrapfly.io/docs/scrape-api/getting-started#features) 

 

 

Scraping Naver in 2026 is harder than scraping Google because Naver serves its search results as JavaScript-embedded JSON, geo-prefers Korean IPs, and ships content across six distinct surfaces (search, images, news, blog, shopping, and finance) each with its own scraping approach. Naver holds around 64% of Korean search in early 2026 according to [StatCounter](https://gs.statcounter.com/search-engine-market-share/all/south-korea), well ahead of Google at roughly 30%, so Korean market research almost always starts here.

In this guide, you'll learn three approaches for each Naver surface: the official Naver Developers API for listings across 10 verticals, hidden JSON endpoints for richer data, and rendered HTML parsing as a last resort. We'll cover search, images, news, blog, shopping, finance, anti-bot handling, and a production setup with Scrapfly. Let's get started.

[How to Scrape Google Search Results in 2026In this scrape guide we'll be taking a look at how to scrape Google Search - the biggest index of public web. We'll cover dynamic HTML parsing and SERP collection itself.](https://scrapfly.io/blog/posts/how-to-scrape-google)



## Key Takeaways

Here's what every Naver scraping project needs to know:

- Use the **Naver Developers API** (`openapi.naver.com/v1/search/*`) for blog, news, shopping, image, webkr, encyclopedia, KiN, book, cafe article, and local search. 25,000 free requests per day per client ID across 10 verticals, returning clean JSON listings
- For organic web search, extract results from the **`entry.bootstrap()` JSON payload** inside Naver's `<script>` tags. The old HTML parsing approach stopped working in September 2025
- For Naver images, the **Developers API `/v1/search/image.json`** covers the standard case. Drop to the backend JSONP endpoint at `s.search.naver.com/p/c/image/search.naver` only when you need full-resolution URLs or volume beyond the 25k/day cap
- **Naver strongly prefers Korean IPs.** Most surfaces serve degraded content or CAPTCHAs from non-Korean geos. Route through a Korean proxy for reliable access
- **Scrapfly handles Naver end-to-end** (Korean IPs, anti-bot bypass, and JS rendering) in a single API call. It's the fastest way to ship a production Naver scraper

**Get web scraping tips in your inbox**Trusted by 100K+ developers and 30K+ enterprises. Unsubscribe anytime.







## What Makes Naver Hard to Scrape?

Naver is harder than Google because it combines JS-rendered search results, geo-restrictions that prefer Korean IPs, and six separate surfaces that each need a different scraping strategy. The official Naver Developers API covers listings across 10 verticals, but when you need full content (blog post bodies, news article text, product detail pages, SERP layout, image files) you have to scrape. See our [Google scraping guide](https://scrapfly.io/blog/posts/how-to-scrape-google) for a useful contrast with how Google's results are structured.

Naver ships content across six main surfaces: **search** (`search.naver.com`), **images** (image vertical of search), **news** (`news.naver.com`), **blog** (`blog.naver.com`), **shopping** (`shopping.naver.com`, `smartstore.naver.com`, `brand.naver.com`), and **finance** (`finance.naver.com`, `m.stock.naver.com`). Each surface prefers a different approach: the Developers API for listings, hidden JSON endpoints for full content, and rendered HTML parsing as a last resort.



## Which Scraping Approach Should You Use for Each Naver Surface?

The right approach depends on which Naver surface you're scraping. For blog, news, shopping, and web search listings, the official Naver Developers API is the correct first choice. For organic web SERPs, images, and real-time product detail, you need to scrape directly, either the HTML, the JS-embedded JSON, or a hidden backend endpoint.

Here's the decision table:

| Surface | Best approach | Why | Endpoint |
|---|---|---|---|
| Blog, News, Shopping, Image, Web search, Book, Encyclopedia, KiN, Cafe article, Local **listings** | Naver Developers Search API | Free 25k/day, stable JSON schema, no selectors to break, no geo issues | `openapi.naver.com/v1/search/<vertical>.json` |
| Organic web SERPs (full rendered page with ads, knowledge blocks, related blocks) | Extract `entry.bootstrap()` JSON from script tags | Naver moved to JS-rendered results in September 2025, DOM parsing is dead | `search.naver.com/search.naver?where=web` |
| Naver Finance (most-searched stocks, static tables) | Plain HTML scraping | One of the few Naver surfaces still on static HTML, no JS, no auth | `finance.naver.com/sise/lastsearch2.naver` |
| Naver Smart Store / `brand.naver.com` product detail | Hidden JSON endpoint or rendered browser | Real-time per-seller pricing isn't in the API, use Network tab inspection or render with Scrapfly | `smartstore.naver.com/<store>/products/<id>` |
| Mobile stock data (real-time quotes) | Hidden mobile JSON API | Naver's mobile UI uses richer JSON endpoints than the desktop Finance pages | `m.stock.naver.com/api/stock/*` |

The listings-vs-content split matters. The Developers API covers listings (titles, URLs, snippets, metadata) across 10 verticals for free. When you need full content (blog post bodies, news article text, Smart Store product detail, full SERP layout, image files), drop to hidden JSON endpoints or page scraping. Naver also rotates its `sds-comps-*` CSS classes every few months, so favor the API and backend JSON endpoints over DOM selectors wherever possible.



## How Do You Use the Naver Developers API?

The Naver Developers Search API is a free, header-authenticated REST API that returns JSON search listings across 10 verticals (blog, news, shopping, image, web documents, encyclopedia, Knowledge iN, book, cafe articles, and local). All verticals live under one client ID with a 25,000 requests/day limit.

### How Do You Register a Naver Developers App?

Registration takes about two minutes if you already have a Naver account. Go to the [Naver Developers app registration page](https://developers.naver.com/apps/#/register), accept the terms, complete phone verification (one-time), enter an app name (40 chars max), select **Search** under **Use API**, and add your service environments (web URL or mobile package name). Your **Client ID** and **Client Secret** appear in the app's Overview tab.



Use a corporate or team Naver account so credentials don't depend on one personal login. The console is primarily in Korean, so a browser translation extension helps.

### Which Verticals Does the Naver Search API Cover?

Each vertical lives at its own endpoint but shares the same base pattern and auth headers:

| Vertical | Endpoint | Use case | Key fields |
|---|---|---|---|
| Blog | `/v1/search/blog.json` | Korean blog content, brand mentions, reviews | `title`, `link`, `description`, `bloggername`, `bloggerlink`, `postdate` |
| News | `/v1/search/news.json` | Korean media monitoring, aggregation | `title`, `link`, `originallink`, `description`, `pubDate` |
| Shopping | `/v1/search/shop.json` | Product listings, pricing, sellers | `title`, `link`, `image`, `lprice`, `hprice`, `mallName`, `productId`, `brand` |
| Image | `/v1/search/image.json` | Image search results | `title`, `link`, `thumbnail`, `sizeHeight`, `sizeWidth` + optional `filter` param |
| Web search | `/v1/search/webkr.json` | Generic Korean web document search | `title`, `link`, `description` |
| Encyclopedia | `/v1/search/encyc.json` | Reference content | `title`, `link`, `description`, `thumbnail` |
| Knowledge iN | `/v1/search/kin.json` | Korean Q&amp;A community | `title`, `link`, `description` |
| Book | `/v1/search/book.json` | Book metadata, ISBN lookups | `title`, `link`, `image`, `author`, `price`, `publisher`, `isbn`, `pubdate` |
| Cafe article | `/v1/search/cafearticle.json` | Naver Cafe forum posts | `title`, `link`, `description`, `cafename`, `cafeurl` |
| Local | `/v1/search/local.json` | Place/business search | `title`, `link`, `category`, `address`, `roadAddress`, `mapx`, `mapy` |

Most verticals default `display` to 10, but image search defaults to 50. The max for `display` is 100 across all verticals. The image vertical also has an extra `filter` parameter (`all`, `large`, `medium`, `small`, `face`, `animated`) for constraining results by size or type.

### How Do You Send a Naver Search API Request in Python?

The standard pattern works for every vertical. Just swap the endpoint name:

python```python
import requests
import urllib.parse

CLIENT_ID = "YOUR_CLIENT_ID"
CLIENT_SECRET = "YOUR_CLIENT_SECRET"

# URL-encode the Korean query
query = urllib.parse.quote("파이썬")  # Python in Korean

# Blog search endpoint: swap to /news.json, /shop.json, etc.
url = f"https://openapi.naver.com/v1/search/blog.json?query={query}&display=10&start=1&sort=sim"

headers = {
    "X-Naver-Client-Id": CLIENT_ID,
    "X-Naver-Client-Secret": CLIENT_SECRET,
}

response = requests.get(url, headers=headers)
data = response.json()

for item in data["items"]:
    print(item["title"], "-", item["link"])
```



The four standard parameters work across all verticals: `query` (required, UTF-8), `display` (1-100), `start` (1-1000), and `sort` (`sim` or `date`). One code path handles all 10 verticals. Just swap `/blog.json` for `/news.json`, `/shop.json`, `/image.json`, etc.

### What Are the Naver API Rate Limits and Error Codes?

Naver caps the Search API at 25,000 requests per day per client ID across all verticals combined. The limit resets daily. For higher volume, register multiple client IDs or fall back to direct scraping with Scrapfly (covered below). Error code reference:

| Code | HTTP | Meaning | Fix |
|---|---|---|---|
| `SE01` | 400 | Invalid query or parameters | Check URL encoding and parameter names |
| `SE02` | 400 | Invalid `display` value | Must be 1-100 |
| `SE03` | 400 | Invalid `start` value | Must be 1-1000 |
| `SE04` | 400 | Invalid `sort` value | Must be `sim` or `date` |
| `SE06` | 400 | Malformed encoding | Make sure the query is UTF-8 encoded |
| `SE05` | 404 | API doesn't exist | Check endpoint spelling |
| `SE99` | 500 | Naver system error | Retry with exponential backoff |
| n/a | 403 | App not enabled for Search API | Turn on "Search" in app settings |



## How Do You Scrape Naver Search Results in 2026?

In 2026, Naver serves organic web search results as JSON embedded inside `<script>` tags, not as HTML elements. To scrape them, find the `entry.bootstrap()` script, extract the JSON argument, and pull results from `body.props.children[0].props.children[]`. The old CSS selector approach (`.fds-web-doc-root`, `ltg6gsSbjj8tY4bW3009`) broke in September 2025 when Naver moved search to a JS-rendered frontend.



### What Does Naver's Current Search URL Structure Look Like?

Search URL parameters:

| Parameter | Meaning | Example |
|---|---|---|
| `where` | Vertical (`web`, `news`, `image`, `blog`, `shop`, `video`) | `where=web` |
| `query` | Search term (UTF-8 encoded) | `query=%ED%8C%8C%EC%9D%B4%EC%8D%AC` |
| `page` | Page number | `page=2` |
| `start` | Result offset (1-based, step=15) | `start=16` for page 2 |
| `sort` | Result ordering | `sort=sim` or `sort=date` |
| `pd` | Date range filter | `pd=1` (today), `pd=2` (week), `pd=3` (month) |
| `sm` | Search mode | `sm=tab_hty.top` |
| `ackey`, `acq`, `acr` | Autocomplete tracking tokens | Drop them |

The `ackey`, `acq`, and `acr` parameters are autocomplete tracking tokens that appear in shared URLs but aren't required for scraping. Drop them.

python```python
import requests
import urllib.parse

query = urllib.parse.quote("파이썬")
# Start from page 2 to skip SERP feature clutter
url = f"https://search.naver.com/search.naver?where=web&query={query}&page=2&start=16"
response = requests.get(url, headers={"Accept-Language": "ko-KR,ko;q=0.9"})
```



Page 1 mixes organic results with ads, knowledge blocks, and related blocks. Page 2 and beyond give you cleaner organic results, which is why most scrapers skip page 1.

### How Do You Extract Results from the entry.bootstrap() JSON Payload?

Naver used to ship organic results as HTML elements with obfuscated classes. The HTML-selector approach stopped working in September 2025. Results now live inside a `<script>` tag containing an `entry.bootstrap(...)` function call with a JSON argument. The extraction flow: fetch the page, find the `entry.bootstrap(` script tag, brace-count to extract the JSON, parse, and walk the children array.

python```python
import requests
import re
import json
from bs4 import BeautifulSoup

def scrape_naver_search(query: str, page: int = 2) -> list[dict]:
    """Extract organic search results from Naver's entry.bootstrap() payload."""
    encoded = urllib.parse.quote(query)
    start = (page - 1) * 15 + 1
    url = f"https://search.naver.com/search.naver?where=web&query={encoded}&page={page}&start={start}"

    response = requests.get(url, headers={
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/131.0.0.0",
        "Accept-Language": "ko-KR,ko;q=0.9,en;q=0.8",
    })

    # Find the script tag that contains entry.bootstrap(
    soup = BeautifulSoup(response.text, "html.parser")
    script_text = None
    for tag in soup.find_all("script"):
        if tag.string and "entry.bootstrap(" in tag.string:
            script_text = tag.string
            break
    if not script_text:
        return []

    # Brace-count to extract the JSON argument
    start_idx = script_text.find("{", script_text.find("entry.bootstrap("))
    depth, end_idx = 0, start_idx
    for i, ch in enumerate(script_text[start_idx:], start_idx):
        if ch == "{":
            depth += 1
        elif ch == "}":
            depth -= 1
            if depth == 0:
                end_idx = i
                break

    data = json.loads(script_text[start_idx:end_idx + 1])

    # Walk the children to extract each result
    results = []
    children = data["body"]["props"]["children"][0]["props"]["children"]
    for item in children:
        props = item.get("props", {})
        # Each organic result has templateId="webItem"
        if item.get("templateId") != "webItem":
            continue
        # Strip <mark> tags that Naver wraps around matched query terms
        title = re.sub(r"<[^>]+>", "", props.get("title", "")).strip()
        body_text = re.sub(r"<[^>]+>", "", props.get("bodyText", "")).strip()
        results.append({
            "title": title,
            "url": props.get("href", ""),
            "description": body_text,
        })
    return results
```



Each result item has `templateId="webItem"` and exposes `title`, `href`, and `bodyText` in its props. Naver wraps matched query terms in `<mark>...</mark>` tags, so a regex strip cleans the output. If `entry.bootstrap` disappears in the future, use the hidden-JSON-endpoint discovery technique further down to find the new payload location.

### How Do You Paginate Naver Search Results?

Naver web search returns 15 results per page, not 10 like Google. The pagination formula is `start = (page - 1) * 15 + 1` (page 1 = `start=1`, page 2 = `start=16`, page 3 = `start=31`). Naver caps at 10 pages per query (150 results total). Start from page 2 for cleaner organic results, since page 1 carries ads and SERP feature blocks.

This is how page 1 looks like:



While this is how page 2 looks like:



## How Do You Scrape Naver Images?

For most Naver image scraping, use the official Naver Developers Image Search API at `/v1/search/image.json`. It's free, stable, header-authenticated, and returns clean JSON listings. For cases where you need full-resolution image URLs, fields not exposed by the API, or volume beyond the 25k/day cap, Naver's backend JSONP endpoint at `s.search.naver.com/p/c/image/search.naver` is an unauthenticated complement that uses the same response Naver's own UI consumes.

### Path 1: The Naver Developers Image Search API

The image endpoint uses the same auth headers as every other Search API vertical. Its parameters match the standard pattern (`query`, `display`, `start`, `sort`), with two image-specific touches: `display` defaults to 50 (higher than other verticals), and a `filter` parameter constrains results to size or type.

python```python
import requests
import urllib.parse

CLIENT_ID = "YOUR_CLIENT_ID"
CLIENT_SECRET = "YOUR_CLIENT_SECRET"

query = urllib.parse.quote("서울 야경")  # Seoul night view
# filter=large returns only high-resolution images
url = (
    "https://openapi.naver.com/v1/search/image.json"
    f"?query={query}&display=50&start=1&sort=sim&filter=large"
)

headers = {
    "X-Naver-Client-Id": CLIENT_ID,
    "X-Naver-Client-Secret": CLIENT_SECRET,
}

response = requests.get(url, headers=headers)
data = response.json()

for item in data["items"]:
    print(f"{item['title']}: {item['link']} ({item['sizeWidth']}x{item['sizeHeight']})")
```



The `filter` parameter accepts `all`, `large`, `medium`, `small`, `face`, and `animated`. Each image item returns `title` (with `<b>` tags around matched terms), `link` (original image URL), `thumbnail`, and `sizeHeight` / `sizeWidth`. Use the Image API path by default. The API is stable, authoritative, and free up to 25,000 requests per day shared across all Search API verticals.

### Path 2: The backend JSONP endpoint

Reach for the backend endpoint when you need full-resolution `originalUrl` values the API may not expose, richer fields like thumbnail dimensions, volume beyond the 25k/day cap, or unauthenticated access for a lightweight tool without app registration.

The endpoint:

text```text
https://s.search.naver.com/p/c/image/search.naver?query=<encoded>&json_type=6&display=50&start=1&_callback=serpapi
```



The response is JSONP, not plain JSON, so it arrives wrapped as `serpapi({ "items": [...] })`. Regex-strip the wrapper before parsing.

python```python
import requests
import re
import json
import urllib.parse

query = urllib.parse.quote("서울 야경")
url = (
    "https://s.search.naver.com/p/c/image/search.naver"
    f"?query={query}&json_type=6&display=50&start=1&_callback=serpapi"
)

response = requests.get(url, headers={
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/131.0.0.0",
    "Referer": "https://search.naver.com/",
    "Accept-Language": "ko-KR,ko;q=0.9",
})

# Strip the serpapi(...) callback wrapper
match = re.search(r"serpapi\((\{.*\})\)", response.text, re.DOTALL)
data = json.loads(match.group(1))

for item in data["items"]:
    print(f"{item['title']}: {item['originalUrl']} ({item['orgWidth']}x{item['orgHeight']})")
```



Each image item exposes `title`, `writerTitle` (source attribution), `thumb`, `thumbWidth`/`thumbHeight`, `orgWidth`/`orgHeight`, and `originalUrl` (the full-resolution download URL). There's no top-level `link` field, so use `originalUrl`. The backend endpoint still returns degraded results from non-Korean IPs in some cases. Use a Korean proxy for production reliability.

Once you have the image URLs from either path, see our guide on [how to scrape and download images at scale](https://scrapfly.io/blog/posts/how-to-web-scrape-images-from-websites-python) for the file-handling foundations.



## How Do You Scrape Naver News?

The easiest way to get Naver news at scale is the Naver Developers API `/news` vertical, which returns publisher, headline, summary, original link, and publication date for up to 25,000 queries per day. For full article text you need to scrape individual `news.naver.com` pages, which use the current `sds-comps-*` DOM namespace.

### Path 1: Developers API for news listings

The code pattern is the same as the blog API call above. Just swap `/blog.json` for `/news.json`:

python```python
import requests
import urllib.parse

query = urllib.parse.quote("인공지능")  # Artificial intelligence
url = f"https://openapi.naver.com/v1/search/news.json?query={query}&display=20&sort=date"

response = requests.get(url, headers={
    "X-Naver-Client-Id": "YOUR_CLIENT_ID",
    "X-Naver-Client-Secret": "YOUR_CLIENT_SECRET",
})

for item in response.json()["items"]:
    print(f"[{item['pubDate']}] {item['title']}")
    print(f"  Original: {item['originallink']}")
    print(f"  Naver: {item['link']}")
```



News-specific fields: `originallink` is the source publisher's URL, `link` is Naver's mirrored version. Use `originallink` when scraping the full body. The `pubDate` follows RFC 1123 format.

### Path 2: Full article body scraping

For full article text, scrape the individual page at `https://n.news.naver.com/article/<press_id>/<article_id>`. These pages use the current `sds-comps-*` DOM namespace:

python```python
import requests
from bs4 import BeautifulSoup

url = "https://n.news.naver.com/article/001/0015234567"  # example ID
response = requests.get(url, headers={
    "User-Agent": "Mozilla/5.0 Chrome/131.0.0.0",
    "Accept-Language": "ko-KR,ko;q=0.9",
})

soup = BeautifulSoup(response.text, "html.parser")
# Conceptual: sds-comps-* classes rotate every few months
title_el = soup.select_one(".sds-comps-text-type-headline1")
body_el = soup.select_one(".sds-comps-text-type-body1")
title = title_el.get_text(strip=True) if title_el else ""
body = body_el.get_text(strip=True) if body_el else ""
```



The `sds-comps-*` selectors rotate every few months. If the `sds-comps-*` selectors stop working, use the hidden-JSON-endpoint discovery technique below. You can also filter news searches by date with `&pd=1` (today), `pd=2` (week), or `pd=3` (month).



## How Do You Scrape Naver Blog?

For blog search results, use the Naver Developers Blog API at `/v1/search/blog.json`. It returns post title, URL, description, blogger name, blogger URL, and post date with no scraping needed. For full blog post content, you need to scrape `blog.naver.com` directly, which requires handling a nested `<iframe>` where the post body actually lives.



### Path 1: Developers API for blog listings

Same pattern as the other verticals. Blog-specific fields: `bloggername`, `bloggerlink`, and `postdate` (`yyyymmdd` format). For most brand monitoring, review mining, or sentiment analysis, the listing data is enough.

### Path 2: Full blog post content (the iframe trick)

Naver Blog posts render inside a nested `<iframe>`, not in the main page HTML. Fetching `blog.naver.com/<blogger>/<post_id>` directly won't show the post body in `response.text`. The iframe trick is the #1 reason most Naver Blog scrapers fail:

python```python
import requests
from bs4 import BeautifulSoup

session = requests.Session()
session.headers.update({
    "User-Agent": "Mozilla/5.0 Chrome/131.0.0.0",
    "Accept-Language": "ko-KR,ko;q=0.9",
})

# Step 1: fetch the main blog page
post_url = "https://blog.naver.com/example_blogger/223456789012"
response = session.get(post_url)
soup = BeautifulSoup(response.text, "html.parser")

# Step 2: find the iframe pointing to the actual post content
iframe = soup.find("iframe", id="mainFrame")
iframe_src = iframe["src"]  # e.g. /PostView.naver?blogId=...&logNo=...

# Step 3: fetch the iframe URL (session cookie from step 1 is required)
iframe_url = "https://blog.naver.com" + iframe_src
iframe_response = session.get(iframe_url)
post_content = BeautifulSoup(iframe_response.text, "html.parser")
# Extract post title and body from post_content (selectors rotate)
```



Three Naver Blog domains to keep when cleaning URL lists: `blog.naver.com`, `m.blog.naver.com`, and `post.naver.com`. One known limitation: Naver Blog posts sometimes embed text as screenshots (a Korean blogging convention) that won't parse cleanly. OCR is the only workaround.



Scrapfly

#### Extract structured data automatically?

Scrapfly's Extraction API uses AI to turn any webpage into structured data — no selectors needed.

[Try Free →](https://scrapfly.io/register)## How Do You Scrape Naver Shopping and Smart Store?

For product search and listings, use the Naver Developers Shop API at `/v1/search/shop.json`. It returns product title, image, low/high price, mall name, product ID, and brand. For individual product detail pages on `smartstore.naver.com` and `brand.naver.com`, you need to hit Naver's hidden JSON endpoint or render the page with a browser.

### Path 1: Developers API for product listings

python```python
import requests
import urllib.parse

query = urllib.parse.quote("게이밍 헤드셋")  # Gaming headset
url = f"https://openapi.naver.com/v1/search/shop.json?query={query}&display=20"

response = requests.get(url, headers={
    "X-Naver-Client-Id": "YOUR_CLIENT_ID",
    "X-Naver-Client-Secret": "YOUR_CLIENT_SECRET",
})

for item in response.json()["items"]:
    print(f"{item['title']} | {item['lprice']} - {item['hprice']} KRW | {item['mallName']}")
```



Shop-specific fields: `lprice` and `hprice` are the low and high price Naver found across merchants, `mallName` is the selling merchant, `productId` is Naver's internal product ID, and `brand` is the brand name when available.

### Path 2: Individual product pages

Product detail pages at `smartstore.naver.com/<store>/products/<id>` and `brand.naver.com/<brand>/products/<id>` render content with encrypted session tokens for pricing. Two working approaches: inspect the Network tab to find the internal product detail API (returns clean JSON), or use Scrapfly's `render_js=True` to render the page and extract from the DOM. For real-time per-seller pricing, the API's `lprice`/`hprice` aren't enough. Scrape the individual product page directly.



## How Do You Scrape Naver Finance and Stock Data?

Naver Finance's most-searched stocks page at `finance.naver.com/sise/lastsearch2.naver` is the easiest Naver surface to scrape. Static HTML, no authentication, no JavaScript required. For real-time stock quotes and richer data, `m.stock.naver.com` exposes a mobile JSON API that you can discover via the Network tab.

python```python
import requests
from bs4 import BeautifulSoup

url = "https://finance.naver.com/sise/lastsearch2.naver"
response = requests.get(url, headers={
    "User-Agent": "Mozilla/5.0 Chrome/131.0.0.0",
    "Accept-Language": "ko-KR,ko;q=0.9",
})

soup = BeautifulSoup(response.text, "html.parser")
stocks = []

# The most-searched stocks table
for row in soup.select("table.type_5 tr"):
    tds = row.select("td")
    if len(tds) < 6:
        continue
    name_link = row.select_one("td a.tltle")
    if not name_link:
        continue
    name = name_link.get_text(strip=True)
    # Strip commas from Korean-formatted prices (e.g. "1,234,567")
    price = tds[3].get_text(strip=True).replace(",", "")
    change_rate = tds[5].get_text(strip=True)
    stocks.append({"name": name, "price": int(price) if price.isdigit() else price, "change": change_rate})

for stock in stocks[:10]:
    print(f"{stock['name']}: {stock['price']} KRW ({stock['change']})")
```



Gotcha: Chrome DevTools sometimes shows a normalized DOM that doesn't match the raw HTML. If a selector matches in DevTools but not in Python, compare `response.text` against "View Source" in the browser. For richer data, `m.stock.naver.com` exposes mobile JSON endpoints like `/api/stock/basic/` and `/api/stock/integration/` that you can discover via the Network tab.



## How Do You Find Naver's Hidden JSON API Endpoints?

Open any Naver page in Chrome, press F12, switch to the Network tab, filter by "Fetch/XHR", and reload. The requests that return JSON are Naver's internal API endpoints that you can hit directly, bypassing HTML parsing. Naver's own UI fetches structured data from these internal APIs, so they're the source of truth and are much more stable than the rendered HTML.

Step-by-step: open the Naver page in Chrome, press F12 and switch to the Network tab with "Fetch/XHR" filter, reload with Ctrl+R (or trigger scrolling for more results), look for responses with `application/json` or `application/javascript` content types, click "Response" to verify the data is there, right-click and "Copy as cURL (bash)" to grab the full request with headers, then convert to Python `requests` code.



Common Naver hidden JSON endpoints found this way:

- **Image search**: `s.search.naver.com/p/c/image/search.naver` (JSONP)
- **Shopping product detail**: `search.shopping.naver.com/api/search/all`
- **Mobile stock data**: `m.stock.naver.com/api/stock/*`
- **Autocomplete**: `ac.search.naver.com/nx/ac`

If a JSON endpoint returns 200 in Chrome but 403 in Python, you're missing a required header. The culprit is almost always `Referer: https://www.naver.com/` or `Origin: https://search.naver.com`. Copy the exact headers from the cURL export.

[How to Scrape Hidden APIsIn this tutorial we'll be taking a look at scraping hidden APIs which are becoming more and more common in modern dynamic websites - what's the best way to scrape them?](https://scrapfly.io/blog/posts/how-to-scrape-hidden-apis)



## How Do You Avoid Getting Blocked by Naver?

Naver blocks scrapers by watching IP origin (especially non-Korean geos), request headers (especially missing `Accept-Language: ko-KR`), request rate, and behavior signals. Use a Korean IP, set realistic Korean browser headers, throttle requests, and fall back to [anti-bot bypass techniques](https://scrapfly.io/blog/posts/how-to-bypass-anti-bot-protection-when-web-scraping) or Scrapfly when Naver escalates.

### Why Does Naver Block Requests from Outside Korea?

Naver strongly prefers Korean IPs. Non-Korean IPs may get a simplified version with fewer features, trigger CAPTCHAs more aggressively, get rate-limited more strictly, or receive 403/429 on several surfaces.

Quick diagnostic: if your scraper works locally but fails on a cloud server, the cause is almost certainly geo-blocking, not anti-bot detection. Test the same code through a Korean IP before assuming you need a full anti-bot solution. For any production Naver scraping, use a Korean residential or datacenter proxy. See our [introduction to proxies in web scraping](https://scrapfly.io/blog/posts/introduction-to-proxies-in-web-scraping) for the residential/datacenter/mobile tradeoffs.

### What Headers and Session Settings Does Naver Expect?

The key session headers for HTML scraping:

python```python
import requests

session = requests.Session()
session.headers.update({
    "Accept-Language": "ko-KR,ko;q=0.9,en;q=0.8",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
    "Accept-Encoding": "gzip, deflate, br",
    "Connection": "keep-alive",
})
```



A persistent `requests.Session()` keeps cookies across calls, which Naver expects. Cold sessions get flagged more aggressively. Filter out Naver's ad and utility domains when cleaning scraped URL lists: `ader.naver.com`, `adcr.naver.com`, `help.naver.com`, `keep.naver.com`, `nid.naver.com`, `pay.naver.com`, and `m.pay.naver.com`.

For a deeper walkthrough of which headers matter and why, see our [Python requests headers guide](https://scrapfly.io/blog/posts/python-requests-headers-guide) and [how headers are used to block scrapers](https://scrapfly.io/blog/posts/how-to-avoid-web-scraping-blocking-headers).

### How Do You Handle Naver's CAPTCHAs and Rate Limits?

CAPTCHAs appear when you scrape too fast, use a non-Korean IP, skip `Accept-Language: ko-KR`, or spam the same query repeatedly. Mitigation: randomize delays between 1 and 3 seconds, rotate User-Agents across a realistic Chrome/Firefox pool, rotate IPs across a Korean residential pool, and respect `Retry-After` headers on 429 responses.

Building Korean proxy setup yourself is non-trivial. You either invest engineering time into a Korean residential pool with CAPTCHA handling, or use a managed service like Scrapfly that handles it all in one API call

## How Do You Scrape Naver at Scale with Scrapfly?



ScrapFly provides web scraping, screenshot, and extraction APIs for data collection at scale. For Naver specifically, Scrapfly's [Web Scraping API](https://scrapfly.io/products/web-scraping-api) is the fastest path to a production scraper because it handles every Naver-specific obstacle (Korean IP routing, JavaScript rendering of the `entry.bootstrap()` payload, anti-bot bypass, and CAPTCHAs) in a single API call.

Key features for Naver scraping:

- [Anti-Scraping Protection (ASP)](https://scrapfly.io/docs/scrape-api/anti-scraping-protection) bypasses Naver's fingerprinting, CAPTCHAs, and behavior detection with `asp=True`
- [Residential proxies](https://scrapfly.io/docs/scrape-api/proxies) in South Korea through `country="KR"`, no proxy pool to manage
- [JavaScript rendering](https://scrapfly.io/docs/scrape-api/javascript-rendering) through headless browsers with `render_js=True`, required for modern Naver SERPs
- [Sticky sessions](https://scrapfly.io/docs/scrape-api/session) via `session="naver-session"` so Naver sees returning-visitor cookies across requests
- [Python SDK](https://scrapfly.io/docs/sdk/python) for direct integration

Here's the reference implementation that scrapes Naver organic search results through Scrapfly:

python```python
from scrapfly import ScrapflyClient, ScrapeConfig
from bs4 import BeautifulSoup
import json
import re

client = ScrapflyClient(key="YOUR_SCRAPFLY_API_KEY")

# Scrape page 2 of Naver web search for "게이밍 헤드셋" (gaming headset)
result = client.scrape(ScrapeConfig(
    url="https://search.naver.com/search.naver?where=web&query=%EA%B2%8C%EC%9D%B4%EB%B0%8D+%ED%97%A4%EB%93%9C%EC%85%8B&page=2&start=16",
    asp=True,                # anti-bot bypass
    country="KR",            # Korean IP
    render_js=True,          # required for 2025+ JS-rendered results
    session="naver-search",  # sticky cookies across requests
))

# Parse the entry.bootstrap() JSON payload from the rendered HTML
soup = BeautifulSoup(result.content, "html.parser")
for script in soup.find_all("script"):
    if script.string and "entry.bootstrap(" in script.string:
        start = script.string.find("{", script.string.find("entry.bootstrap("))
        depth, end = 0, start
        for i, char in enumerate(script.string[start:], start):
            if char == "{":
                depth += 1
            elif char == "}":
                depth -= 1
                if depth == 0:
                    end = i
                    break
        data = json.loads(script.string[start:end + 1])
        for item in data["body"]["props"]["children"][0]["props"]["children"]:
            if item.get("templateId") != "webItem":
                continue
            props = item["props"]
            title = re.sub(r"<[^>]+>", "", props.get("title", "")).strip()
            url = props.get("href", "")
            print(f"{title}\n{url}\n")
        break
```



Per-surface Scrapfly configuration:

| Surface | `asp` | `country` | `render_js` | Notes |
|---|---|---|---|---|
| Web search (organic SERPs) | `True` | `KR` | `True` | Required for `entry.bootstrap()` payload |
| Image search (JSONP backend, full-res URLs) | `True` | `KR` | `False` | JSONP works without JS rendering |
| News search (rendered page) | `True` | `KR` | `True` | Same as web search |
| Blog post pages (iframe) | `True` | `KR` | `True` | Iframe navigation needs a real browser |
| Smart Store / `brand.naver.com` detail | `True` | `KR` | `True` | Encrypted session tokens need rendering |
| Naver Finance (static tables) | `False` | `KR` | `False` | Static HTML, just needs a Korean IP |
| Naver Developers API | n/a | n/a | n/a | Direct `requests` call, no Scrapfly needed |

The Naver Developers API is still free and still the right answer for listings. Scrapfly is the right answer when you need full content (blog post bodies, news article text, Smart Store product detail, full SERP layout) or need to scale beyond the 25k/day API cap.

### Web Scraping API

Scrape any website with our powerful API. Anti-bot bypass, JavaScript rendering, and rotating proxies built-in.



[Try Web Scraping API](https://scrapfly.io/docs/scrape-api/getting-started)





## FAQ

Do I need a Korean proxy to scrape Naver?Yes, for most surfaces. Naver serves degraded content or throws CAPTCHAs at non-Korean IPs. The main exceptions are the Naver Developers API (no geo restrictions since it's an authenticated first-party API) and static pages like `finance.naver.com/sise/lastsearch2.naver`. For production scraping, use Scrapfly with `country="KR"`, which handles Korean IP routing without you managing a proxy pool.







What's the difference between the Naver Developers API and scraping Naver?The Naver Developers API is the official REST API at `openapi.naver.com/v1/search/*` that returns JSON listings across 10 verticals (blog, news, shopping, image, web, encyclopedia, KiN, book, cafe article, local). It's free up to 25,000 requests per day per client ID. "Scraping Naver" means going beyond those listings for full content (blog post bodies, news article text, product detail pages, SERP layout) by parsing the rendered HTML or hitting Naver's hidden JSON endpoints.







What are the `ackey`, `acq`, and `acr` parameters in Naver search URLs?These are autocomplete tracking tokens Naver adds when you click a search suggestion. `ackey` identifies the autocomplete session, `acq` is the originally typed query, and `acr` is the autocomplete rank of the selected suggestion. These tokens aren't required for scraping and can be safely dropped from URLs. They only appear in user-initiated navigation, not in direct API requests.







How do I find Naver's hidden JSON endpoints?Open any Naver page in Chrome, press F12, switch to the Network tab, filter by "Fetch/XHR", and reload. The requests returning JSON are Naver's internal endpoints. Right-click, then "Copy as cURL", to get the full request including headers (keep `Referer: https://www.naver.com/`). See the "How Do You Find Naver's Hidden JSON API Endpoints?" section above for the full walkthrough.









## Summary

Scraping Naver means picking the right approach for each of its six surfaces. For listings across 10 verticals (blog, news, shopping, image, web, encyclopedia, Knowledge iN, book, cafe article, local), the Naver Developers API is free and stable. For organic web search, extract the `entry.bootstrap()` JSON payload from script tags. For images, start with the API, then drop to the backend JSONP endpoint only for full-resolution URLs or higher volume.

The listings-vs-content boundary matters. Hidden JSON endpoints cover full-content cases like Smart Store product detail and mobile stock data. Naver Finance stays the easiest surface, with static HTML and no JavaScript. Use Korean IPs for almost everything outside the Developers API.

Naver rotates its `sds-comps-*` CSS classes every few months, so favor the API and backend JSON endpoints over DOM selectors wherever you can. For production-scale Naver scraping without building a Korean proxy pool and CAPTCHA pipeline yourself, [Scrapfly](https://scrapfly.io) handles every surface in one API call.



Legal Disclaimer and PrecautionsThis tutorial covers popular web scraping techniques for education. Interacting with public servers requires diligence and respect:

- Do not scrape at rates that could damage the website.
- Do not scrape data that's not available publicly.
- Do not store PII of EU citizens protected by GDPR.
- Do not repurpose *entire* public datasets which can be illegal in some countries.

Scrapfly does not offer legal advice but these are good general rules to follow. For more you should consult a lawyer.

 

    Table of Contents- [Key Takeaways](#key-takeaways)
- [What Makes Naver Hard to Scrape?](#what-makes-naver-hard-to-scrape)
- [Which Scraping Approach Should You Use for Each Naver Surface?](#which-scraping-approach-should-you-use-for-each-naver-surface)
- [How Do You Use the Naver Developers API?](#how-do-you-use-the-naver-developers-api)
- [How Do You Register a Naver Developers App?](#how-do-you-register-a-naver-developers-app)
- [Which Verticals Does the Naver Search API Cover?](#which-verticals-does-the-naver-search-api-cover)
- [How Do You Send a Naver Search API Request in Python?](#how-do-you-send-a-naver-search-api-request-in-python)
- [What Are the Naver API Rate Limits and Error Codes?](#what-are-the-naver-api-rate-limits-and-error-codes)
- [How Do You Scrape Naver Search Results in 2026?](#how-do-you-scrape-naver-search-results-in-2026)
- [What Does Naver's Current Search URL Structure Look Like?](#what-does-naver-s-current-search-url-structure-look-like)
- [How Do You Extract Results from the entry.bootstrap() JSON Payload?](#how-do-you-extract-results-from-the-entry-bootstrap-json-payload)
- [How Do You Paginate Naver Search Results?](#how-do-you-paginate-naver-search-results)
- [How Do You Scrape Naver Images?](#how-do-you-scrape-naver-images)
- [Path 1: The Naver Developers Image Search API](#path-1-the-naver-developers-image-search-api)
- [Path 2: The backend JSONP endpoint](#path-2-the-backend-jsonp-endpoint)
- [How Do You Scrape Naver News?](#how-do-you-scrape-naver-news)
- [Path 1: Developers API for news listings](#path-1-developers-api-for-news-listings)
- [Path 2: Full article body scraping](#path-2-full-article-body-scraping)
- [How Do You Scrape Naver Blog?](#how-do-you-scrape-naver-blog)
- [Path 1: Developers API for blog listings](#path-1-developers-api-for-blog-listings)
- [Path 2: Full blog post content (the iframe trick)](#path-2-full-blog-post-content-the-iframe-trick)
- [How Do You Scrape Naver Shopping and Smart Store?](#how-do-you-scrape-naver-shopping-and-smart-store)
- [Path 1: Developers API for product listings](#path-1-developers-api-for-product-listings)
- [Path 2: Individual product pages](#path-2-individual-product-pages)
- [How Do You Scrape Naver Finance and Stock Data?](#how-do-you-scrape-naver-finance-and-stock-data)
- [How Do You Find Naver's Hidden JSON API Endpoints?](#how-do-you-find-naver-s-hidden-json-api-endpoints)
- [How Do You Avoid Getting Blocked by Naver?](#how-do-you-avoid-getting-blocked-by-naver)
- [Why Does Naver Block Requests from Outside Korea?](#why-does-naver-block-requests-from-outside-korea)
- [What Headers and Session Settings Does Naver Expect?](#what-headers-and-session-settings-does-naver-expect)
- [How Do You Handle Naver's CAPTCHAs and Rate Limits?](#how-do-you-handle-naver-s-captchas-and-rate-limits)
- [How Do You Scrape Naver at Scale with Scrapfly?](#how-do-you-scrape-naver-at-scale-with-scrapfly)
- [Web Scraping API](#web-scraping-api)
- [FAQ](#faq)
- [Summary](#summary)
 
    Join the Newsletter  Get monthly web scraping insights 

 

  



Scale Your Web Scraping

Anti-bot bypass, browser rendering, and rotating proxies, all in one API. Start with 1,000 free credits.

  No credit card required  1,000 free API credits  Anti-bot bypass included 

 [Start Free](https://scrapfly.io/register) [View Docs](https://scrapfly.io/docs/onboarding) 

 Not ready? Get our newsletter instead. 

 

## Explore this Article with AI

 [ ChatGPT ](https://chat.openai.com/?q=Summarize%20this%20page%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-naver) [ Gemini ](https://www.google.com/search?udm=50&aep=11&q=Summarize%20this%20page%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-naver) [ Grok ](https://x.com/i/grok?text=Summarize%20this%20page%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-naver) [ Perplexity ](https://www.perplexity.ai/search/new?q=Summarize%20this%20page%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-naver) [ Claude ](https://claude.ai/new?q=Summarize%20this%20page%3A%20https%3A%2F%2Fscrapfly.io%2Fblog%2Fposts%2Fhow-to-scrape-naver) 



 ## Related Articles

 [  

 python crawling 

### Intro to Web Scraping Images with Python

In this guide, we’ll explore how to scrape images from websites using different methods. We'll also cover the most commo...

 

 ](https://scrapfly.io/blog/posts/how-to-web-scrape-images-from-websites-python) [  

 python scrapeguide 

### How to Scrape Google Search Results in 2026

In this scrape guide we'll be taking a look at how to scrape Google Search - the biggest index of public web. We'll cov...

 

 ](https://scrapfly.io/blog/posts/how-to-scrape-google) [     

 api 

### Guide to Yahoo Finance API

Yahoo Financehttps://finance.yahoo.com/ is a comprehensive platform for accessing stock market data, financial news, com...

 

 ](https://scrapfly.io/blog/posts/guide-to-yahoo-finance-api) 

  ## Related Questions

- [ Q How to get file type of an URL in Python? ](https://scrapfly.io/blog/answers/how-to-get-url-filetype-in-python)
- [ Q How to fix Python requests MissingSchema error? ](https://scrapfly.io/blog/answers/python-requests-exception-missingschema)
 
  



   



 Extract structured data with AI, **1,000 free credits** [Start Free](https://scrapfly.io/register)