# Kitapyurdu Scraper | Book Prices, ISBN & Bestsellers (`atesen-software/kitapyurdu-scraper`) Actor

Scrape Kitapyurdu.com category, publisher, author and keyword listings: book price, list price, discount, authors, publisher, ISBN, pages, stock and sales counter in TRY. Identifies itself honestly and follows robots.txt.

- **URL**: https://apify.com/atesen-software/kitapyurdu-scraper.md
- **Developed by:** [Atesen Software](https://apify.com/atesen-software) (community)
- **Categories:** E-commerce, Marketing, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 book results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Kitapyurdu Scraper: Book Prices, ISBN, Publishers & Bestsellers

Scrape **Kitapyurdu.com**, one of Turkey's largest online bookstores, without writing code. Paste a category, publisher or author page (or type keywords) and get one clean row per book: title, authors, publisher, Kitapyurdu price, publisher list price, discount, publication date, pages, language, binding and badges. Switch on **Include book details** to add the **ISBN-13**, exact rating counts, the "bought N times" sales counter, stock level, favourites and categories.

- Category, publisher, author and list pages, plus keyword search and single book pages
- Prices in TRY with the publisher's list price and the computed discount
- Authors, publisher (with link), publication date, page count, language, binding, paper type
- Best-seller sorting and newest-first sorting
- Detail mode: ISBN-13, written-review and rating counts, sales counter, stock, favourites, categories
- Up to 100 books per request, so large categories need few requests
- Polite by design: identifies itself, follows robots.txt, never solves CAPTCHAs, pay per result with a cost cap

### Quick start (about 30 seconds)

1. Open the **Input** tab and click **Start**. The prefilled input reads the *Edebiyat* (literature) category and saves 100 books.
2. Open the **Output** tab: cover, title, authors, publisher, price, list price, discount and publication date for each book.
3. Add **Include book details** to get the ISBN-13 and the sales counter, or change the URL to any category, publisher or author page.

### What you can do with it

| Goal | Settings |
| --- | --- |
| Track the best sellers of a category | A category URL, **Sort listings by** = Best sellers (last 12 months) |
| Watch new releases | **Sort listings by** = Newest publication date |
| Compare list price and Kitapyurdu price | Read `listPrice`, `price` and `discountPercent` |
| Build a catalogue of one publisher or author | The `/yayinevi/...` or `/yazar/...` page URL |
| Match books by ISBN | **Include book details**, read `isbn` |
| Estimate demand | **Include book details**, read `purchasedCount` and `favoriteCount` |
| Look up a title or an ISBN | **Search keywords**, for example `ahmet ümit` or `9789750868702` |

### Input

| Field | What it does |
| --- | --- |
| **Kitapyurdu URLs** | Category (`/kategori/kitap-edebiyat/128.html`), publisher (`/yayinevi/yapi-kredi-yayinlari/117.html`), author (`/yazar/ahmet-umit/12108.html`), list pages or a single book (`/kitap/.../767268.html`). |
| **Search keywords** | Keywords, titles, authors or ISBNs, one per line. |
| **Maximum books** | Stops after this many unique books across all URLs and keywords. Each saved book is one billable result. |
| **Maximum pages per URL** | Upper limit of listing pages read for each URL. |
| **Sort listings by** | Kitapyurdu default, best sellers (last 12 months) or newest publication date. A sort already in the URL is kept. |
| **Books per page** | 20, 25, 50, 75 or 100. 100 needs the fewest requests. |
| **Include book details** | Opens every book page for ISBN, rating counts, sales counter, stock, favourites, dimensions and categories. One extra request per book. |
| **Maximum concurrency / requests per minute** | Keep the load on the site low. Defaults: 3 and 60. |
| **Contact URL for the bot identity** | Added to the User-Agent so the site can contact the bot owner. |
| **Proxy** | On by default: Kitapyurdu refuses datacenter IP addresses (HTTP 403), so the Actor uses Apify Proxy residential IPs in Turkey. A proxy only changes the IP address; the Actor never bypasses protections. |

Example, the 300 best-selling books of the literature category with ISBN and sales counter:

```json
{
  "startUrls": [{ "url": "https://www.kitapyurdu.com/kategori/kitap-edebiyat/128.html" }],
  "sortBy": "purchased_365",
  "maxItems": 300,
  "includeProductDetails": true
}
```

Example, two keywords:

```json
{
  "searchQueries": ["ahmet ümit", "9789750868702"],
  "maxItems": 50
}
```

### Output

One dataset item per book. Real record from a test run of the literature category (listing mode):

```json
{
  "productId": "728967",
  "title": "Bahçıvan ve Ölüm",
  "url": "https://www.kitapyurdu.com/kitap/bahcivan-ve-olum/728967.html",
  "imageUrl": "https://img.kitapyurdu.com/v1/getImage/fn:12220047/wi:200/wh:bd3b98f35",
  "authors": ["Georgi Gospodinov"],
  "publisher": "METİS YAYINLARI",
  "publisherUrl": "https://www.kitapyurdu.com/yayinevi/metis-yayinlari/81.html",
  "price": 285.94,
  "listPrice": 375,
  "discountPercent": 23.7,
  "currency": "TRY",
  "publishDate": "2026-07-31",
  "pages": 208,
  "language": "TÜRKÇE",
  "coverType": "Karton Kapak",
  "paperType": null,
  "ratingStars": 4,
  "badges": ["Roman Kategorisinde 2025'in En İyi 1. Kitabı", "Eylül Görmüş Seçkisi"],
  "shippingNote": "24 Saatte Kargoda",
  "categoryId": "128",
  "page": 1,
  "position": 1,
  "scrapedAt": "2026-10-24T14:22:32.812Z"
}
```

With **Include book details** a row also contains (real values from a test run, shortened):

```json
{
  "productId": "767268",
  "title": "Roma'nın Beş Günü",
  "authors": ["Ahmet Ümit"],
  "publisher": "YAPI KREDİ YAYINLARI",
  "price": 316.27,
  "listPrice": 500,
  "discountPercent": 36.7,
  "isbn": "9789750868702",
  "availability": "InStock",
  "rating": 5,
  "ratingCount": 70,
  "reviewCount": 41,
  "purchasedCount": 8803,
  "stockText": "10+",
  "favoriteCount": 4164,
  "dimensions": "13.5 x 23 cm",
  "categories": ["Kitap > Edebiyat > Roman (Yerli)", "Kitap > Edebiyat > Polisiye"],
  "detailsFetched": true
}
```

Notes on the fields:

- `price` is the Kitapyurdu price. `listPrice` is the publisher's list price ("Liste Fiyatı"). `discountPercent` is calculated from the two and is `null` when the list price is not shown.
- `ratingStars` is the whole-star rating drawn on the listing card (1 to 5) and is `null` when no star is shown. Detail mode adds the exact `rating`, `ratingCount` and `reviewCount`.
- Missing values are `null`. A price that is not shown is never written as 0.
- Reviewer names and review texts are not collected.
- A `RUN_SUMMARY` record in the key-value store lists the pages read, blocked or unreadable pages, a `complete` flag and the stop reason.

#### Status rows

A wrong URL or an empty search does not fail the run. You get a free row with `"type": "status"`:

| `status` | Meaning |
| --- | --- |
| `not_found` | The page returned HTTP 404 or 410 |
| `unrecognized_page` | Kitapyurdu sent the Actor somewhere else (for example the home page for an unknown category), or the page did not look like a listing after three retries |
| `no_results` | The input was valid but returned no books |

Status rows are never charged. Filter them out with `type != "status"`.

### Pricing

Pay per result. The amount is on the **Pricing** tab. One book row is one result, with or without book details. Status rows are free. Set **Maximum cost per run** in the run options: the Actor stops cleanly when the budget is used and never saves rows it cannot charge for.

### Tips

- Use the 100-books-per-page setting (default) for large categories: it needs five times fewer requests than 20 per page.
- Listing mode needs one request per 100 books. Detail mode opens one extra page per book and is much slower, so use it when you need the ISBN or the sales counter.
- To follow a price over time, schedule the Actor with the same input and compare `price` between runs by `productId`.

### Limitations

- Only listing pages and book pages are read. Kitapyurdu's cart, account, checkout and image paths are never requested.
- The listing card shows whole stars only; use detail mode for the exact rating.
- Stock is shown by Kitapyurdu as text such as `10+`, not as an exact number.
- Kitapyurdu can change its pages at any time. When a page cannot be read the Actor says so in a status row and in the run's status message instead of returning empty results.
- Turkish storefront and TRY prices only.

### Is it legal to scrape Kitapyurdu?

The Actor reads only publicly visible book data, never logs in, identifies itself in the User-Agent and follows Kitapyurdu's robots.txt (it closes only admin, system, image and download paths). It never solves CAPTCHAs and never bypasses bot protection; it connects through Turkish residential IPs because the site refuses datacenter IPs, and if the site still refuses requests the run ends and says so. You are responsible for using the data in line with Kitapyurdu's terms of use, copyright rules for covers and descriptions, the Turkish personal-data law (KVKK) and other laws that apply to you. This is not legal advice.

### FAQ

**Can I get the ISBN?** Yes, with **Include book details**. The listing pages alone do not show it.

**Can I scrape a whole category?** Yes. Raise **Maximum books** and **Maximum pages per URL**. At 100 books per page a 10,000-book category is 100 requests.

**Do I need my own proxy?** No. The Actor uses Apify Proxy residential IPs in Turkey by default because Kitapyurdu answers datacenter IP addresses with HTTP 403. The cost is included in the price of a result. If the site still refuses the connection, the run ends and says so.

**Why is `ratingStars` a whole number?** It is the star icon count on the listing card. Use detail mode for the exact average.

**Can I run it from n8n, Make, Zapier or Google Sheets?** Yes. Every Apify Actor can be started through the Apify API and its integrations.

**Found a problem?** Open an issue on the Actor's Issues tab with the run ID and the URL.

# Actor input Schema

## `startUrls` (type: `array`):

Kitapyurdu category (https://www.kitapyurdu.com/kategori/kitap-edebiyat/128.html), publisher (/yayinevi/...), author (/yazar/...) or list pages. A book page URL (/kitap/.../767268.html) returns that single book. You can also use Search keywords below.

## `searchQueries` (type: `array`):

Keywords, authors, titles or ISBNs to search on Kitapyurdu, one per line (for example "ahmet ümit" or "9789750868702").

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

Stop after this many unique books have been saved across all URLs and keywords. Each saved book row is one billable result.

## `maxPagesPerUrl` (type: `integer`):

Maximum listing pages to read for each URL. A page holds up to the chosen page size of books (100 by default).

## `sortBy` (type: `string`):

Sort order for listings that do not already contain one in the URL.

## `pageSize` (type: `string`):

How many books Kitapyurdu returns per listing page. 100 needs the fewest requests.

## `includeProductDetails` (type: `boolean`):

Open every book page to add the ISBN, description, exact rating and review counts, the "bought N times" sales counter, stock level, favourites, dimensions and categories. This makes one extra request per book, so the run is slower.

## `maxConcurrency` (type: `integer`):

How many pages may be requested in parallel. Keep this low to stay polite.

## `maxRequestsPerMinute` (type: `integer`):

Upper limit on requests per minute across the whole run.

## `contactUrl` (type: `string`):

This URL is added to the User-Agent header so the site operator can contact the bot owner. Replace it with your own website or contact page if you prefer.

## `proxyConfiguration` (type: `object`):

On by default: Kitapyurdu refuses requests from datacenter IP addresses (HTTP 403), so the Actor connects through Apify Proxy residential IPs in Turkey. The Actor never solves CAPTCHAs or bypasses challenges; a proxy only changes the IP address the requests come from. Turn it off only when you run the Actor from your own Turkish connection.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.kitapyurdu.com/kategori/kitap-edebiyat/128.html"
    }
  ],
  "searchQueries": [],
  "maxItems": 100,
  "maxPagesPerUrl": 50,
  "sortBy": "default",
  "pageSize": "100",
  "includeProductDetails": false,
  "maxConcurrency": 3,
  "maxRequestsPerMinute": 60,
  "contactUrl": "https://atesensoftware.com",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "TR"
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing the scraped books

## `summary` (type: `string`):

Page counts, blocked requests and stop reason of the run

# 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 = {
    "startUrls": [
        {
            "url": "https://www.kitapyurdu.com/kategori/kitap-edebiyat/128.html"
        }
    ],
    "searchQueries": [],
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "TR"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("atesen-software/kitapyurdu-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 = {
    "startUrls": [{ "url": "https://www.kitapyurdu.com/kategori/kitap-edebiyat/128.html" }],
    "searchQueries": [],
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "TR",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("atesen-software/kitapyurdu-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 '{
  "startUrls": [
    {
      "url": "https://www.kitapyurdu.com/kategori/kitap-edebiyat/128.html"
    }
  ],
  "searchQueries": [],
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "TR"
  }
}' |
apify call atesen-software/kitapyurdu-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,atesen-software/kitapyurdu-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/Na7VQrYN4zAL5baxU/builds/k9BDz8H1C3ztabXvj/openapi.json
