# Oikotie.fi  scraper

This scraper pulls out all real estate classified ads from Finish Oikotie service. In addition to scraping, it uses Atrophic Claude 3 Haiku to transform past and upcoming renovations into monetary renovation cost.

## Actor Statistics

- Total users: 1
- Monthly users: 1
- Runs succeeded: 0.00%
- Categories: Real estate

## Pricing

$10.00 / 1,000 results

## Input Schema

- **running\_mode** (type: string): Whether to run the scraper once with the given parameters or to run it continuously
- **condition\_type** (type: array): Type of the condition

## API example

## Oikotie.fi scraper

- **OpenAPI Version:** `3.1.1`
- **API Version:** `0.0`

This scraper pulls out all real estate classified ads from Finish Oikotie service. In addition to scraping, it uses Atrophic Claude 3 Haiku to transform past and upcoming renovations into monetary renovation cost.

### Servers

- **URL:** `https://api.apify.com/v2`

### Operations

#### Executes an Actor, waits for its completion, and returns Actor's dataset items in response.

- **Method:** `POST`
- **Path:** `/acts/prebuy~oikotie-fi-scraper/run-sync-get-dataset-items`
- **Tags:** Run Actor

##### Request Body

###### Content-Type: application/json

- **`running_mode` (required)**

  `string`, possible values: `"sample", "full"`, default: `"sample"` — Whether to run the scraper once with the given parameters or to run it continuously

- **`condition_type`**

  `array` — Type of the condition

  **Items:**

  `string`, possible values: `"2", "4", "8", "32"`

**Example:**

```
{
  "running_mode": "sample",
  "condition_type": [
    "2"
  ]
}
```

##### Responses

###### Status: 200 OK

#### Executes an Actor and returns information about the initiated run in response.

- **Method:** `POST`
- **Path:** `/acts/prebuy~oikotie-fi-scraper/runs`
- **Tags:** Run Actor

##### Request Body

###### Content-Type: application/json

- **`running_mode` (required)**

  `string`, possible values: `"sample", "full"`, default: `"sample"` — Whether to run the scraper once with the given parameters or to run it continuously

- **`condition_type`**

  `array` — Type of the condition

  **Items:**

  `string`, possible values: `"2", "4", "8", "32"`

**Example:**

```
{
  "running_mode": "sample",
  "condition_type": [
    "2"
  ]
}
```

##### Responses

###### Status: 200 OK

\####### Content-Type: application/json

- **`data`**

  `object`

  - **`actId`**

    `string`

  - **`buildId`**

    `string`

  - **`buildNumber`**

    `string`

  - **`containerUrl`**

    `string`

  - **`defaultDatasetId`**

    `string`

  - **`defaultKeyValueStoreId`**

    `string`

  - **`defaultRequestQueueId`**

    `string`

  - **`finishedAt`**

    `string`, format: `date-time`

  - **`id`**

    `string`

  - **`meta`**

    `object`

    - **`origin`**

      `string`

    - **`userAgent`**

      `string`

  - **`options`**

    `object`

    - **`build`**

      `string`

    - **`diskMbytes`**

      `integer`

    - **`memoryMbytes`**

      `integer`

    - **`timeoutSecs`**

      `integer`

  - **`startedAt`**

    `string`, format: `date-time`

  - **`stats`**

    `object`

    - **`computeUnits`**

      `integer`

    - **`inputBodyLen`**

      `integer`

    - **`rebootCount`**

      `integer`

    - **`restartCount`**

      `integer`

    - **`resurrectCount`**

      `integer`

  - **`status`**

    `string`

  - **`usage`**

    `object`

    - **`ACTOR_COMPUTE_UNITS`**

      `integer`

    - **`DATA_TRANSFER_EXTERNAL_GBYTES`**

      `integer`

    - **`DATA_TRANSFER_INTERNAL_GBYTES`**

      `integer`

    - **`DATASET_READS`**

      `integer`

    - **`DATASET_WRITES`**

      `integer`

    - **`KEY_VALUE_STORE_LISTS`**

      `integer`

    - **`KEY_VALUE_STORE_READS`**

      `integer`

    - **`KEY_VALUE_STORE_WRITES`**

      `integer`

    - **`PROXY_RESIDENTIAL_TRANSFER_GBYTES`**

      `integer`

    - **`PROXY_SERPS`**

      `integer`

    - **`REQUEST_QUEUE_READS`**

      `integer`

    - **`REQUEST_QUEUE_WRITES`**

      `integer`

  - **`usageTotalUsd`**

    `number`

  - **`usageUsd`**

    `object`

    - **`ACTOR_COMPUTE_UNITS`**

      `integer`

    - **`DATA_TRANSFER_EXTERNAL_GBYTES`**

      `integer`

    - **`DATA_TRANSFER_INTERNAL_GBYTES`**

      `integer`

    - **`DATASET_READS`**

      `integer`

    - **`DATASET_WRITES`**

      `integer`

    - **`KEY_VALUE_STORE_LISTS`**

      `integer`

    - **`KEY_VALUE_STORE_READS`**

      `integer`

    - **`KEY_VALUE_STORE_WRITES`**

      `number`

    - **`PROXY_RESIDENTIAL_TRANSFER_GBYTES`**

      `integer`

    - **`PROXY_SERPS`**

      `integer`

    - **`REQUEST_QUEUE_READS`**

      `integer`

    - **`REQUEST_QUEUE_WRITES`**

      `integer`

  - **`userId`**

    `string`

**Example:**

```
{
  "data": {
    "id": "",
    "actId": "",
    "userId": "",
    "startedAt": "2025-01-08T00:00:00.000Z",
    "finishedAt": "2025-01-08T00:00:00.000Z",
    "status": "READY",
    "meta": {
      "origin": "API",
      "userAgent": ""
    },
    "stats": {
      "inputBodyLen": 2000,
      "rebootCount": 0,
      "restartCount": 0,
      "resurrectCount": 0,
      "computeUnits": 0
    },
    "options": {
      "build": "latest",
      "timeoutSecs": 300,
      "memoryMbytes": 1024,
      "diskMbytes": 2048
    },
    "buildId": "",
    "defaultKeyValueStoreId": "",
    "defaultDatasetId": "",
    "defaultRequestQueueId": "",
    "buildNumber": "1.0.0",
    "containerUrl": "",
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0,
      "DATASET_READS": 0,
      "DATASET_WRITES": 0,
      "KEY_VALUE_STORE_READS": 0,
      "KEY_VALUE_STORE_WRITES": 1,
      "KEY_VALUE_STORE_LISTS": 0,
      "REQUEST_QUEUE_READS": 0,
      "REQUEST_QUEUE_WRITES": 0,
      "DATA_TRANSFER_INTERNAL_GBYTES": 0,
      "DATA_TRANSFER_EXTERNAL_GBYTES": 0,
      "PROXY_RESIDENTIAL_TRANSFER_GBYTES": 0,
      "PROXY_SERPS": 0
    },
    "usageTotalUsd": 0.00005,
    "usageUsd": {
      "ACTOR_COMPUTE_UNITS": 0,
      "DATASET_READS": 0,
      "DATASET_WRITES": 0,
      "KEY_VALUE_STORE_READS": 0,
      "KEY_VALUE_STORE_WRITES": 0.00005,
      "KEY_VALUE_STORE_LISTS": 0,
      "REQUEST_QUEUE_READS": 0,
      "REQUEST_QUEUE_WRITES": 0,
      "DATA_TRANSFER_INTERNAL_GBYTES": 0,
      "DATA_TRANSFER_EXTERNAL_GBYTES": 0,
      "PROXY_RESIDENTIAL_TRANSFER_GBYTES": 0,
      "PROXY_SERPS": 0
    }
  }
}
```

#### Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.

- **Method:** `POST`
- **Path:** `/acts/prebuy~oikotie-fi-scraper/run-sync`
- **Tags:** Run Actor

##### Request Body

###### Content-Type: application/json

- **`running_mode` (required)**

  `string`, possible values: `"sample", "full"`, default: `"sample"` — Whether to run the scraper once with the given parameters or to run it continuously

- **`condition_type`**

  `array` — Type of the condition

  **Items:**

  `string`, possible values: `"2", "4", "8", "32"`

**Example:**

```
{
  "running_mode": "sample",
  "condition_type": [
    "2"
  ]
}
```

##### Responses

###### Status: 200 OK

### Schemas

#### inputSchema

- **Type:**`object`

* **`running_mode` (required)**

  `string`, possible values: `"sample", "full"`, default: `"sample"` — Whether to run the scraper once with the given parameters or to run it continuously

* **`condition_type`**

  `array` — Type of the condition

  **Items:**

  `string`, possible values: `"2", "4", "8", "32"`

**Example:**

```
{
  "running_mode": "sample",
  "condition_type": [
    "2"
  ]
}
```

#### runsResponseSchema

- **Type:**`object`

* **`data`**

  `object`

  - **`actId`**

    `string`

  - **`buildId`**

    `string`

  - **`buildNumber`**

    `string`

  - **`containerUrl`**

    `string`

  - **`defaultDatasetId`**

    `string`

  - **`defaultKeyValueStoreId`**

    `string`

  - **`defaultRequestQueueId`**

    `string`

  - **`finishedAt`**

    `string`, format: `date-time`

  - **`id`**

    `string`

  - **`meta`**

    `object`

    - **`origin`**

      `string`

    - **`userAgent`**

      `string`

  - **`options`**

    `object`

    - **`build`**

      `string`

    - **`diskMbytes`**

      `integer`

    - **`memoryMbytes`**

      `integer`

    - **`timeoutSecs`**

      `integer`

  - **`startedAt`**

    `string`, format: `date-time`

  - **`stats`**

    `object`

    - **`computeUnits`**

      `integer`

    - **`inputBodyLen`**

      `integer`

    - **`rebootCount`**

      `integer`

    - **`restartCount`**

      `integer`

    - **`resurrectCount`**

      `integer`

  - **`status`**

    `string`

  - **`usage`**

    `object`

    - **`ACTOR_COMPUTE_UNITS`**

      `integer`

    - **`DATA_TRANSFER_EXTERNAL_GBYTES`**

      `integer`

    - **`DATA_TRANSFER_INTERNAL_GBYTES`**

      `integer`

    - **`DATASET_READS`**

      `integer`

    - **`DATASET_WRITES`**

      `integer`

    - **`KEY_VALUE_STORE_LISTS`**

      `integer`

    - **`KEY_VALUE_STORE_READS`**

      `integer`

    - **`KEY_VALUE_STORE_WRITES`**

      `integer`

    - **`PROXY_RESIDENTIAL_TRANSFER_GBYTES`**

      `integer`

    - **`PROXY_SERPS`**

      `integer`

    - **`REQUEST_QUEUE_READS`**

      `integer`

    - **`REQUEST_QUEUE_WRITES`**

      `integer`

  - **`usageTotalUsd`**

    `number`

  - **`usageUsd`**

    `object`

    - **`ACTOR_COMPUTE_UNITS`**

      `integer`

    - **`DATA_TRANSFER_EXTERNAL_GBYTES`**

      `integer`

    - **`DATA_TRANSFER_INTERNAL_GBYTES`**

      `integer`

    - **`DATASET_READS`**

      `integer`

    - **`DATASET_WRITES`**

      `integer`

    - **`KEY_VALUE_STORE_LISTS`**

      `integer`

    - **`KEY_VALUE_STORE_READS`**

      `integer`

    - **`KEY_VALUE_STORE_WRITES`**

      `number`

    - **`PROXY_RESIDENTIAL_TRANSFER_GBYTES`**

      `integer`

    - **`PROXY_SERPS`**

      `integer`

    - **`REQUEST_QUEUE_READS`**

      `integer`

    - **`REQUEST_QUEUE_WRITES`**

      `integer`

  - **`userId`**

    `string`

**Example:**

```
{
  "data": {
    "id": "",
    "actId": "",
    "userId": "",
    "startedAt": "2025-01-08T00:00:00.000Z",
    "finishedAt": "2025-01-08T00:00:00.000Z",
    "status": "READY",
    "meta": {
      "origin": "API",
      "userAgent": ""
    },
    "stats": {
      "inputBodyLen": 2000,
      "rebootCount": 0,
      "restartCount": 0,
      "resurrectCount": 0,
      "computeUnits": 0
    },
    "options": {
      "build": "latest",
      "timeoutSecs": 300,
      "memoryMbytes": 1024,
      "diskMbytes": 2048
    },
    "buildId": "",
    "defaultKeyValueStoreId": "",
    "defaultDatasetId": "",
    "defaultRequestQueueId": "",
    "buildNumber": "1.0.0",
    "containerUrl": "",
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0,
      "DATASET_READS": 0,
      "DATASET_WRITES": 0,
      "KEY_VALUE_STORE_READS": 0,
      "KEY_VALUE_STORE_WRITES": 1,
      "KEY_VALUE_STORE_LISTS": 0,
      "REQUEST_QUEUE_READS": 0,
      "REQUEST_QUEUE_WRITES": 0,
      "DATA_TRANSFER_INTERNAL_GBYTES": 0,
      "DATA_TRANSFER_EXTERNAL_GBYTES": 0,
      "PROXY_RESIDENTIAL_TRANSFER_GBYTES": 0,
      "PROXY_SERPS": 0
    },
    "usageTotalUsd": 0.00005,
    "usageUsd": {
      "ACTOR_COMPUTE_UNITS": 0,
      "DATASET_READS": 0,
      "DATASET_WRITES": 0,
      "KEY_VALUE_STORE_READS": 0,
      "KEY_VALUE_STORE_WRITES": 0.00005,
      "KEY_VALUE_STORE_LISTS": 0,
      "REQUEST_QUEUE_READS": 0,
      "REQUEST_QUEUE_WRITES": 0,
      "DATA_TRANSFER_INTERNAL_GBYTES": 0,
      "DATA_TRANSFER_EXTERNAL_GBYTES": 0,
      "PROXY_RESIDENTIAL_TRANSFER_GBYTES": 0,
      "PROXY_SERPS": 0
    }
  }
}
```

## 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 = {
    "condition_type": [
        "2",
        "4",
        "8",
        "32"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("prebuy/oikotie-fi-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 = { "condition_type": [
        "2",
        "4",
        "8",
        "32",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("prebuy/oikotie-fi-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 '{
  "condition_type": [
    "2",
    "4",
    "8",
    "32"
  ]
}' |
apify call prebuy/oikotie-fi-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?actors=prebuy/oikotie-fi-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

### Application Settings

General settings for the application behavior:

- **IS\_DEBUGGING**: Set to `True` for debugging mode, which provides more verbose output helpful in development. Default is `False`.
- **WORKER\_NUM**: The number of worker processes for the application. Example: `5`
- **IS\_UPDATE\_OLD\_AI\_RESULT**: Controls whether to update old AI results. Default is `True`.
- **FIELDS\_TO\_CLASSIFY\_STRING**: Specifies the fields in the input data that need to be classified. Example: `"upcomingRenovations,doneRenovation"`

### Data Flow

The application processes data in the following order:

1. Empty oikotie-deals key-value store created on Apify.
2. Prepare api\_headers to access the Oikotie API. Each thread has its own api\_headers.
3. Prepare deal generator to scrape with set of filters. (Extracted from the Oikotie API)
4. Extract basic information from each deal.
5. Apply multithreading to extract more detailed information from each deal for each batch of deals (24 deals per page).
6. Classify the extracted data. Only the fields specified in the `FIELDS_TO_CLASSIFY_STRING` setting are included in the classification.
   Current input data format: Hardcoded in the `classify_deal_by_anthropic` function.
   '''
   Past renovations in Finnish language is here: {doneRenovations}
   Future planned renovations in Finnish language is here: {upcomingRenovations}
   '''
7. Save the classified data with deal detail to the oikotie-deals key-value store.
   Current output data format:
   `      {
            "cardId": 21226538,
            "updatedAt": "2024-05-08T15:15:52.848291",
            "url": "https://asunnot.oikotie.fi/myytavat-asunnot/lahti/21226538",
            "roomConfiguration": "1h+k",
            "buildYear": 1968,
            "price": 29900.0,
            "size": 42.0,
            "description": "42 m2 keittiöllinen yksiö Lahden Nastolan Rakokiven palveluiden läheltä",
            "rooms": 1,
            "city": "Lahti",
            "country": "Suomi",
            "postalCode": "15550",
            "upcomingRenovations": "V. KPH silikonien tarkistus ja vaihto, radon mittaus, palovaroittimien uusinta, v. -25 IV-kanavien nuohous, v. -28 Mahdollinen rappukäyttävien lattiapintojen uusiminen ja seinien maalaus.",
            "doneRenovations": "V. -02 julkisivuremontti ja käyttövesiputket, v. -04 lämmönvaihdin ja kaapeli tv, v. -07 kylmäkellarin automatiikka, v. -08 jäteastiasto ja saunaremontti, v. -11 parkkitolppien ja kellojen uusiminen+lisätolppa sekä saunan lauteiden ja seinien korjaus, v. -16 lukituksen uusiminen, v. -19 rappukäytävien, autotallien ja pyörävarastojen ovien uusiminen, v. -23 vesikaton maalaus ja viemärisukitus",
            "conditionType": "Tyydyttävä",
            "housingType": "Omistus",
            "landOwnership": "Oma",
            "debtFreePriceText": "29 900 €",
            "sellingPriceText": "25 491,39 €",
            "pricePerSquareMeterText": "711,90 € / m2",
            "debtShareText": "4 408,61 €",
            "treatmentFeeText": "168 € / kk",
            "capitalConsidersationText": "63 € / kk",
            "totalCompanyConsidersationText": "231 € / kk",
            "waterFeeText": null,
            "otherCostsText": "Taloyhtiön hallitukselle on annettu valtuutus periä (tai olla perimättä) ylimääräisiä vastikkeita yhtiön taloudellisen aseman tai maksuvalmiuden sitä vaatiessa\n\nLisätietoja maksuista: Ovilainan rahoitusvastike 35,70 €/kk (yksi erä jäljellä), Kylmävesi 5 €/m3, lämminvesi 9 €/m3, autotallivuokra 25 €/kk. Vapaat vuorot ja paikat varmistettava isännöinnistä.",
            "anthropic_model": "claude-3-haiku-20240307",
            "anthropic_system_prompt": "Following text contains list of completed (done) renovations and planned future (upcoming) renovations of a department flat. Please evaluate the list and make conclusions if the Pipes are in original state or renovated. Output only one of the two options: \"1. Pipes are renovated\" or \"2. Pipes are in original condition\" or \"3. Pipe condition is unclear or they are partially renovated\". Texts are in Finnish language. Do not return any explanations, only the conclusion from list of three options. For example if the upcoming renovations contains text \"Linjasaneeraus alkanee alustavan arvion mukaan loppuvuonna\" then correct answer is \"2. Pipes are in original condition\"",
            "anthropic_classification_result": null,
            "anthropic_classification_at": "2024-05-08 15:15:52.848291"
            }
        `
