Open Library Scraper: Books, Authors & Editions avatar

Open Library Scraper: Books, Authors & Editions

Pricing

from $0.37 / 1,000 book scrapeds

Go to Apify Store
Open Library Scraper: Books, Authors & Editions

Open Library Scraper: Books, Authors & Editions

Scrape Open Library by search term, ISBN or subject: title, authors, ISBNs, publishers, first publication year, subjects, cover images and edition lists. No key.

Pricing

from $0.37 / 1,000 book scrapeds

Rating

0.0

(0)

Developer

Arman Hossain

Arman Hossain

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

Open Library Scraper: Book records by search, ISBN or subject, authors, every ISBN, publishers, first publish year and editions

Turns a search term, an ISBN or a subject heading into structured book records: title, authors, every ISBN across every printing, publishers, first publication year, subjects, languages, cover image and edition list.

Open Library is the Internet Archive's open bibliographic database. This Actor reads it directly, so there is no browser, no proxy, no credentials and no account.

Agent skill: SKILL.md

https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/openlibrary-books-scraper.md

What you get

FieldWhat it holds
query, queryTypeWhich input produced this record, and whether it came from a search, an ISBN or a subject
olKey, urlOpen Library work key (/works/OL893516W) and the human-readable page
title, subtitleWork title and subtitle
authors, authorKeysAuthor names and their Open Library author keys
isbn10, isbn13Every ISBN Open Library knows for the work, split by length
publishersEvery publisher across all editions
firstPublishYearYear of the earliest known edition
numberOfPagesMedian page count across editions
subjectsSubject headings, capped at 50
languages3-letter MARC language codes across editions
coverUrlLarge cover image URL, or null when no cover is on file
editionCountHow many printings Open Library has catalogued
ratingsAverage, ratingsCountCommunity rating, null when nobody has rated it
editionsPer-printing detail when includeEditions is on. null when you did not ask for editions, and also when the edition lookup itself failed. Never a fabricated empty list
scrapedAtRun timestamp

RUN_SUMMARY in the key-value store holds the counts and, more usefully, everything that did not happen: failures (queries that errored), targetsWithoutMatches (queries that ran and matched nothing), targetsSkipped (queries never run because maxResults was already spent), rejectedInputs (entries that could not be turned into a query at all) and editionFailures (books delivered with editions: null because that lookup failed). A missing book is always traceable to one of those lines.

Use cases

  • Catalogue enrichment. Turn a spreadsheet of ISBNs into full records with covers and subjects.
  • Reading-list and library apps. Search by title or author and store the result as-is.
  • Publishing market research. Count editions and publishers per subject or per year.
  • AI agents and RAG. A permissively licensed book-metadata layer with no key to rotate.
  • Deduplication. Resolve any ISBN to its parent work so different printings collapse to one row.

Quick start

One search, twenty books:

{
"searchQueries": ["dune"]
}

ISBNs from a catalogue, with every printing attached:

{
"isbns": ["9780441013593", "0-441-01359-0"],
"includeEditions": true,
"maxEditionsPerBook": 25
}

Subject sweep for market research:

{
"subjects": ["science fiction", "cryptography"],
"searchQueries": ["author:le guin"],
"maxResults": 200
}

Input

FieldTypeDefaultNotes
searchQueriesarray[]Free-text searches. Open Library's field syntax works too: author:le guin, title:dune, publisher:penguin.
isbnsarray[]ISBN-10 or ISBN-13. Hyphens and spaces are stripped. Resolves to the parent work, so you get all printings, not just the one you asked for.
subjectsarray[]Subject headings. Multi-word values are quoted automatically.
includeEditionsbooleanfalseAttach per-printing detail. Costs one extra request per book.
maxEditionsPerBookinteger10Cap on attached editions, 1 to 100. Only read when includeEditions is on. It bounds the edition list inside a row, not the number of rows.
maxResultsinteger20Hard ceiling on the books saved by the whole run, 1 to 1000, across every query, ISBN and subject together. Three queries at maxResults: 20 save 20 books in total, not 60.

At least one of searchQueries, isbns or subjects must be non-empty. All three can be used together: results are merged and de-duplicated on olKey, so a book found by two different queries is saved once.

maxResults is shared evenly between your targets and whatever one target leaves unused passes to the ones after it, so three queries at maxResults: 30 take 10 each, and if the first matches only 2 books the remaining 28 are available to the other two. Values outside 1 to 1000 are rejected before anything is fetched, rather than quietly rounded into a different run than the one you asked for.

Output example

{
"query": "dune",
"queryType": "search",
"olKey": "/works/OL893516W",
"url": "https://openlibrary.org/works/OL893516W",
"title": "Children of Dune",
"subtitle": null,
"authors": ["Frank Herbert"],
"authorKeys": ["OL79034A"],
"isbn10": ["0425071790", "0441015905", "0575074906"],
"isbn13": ["9782266027229", "9780441104024", "9780425079027"],
"publishers": ["Orion Publishing Group, Limited", "Pocket", "Berkley Publishing"],
"firstPublishYear": 1976,
"numberOfPages": 504,
"subjects": ["Dune (Imaginary place)", "Fiction", "Fiction in English", "Science Fiction"],
"languages": ["pol", "chi", "ger", "eng", "spa", "dut", "fre", "por"],
"coverUrl": "https://covers.openlibrary.org/b/id/6976407-L.jpg",
"editionCount": 77,
"ratingsAverage": 3.96,
"ratingsCount": 47,
"editions": [
{
"editionKey": "/books/OL47362500M",
"title": "Dzieci Diuny",
"publishDate": "Apr 14, 2020",
"publishers": ["Rebis"],
"isbn10": ["8381880475"],
"isbn13": ["9788381880473"],
"numberOfPages": 528,
"physicalFormat": "hardcover",
"languages": ["pol"]
}
],
"scrapedAt": "2026-08-06T12:00:00.000Z"
}

Works versus editions

Open Library models a book at two levels, and the difference matters when you join data:

LevelKey looks likeWhat it is
Work/works/OL893516WThe abstract book. One row per title, regardless of printing.
Edition/books/OL47362500MOne physical or digital printing, with its own ISBN, publisher and page count.

Every dataset item is a work. isbn10, isbn13, publishers and languages are unions across all its editions, which is why a single record can carry hundreds of ISBNs. Set includeEditions: true when you need each printing separated out.

API example

curl -X POST "https://api.apify.com/v2/acts/arman-bd~openlibrary-books-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"isbns": ["9780441013593"],
"includeEditions": true,
"maxEditionsPerBook": 5
}'

JavaScript example

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('arman-bd/openlibrary-books-scraper').call({
searchQueries: ['dune'],
subjects: ['science fiction'],
maxResults: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const book of items) console.log(`${book.title} - ${book.authors.join(', ')} (${book.firstPublishYear})`);

Notes

  • One bad query won't kill the run. A failed query is recorded in RUN_SUMMARY.failures and the Actor moves on. It only errors out if every query failed and nothing was saved, because a run that saved nothing must never look like a run that found nothing.
  • A query that matches nothing is not an error, but it is not silence either: you get zero rows and the query is named in RUN_SUMMARY.targetsWithoutMatches.
  • maxResults is the most rows a run can save, so it is also the most a run can cost. Rows are only charged when they are saved: duplicates, unusable inputs and failed queries are not.
  • The fields you get back are the fields the Actor asks for. The default projection is thin, so this Actor requests an explicit 15-column field list.
  • Subjects are capped at 50 per book. Popular works carry hundreds of near-duplicate headings, and the first 50 are the useful ones.
  • Public data only. Open Library's bibliographic data is published under CC0. Covers have their own terms, so this Actor returns cover URLs rather than image bytes.

FAQ

Do I need an Open Library account or key? No. You supply no credentials.

Why does one record have 248 ISBNs? Because it is a work, not an edition. Those are the ISBNs of all 160 printings. Turn on includeEditions to see which ISBN belongs to which printing.

Can I search by author? Yes, put author:le guin in searchQueries. The full Open Library search syntax is passed through unchanged.

Is maxResults a run total or a per-query cap? A run total. Five queries at maxResults: 100 save 100 books between them, not 500. Raise it when you want more.

What happens if I send maxResults: 0 or -5? The run stops with an error naming the field, before anything is fetched or charged. There is no "unlimited" value: an out-of-range cap used to be quietly rewritten into a different one, which meant a bill nobody agreed to.

Why did a query return nothing when maxResults was still high enough? Check RUN_SUMMARY. targetsWithoutMatches means it ran and matched nothing; targetsSkipped means the run total was already spent before that query was reached; failures means it errored.

Why is ratingsAverage null? Most works have no community ratings. Rather than reporting a fake 0.0, this Actor returns null when ratingsCount is zero.

Can I plug it into something else? Yes. Apify API, the client libraries, webhooks, scheduled runs, dataset exports to JSON, CSV or Excel, or MCP. The output is structured JSON.