# IMSLP Scraper (`crawlerbros/imslp-scraper`) Actor

Scrape IMSLP (Petrucci Music Library) - the world's largest free public-domain sheet music library with 260k+ works. Search works, browse by composer or genre category, fetch full work details, score file (PDF) URLs and recordings.

- **URL**: https://apify.com/crawlerbros/imslp-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Social media, Automation, Other
- **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

## IMSLP Scraper

Scrape **IMSLP (Petrucci Music Library)** — the world's largest free public-domain sheet music library, with 260,000+ works. Search works by title / composer / keyword, browse all works by a composer, browse genre categories (symphonies, sonatas, concertos, operas…), or fetch a work by its `IMSLP#` id — and get full work details, score file (PDF) URLs, recordings and genre/period/instrumentation metadata. HTTP-only via the public imslp.org MediaWiki API. No auth, no proxy.

### What this actor does

- **Four modes:** `search`, `browseByComposer`, `browseByCategory`, `byWorkId`
- **Full work detail:** work title, alternative title, opus number, key, movements, dedication, year of composition, year of first publication, average duration, piece style, librettist, language, instrumentation
- **Score files:** every downloadable score (mostly PDF) with its file name, description, size and direct URL
- **Recordings:** audio recordings (MP3/OGG) with direct URLs
- **Filters:** genre tags, period (piece style), instrumentation, keyword
- **Empty fields are omitted**

### Data Source

IMSLP (International Music Score Library Project / Petrucci Music Library) — https://imslp.org — a free, non-commercial library of public-domain and Creative Commons scores. This actor uses the public MediaWiki API (`api.php`; `action=query` / `action=parse`) and is not affiliated with IMSLP.

#### Score file URLs and IMSLP's bot check (verified)

The `files[].url` and `recordings[].url` values emitted by this actor are IMSLP's canonical file URLs (`https://imslp.org/images/...`). **Verified live:** for scripted clients (plain `curl`, `httpx`, even browser-impersonating `curl_cffi`), IMSLP answers these URLs with a `302` to `/friendlytest.html` — an **MTCaptcha bot check** ("IMSLP - Bot Check"), and the PDF/MP3 bytes are never served. Only a real browser that completes the captcha receives the file.

Because the bytes are **not fetchable by any scripted client**, the actor cannot rehost them into the Apify Key-Value Store; it therefore emits the canonical upstream URLs as-is for customers who consume IMSLP in a browser context, and documents this behavior instead. The URL, file size and description for every file/recording are still captured, so records are complete except for the downloadable bytes.

### Output per work

- `imslpId` — IMSLP page id (when resolvable)
- `title` — full IMSLP page title (e.g. `Piano Sonata No.4, Op.7 (Beethoven, Ludwig van)`)
- `workTitle`, `alternativeTitle` — from the work info template
- `composer` — extracted from the title
- `opus` — Opus/Catalogue number
- `key` — musical key
- `movementsHeader`, `numberOfMovements`, `incipit`
- `dedication`, `yearOfComposition`, `yearOfFirstPublication`
- `librettist`, `language`, `averageDuration`
- `pieceStyle` — Baroque / Classical / Romantic / Modern / …
- `instrumentation` — e.g. `piano`, `violin and piano`, `orchestra`
- `genreTags[]` — IMSLP genre tags (e.g. `sonatas`)
- `instrumentationTags[]` — IMSLP instrument tags (e.g. `pf`)
- `externalLinks[]` — Wikipedia / AllMusic style links
- `files[]` — scores: `fileName`, `fileDescription`, `url`, `fileSize` (capped at 30)
- `recordings[]` — audio: `fileName`, `fileDescription`, `url` (capped at 15)
- `sourceUrl` — canonical IMSLP work page
- `recordType: "work"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `browseByComposer` / `browseByCategory` / `byWorkId` |
| `searchQuery` | string | `beethoven piano sonata` | Free-text query (mode=search) |
| `composerName` | string | – | IMSLP composer category, e.g. `Beethoven, Ludwig van` (mode=browseByComposer) |
| `category` | string | – | Genre category dropdown (mode=browseByCategory) |
| `workIds` | array | – | `IMSLP#` ids or work URLs (mode=byWorkId) |
| `genre` | string | – | Genre-tag filter dropdown |
| `period` | string | – | Period / piece-style filter dropdown |
| `instrumentation` | string | – | Instrumentation filter dropdown |
| `containsKeyword` | string | – | Keep only works whose title/work title/composer contains the text |
| `maxItems` | int | `50` | Hard cap (1–1000) |

#### Example: search for piano sonatas by Beethoven

```json
{
  "mode": "search",
  "searchQuery": "beethoven piano sonata",
  "maxItems": 20
}
```

#### Example: everything by one composer

```json
{
  "mode": "browseByComposer",
  "composerName": "Chopin, Frédéric",
  "genre": "nocturnes",
  "maxItems": 50
}
```

#### Example: browse a genre category, Classical period only

```json
{
  "mode": "browseByCategory",
  "category": "Symphonies",
  "period": "Classical",
  "maxItems": 100
}
```

#### Example: lookup by IMSLP# id

```json
{
  "mode": "byWorkId",
  "workIds": ["IMSLP17208", "https://imslp.org/wiki/Piano_Sonata_No.4,_Op.7_(Beethoven,_Ludwig_van)"],
  "maxItems": 5
}
```

### Use cases

- **Musicology research** — build datasets of public-domain works by composer, genre or period
- **Sheet-music apps** — index works with direct score download URLs
- **Music education** — curate repertoire lists by instrumentation (e.g. all violin-and-piano sonatas)
- **Copyright / public-domain analysis** — track composers, years of composition and publication
- **Piano pedagogy** — filter sonatas/etudes by difficulty-adjacent metadata (opus, key, composer)

### Limitations

- **Score file bytes are not script-downloadable** — IMSLP answers scripted clients with a `302` to `/friendlytest.html` (MTCaptcha bot check); the actor emits the canonical upstream URLs as-is for consumption in a browser context. URL, file size and description are still captured for every file/recording.
- **Caps on files and recordings** — the first 30 score files and 15 recordings per work are emitted to keep payloads manageable.
- **Metadata completeness varies** — `opus`, `key`, `dedication` and similar fields depend on the work page's info template; works without them simply omit the fields. `imslpId` is emitted when resolvable.
- **Search relies on IMSLP's MediaWiki index** — the same relevance behavior as imslp.org's own search.
- **Not affiliated** — this actor is a third-party tool and is not affiliated with IMSLP.

### FAQ

**What is IMSLP?** The International Music Score Library Project (Petrucci Music Library), a volunteer-curated library of over 700,000 public-domain scores and recordings. It is the largest free sheet-music source on the internet.

**How fresh is the data?** The actor reads IMSLP pages live at run time, so data is as fresh as the source itself.

**Why are `files` and `recordings` capped?** Very large works can carry 100+ files; the actor emits the first 30 score files and 15 recordings to keep payloads manageable.

**Are the score file URLs directly downloadable?** The URLs are IMSLP's canonical file URLs. IMSLP protects automated bulk downloading with a bot check — a human visiting the file page in a browser can download directly; scripted clients may be asked to pass IMSLP's verification first. The actor itself does not bypass this.

**Which periods are supported?** Baroque, Classical, Romantic, Modern, Medieval, Renaissance, Impressionist, Early 20th century and Contemporary — matching IMSLP's piece-style values.

**Is this affiliated with IMSLP?** No — this is a third-party actor using the public IMSLP MediaWiki API.

# Actor input Schema

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

What to fetch.

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

Free-text query — work titles, composers, instruments (mode=search).

## `composerName` (type: `string`):

IMSLP composer category, e.g. `Beethoven, Ludwig van`, `Mozart, Wolfgang Amadeus`, `Chopin, Frédéric`.

## `category` (type: `string`):

IMSLP genre category to browse.

## `workIds` (type: `array`):

IMSLP# ids (e.g. `IMSLP17208`), raw page ids, or full imslp.org/wiki/... work URLs.

## `genre` (type: `string`):

Only emit works whose IMSLP genre tags match (e.g. `sonatas`, `symphonies`, `waltzes`).

## `period` (type: `string`):

Only emit works matching the IMSLP piece-style period.

## `instrumentation` (type: `string`):

Only emit works scored for the selected instrument / ensemble.

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

Only emit works whose title, work title or composer contains this text (case-insensitive).

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

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "beethoven piano sonata",
  "workIds": [],
  "maxItems": 50
}
```

# Actor output Schema

## `works` (type: `string`):

Dataset containing all scraped IMSLP works.

# 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": "beethoven piano sonata",
    "workIds": [],
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/imslp-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": "beethoven piano sonata",
    "workIds": [],
    "maxItems": 50,
}

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

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).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": "beethoven piano sonata",
  "workIds": [],
  "maxItems": 50
}' |
apify call crawlerbros/imslp-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawlerbros/imslp-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0Ac30t0n6l1X0ixj9/builds/w1hElGLil03Qq3zJN/openapi.json
