# NetEase Music Scraper (`crawlerbros/netease-music-scraper`) Actor

Scrape NetEase Cloud Music (music.163.com) without login - search song suggestions, fetch songs by URL, artist top songs, browse playlists, and pull top-100 charts with cover art and full metadata.

- **URL**: https://apify.com/crawlerbros/netease-music-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## NetEase Music Scraper

Scrapes [NetEase Cloud Music](https://music.163.com/) (网易云音乐) — China's largest music streaming platform — **without login**.

### Data source

Music data and lyrics come from the public NetEase Cloud Music web endpoints (music.163.com `/api/...`) — no login, no API key. See the Notes section for endpoint-level caveats.

### What it does

| Mode | Endpoint (public, no auth) | Output |
|---|---|---|
| `search` | `/api/search/get?type=1&s=&limit=&offset=` | Song search (paginated, deduped) |
| `bySongUrl` | `/api/song/detail/?id=&ids=` (+ optional LRC lyric) | Full song record incl. popularity, score, mv id |
| `byArtist` | `/api/artist/top/song?id=&offset=` | Artist top songs (paginated) |
| `byArtistAlbums` | `/api/artist/albums/{id}?limit=&offset=` | Artist album discography (paginated) |
| `byPlaylist` | `/api/playlist/list?cat=&order=&offset=` | Playlist browse (paginated) |
| `byToplist` | `/api/toplist/detail` + `/api/playlist/detail?id=` | Chart summary + top-100 tracks |

All endpoints verified live (HTTP 200 with real content) from a datacenter network. The web search endpoint `/api/search/get/web` returns AES-encrypted payloads (anti-bot), so search uses the plaintext `/api/search/get` endpoint instead (paginated up to `maxItems`, deduped by song id). The album-detail endpoint (`/api/album/*`) is no longer served publicly — album *metadata* is exposed via `byArtistAlbums`, and album tracks via playlist/artist/toplist modes.

### Output fields

**song records (`recordType: "song"`)** — `songId`, `name`, `alias[]`, `artists[]`, `artist`, `albumId`, `album`, `durationSec`, `coverUrl`, `popularity`, `score`, `fee`, `mvid`, `publishTimeMs`, `commentThreadId`, `playedNum`, `starredNum`, `copyright`, `copyrightId`, `disc`, `trackNo`, `position`, `single`, `mp3Url`, `transName`, `lyric` (optional, bySongUrl), `sourceUrl`, `scrapedAt`.

**album records (`recordType: "album"`, mode=byArtistAlbums)** — `albumId`, `name`, `coverUrl`, `trackCount`, `publishTimeMs`, `company`, `type`, `subType`, `paid`, `onSale`, `artists[]`, `artist`, `sourceUrl`.

**playlist records** — `playlistId`, `name`, `coverUrl`, `playCount`, `trackCount`, `creatorName`, `creatorId`, `creatorAvatarUrl`, `tags[]`, `description`, `subscribedCount`, `commentCount`, `shareCount`, `totalDurationMs`, `updateTimeMs`, `sourceUrl`.

**toplist records** — `toplistId`, `name`, `playCount`, `trackCount`, `subscribedCount`, `updateFrequency`, `description`, `coverUrl`, `sourceUrl`.

**error records (`recordType: "error"`)** — emitted for invalid URLs / missing songs / unknown toplists (`errorCode`, `errorMessage`, `inputValue`). Invalid inputs are never silently dropped.

Every data record carries `sourceUrl`, `scrapedAt` (UTC ISO) and `recordType`; error records carry `inputValue` in place of `sourceUrl` (the offending input, not a page URL). Null/empty fields are stripped before push.

### Filters

- `minDurationSec` / `maxDurationSec` — song length window
- `minPopularity` — 0–100 popularity floor
- `containsKeyword` — case-insensitive substring on title

### Notes

- Cover images are normalized to `https://p*.music.126.net/...` and verify HTTP 200 with `image/*` content-type from a clean shell (no Referer needed).
- `playlistOrder=new` is exposed in the schema but the upstream `/api/playlist/list` endpoint ignores the `order` param from datacenter IPs (HTTP 200, empty `playlists` for every tested category) — the actor fail-softs with a status message and 0 records. Use the default `hot` order for playlist browsing.
- Search results (mode=search) can omit `popularity` for some songs; the `minPopularity` filter drops records whose popularity is unknown rather than passing them (a record with unknown popularity cannot satisfy a popularity floor).
- Paginated modes stop examining after 500 records; if filters match nothing, the run ends cleanly with 0 records and a status message (inverted `minDurationSec > maxDurationSec` is rejected up front). The upstream `/api/artist/top/song` endpoint ignores the `offset` param (it always returns the same ~50 top songs with `more: true`), so `byArtist` dedupes by song id and stops paginating once a page adds no new songs — the output never contains duplicate records.
- Duplicate song URLs in `songUrls` (mode=bySongUrl) are deduped to a single unique record per song id.
- `maxItems` is a hard cap on ALL emitted records including `error` records.
- Auto-escalation: on HTTP 403/429 the actor lazily engages the Apify AUTO (datacenter) proxy and retries with exponential backoff.
- Memory: 1024 MB (Tier 1, plain HTTP).

# Actor input Schema

## `mode` (type: `string`):

What to fetch.

## `searchQuery` (type: `string`):

Free-text query (mode=search).

## `songUrls` (type: `array`):

music.163.com song URLs, e.g. `https://music.163.com/#/song?id=186016`.

## `artistId` (type: `integer`):

NetEase artist id, e.g. 6452 (Jay Chou). Either artistId or artistName.

## `artistName` (type: `string`):

Artist name resolved to an id via the suggestions API when artistId is empty.

## `playlistCat` (type: `string`):

Playlist genre to browse.

## `playlistOrder` (type: `string`):

Sort playlists by popularity or freshness.

## `toplistId` (type: `string`):

NetEase chart to fetch (top 100 tracks).

## `includeToplistInfo` (type: `boolean`):

Emit the toplist summary record before its tracks.

## `includeLyric` (type: `boolean`):

Attach the first 2000 chars of the LRC lyric to song records.

## `minDurationSec` (type: `integer`):

Drop songs shorter than this.

## `maxDurationSec` (type: `integer`):

Drop songs longer than this.

## `minPopularity` (type: `integer`):

Drop songs with lower popularity (0-100).

## `containsKeyword` (type: `string`):

Only keep songs whose title contains this substring (case-insensitive).

## `maxItems` (type: `integer`):

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "周杰伦",
  "songUrls": [],
  "playlistCat": "华语",
  "playlistOrder": "hot",
  "includeToplistInfo": true,
  "includeLyric": false,
  "maxItems": 30
}
```

# Actor output Schema

## `items` (type: `string`):

Dataset containing all scraped NetEase Cloud Music records (recordType: song | album | playlist | toplist | error).

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "search",
    "searchQuery": "周杰伦",
    "songUrls": [],
    "playlistCat": "华语",
    "playlistOrder": "hot",
    "includeToplistInfo": true,
    "includeLyric": false,
    "maxItems": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/netease-music-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "search",
    "searchQuery": "周杰伦",
    "songUrls": [],
    "playlistCat": "华语",
    "playlistOrder": "hot",
    "includeToplistInfo": True,
    "includeLyric": False,
    "maxItems": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/netease-music-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "search",
  "searchQuery": "周杰伦",
  "songUrls": [],
  "playlistCat": "华语",
  "playlistOrder": "hot",
  "includeToplistInfo": true,
  "includeLyric": false,
  "maxItems": 30
}' |
apify call crawlerbros/netease-music-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=crawlerbros/netease-music-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/u3hJesK0AQfEhskAW/builds/KJmMQMLc5caorQXG8/openapi.json
