# Africa OpportuScan (`maryse_gahou/africa-opportuscan`) Actor

Scrapes scholarship, grant, and academic opportunity listings from configurable sources and outputs structured, matchable data for African students.

- **URL**: https://apify.com/maryse_gahou/africa-opportuscan.md
- **Developed by:** [Maryse GAHOU](https://apify.com/maryse_gahou) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.05 / 1,000 opportunity founds

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

## Africa OpportuScan Actor

Apify Actor that collects scholarships, grants, and academic opportunities from configurable public sources. The Actor writes opportunity records to a Dataset that the Africa OpportuScan dashboard can consume.

### Team 3M

Maryse, Mélène, and Mevic.

### How it works

The `sources` input describes the pages to visit and their CSS selectors. For each matching card, the Actor extracts the title, link, deadline when available, and collection timestamp. Source URLs must use HTTP or HTTPS.

### Important files

- `.actor/actor.json`: Actor metadata.
- `.actor/input_schema.json`: input contract and default values.
- `.actor/output_schema.json`: Dataset output link definition.
- `.actor/pay_per_event.json`: Pay-per-event configuration.
- `src/main.js`: CheerioCrawler scraping logic.

### Example input

```json
{
  "sources": [
    {
      "sourceName": "Example source",
      "url": "https://example.org/scholarships",
      "listItemSelector": "article",
      "titleSelector": "h2 a",
      "linkSelector": "h2 a",
      "deadlineSelector": ".deadline"
    }
  ],
  "maxItemsPerSource": 30
}
```

### Example output

```json
{
  "source": "Example source",
  "title": "Example scholarship",
  "link": "https://example.org/scholarships/example",
  "deadline": "2026-12-15",
  "deadlineText": "15 December 2026",
  "scrapedAt": "2026-09-25T03:00:00.000Z"
}
```

### Run locally

```bash
npm install
APIFY_LOCAL_STORAGE_DIR=./storage npm start
```

Results are written to `storage/datasets/default/`.

### Publication and monetization

1. Log in with `apify login`.
2. Push the Actor with `apify push`.
3. Verify the schemas in the Apify Console.
4. Enable the **Pay per event** pricing model.
5. Use `apify-default-dataset-item` as the primary event for default Dataset items.
6. Publish the Actor on the Apify Store.
7. Add the public Store URL to the submission documentation.

The Pay-per-event file is a configuration reference. The pricing must also be enabled in the Apify Console.

### Transparency and limitations

The Actor collects public pages and must not be used to bypass authentication, paywalls, robots.txt restrictions, or a site's terms of use. Extracted data never replaces the official page. Fields that cannot be determined remain null and must be verified manually.

# Actor input Schema

## `sources` (type: `array`):

One entry per site. sourceName, url and CSS selectors (listItemSelector = one card/row per opportunity, titleSelector, linkSelector, deadlineSelector optional).

## `maxItemsPerSource` (type: `integer`):

Safety cap so a single source can't exhaust the run.

## Actor input object example

```json
{
  "sources": [
    {
      "sourceName": "GreatYOP (bourses, francophone)",
      "url": "https://greatyop.com/category/bourses/",
      "listItemSelector": "article",
      "titleSelector": "h2.entry-title a",
      "linkSelector": "h2.entry-title a",
      "deadlineSelector": ".gy-pcard-bottom p"
    },
    {
      "sourceName": "OYA Opportunities",
      "url": "https://oyaop.com/opportunities/scholarships-and-fellowships",
      "listItemSelector": "article.single_archive_detail",
      "titleSelector": "h5.single_archive_title",
      "linkSelector": "a[href*='/opportunity/']",
      "deadlineSelector": ".single_archive_deadline"
    },
    {
      "sourceName": "Opportunities For Africans",
      "url": "https://www.opportunitiesforafricans.com/category/scholarships/",
      "listItemSelector": "article.post",
      "titleSelector": "h2.penci-entry-title a",
      "linkSelector": "h2.penci-entry-title a",
      "deadlineSelector": ""
    },
    {
      "sourceName": "Opportunity Desk",
      "url": "https://opportunitydesk.org/category/fellowships-and-scholarships/",
      "listItemSelector": "article",
      "titleSelector": "h2.post-title a",
      "linkSelector": "h2.post-title a",
      "deadlineSelector": ""
    },
    {
      "sourceName": "Scholarship Corner",
      "url": "https://scholarshipscorner.website/category/scholarships/",
      "listItemSelector": "article.elementor-post",
      "titleSelector": ".elementor-post__title a",
      "linkSelector": ".elementor-post__title a",
      "deadlineSelector": ""
    }
  ],
  "maxItemsPerSource": 30
}
```

# Actor output Schema

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

Public opportunity records scraped during this 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 = {
    "sources": [
        {
            "sourceName": "GreatYOP (bourses, francophone)",
            "url": "https://greatyop.com/category/bourses/",
            "listItemSelector": "article",
            "titleSelector": "h2.entry-title a",
            "linkSelector": "h2.entry-title a",
            "deadlineSelector": ".gy-pcard-bottom p"
        },
        {
            "sourceName": "OYA Opportunities",
            "url": "https://oyaop.com/opportunities/scholarships-and-fellowships",
            "listItemSelector": "article.single_archive_detail",
            "titleSelector": "h5.single_archive_title",
            "linkSelector": "a[href*='/opportunity/']",
            "deadlineSelector": ".single_archive_deadline"
        },
        {
            "sourceName": "Opportunities For Africans",
            "url": "https://www.opportunitiesforafricans.com/category/scholarships/",
            "listItemSelector": "article.post",
            "titleSelector": "h2.penci-entry-title a",
            "linkSelector": "h2.penci-entry-title a",
            "deadlineSelector": ""
        },
        {
            "sourceName": "Opportunity Desk",
            "url": "https://opportunitydesk.org/category/fellowships-and-scholarships/",
            "listItemSelector": "article",
            "titleSelector": "h2.post-title a",
            "linkSelector": "h2.post-title a",
            "deadlineSelector": ""
        },
        {
            "sourceName": "Scholarship Corner",
            "url": "https://scholarshipscorner.website/category/scholarships/",
            "listItemSelector": "article.elementor-post",
            "titleSelector": ".elementor-post__title a",
            "linkSelector": ".elementor-post__title a",
            "deadlineSelector": ""
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maryse_gahou/africa-opportuscan").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 = { "sources": [
        {
            "sourceName": "GreatYOP (bourses, francophone)",
            "url": "https://greatyop.com/category/bourses/",
            "listItemSelector": "article",
            "titleSelector": "h2.entry-title a",
            "linkSelector": "h2.entry-title a",
            "deadlineSelector": ".gy-pcard-bottom p",
        },
        {
            "sourceName": "OYA Opportunities",
            "url": "https://oyaop.com/opportunities/scholarships-and-fellowships",
            "listItemSelector": "article.single_archive_detail",
            "titleSelector": "h5.single_archive_title",
            "linkSelector": "a[href*='/opportunity/']",
            "deadlineSelector": ".single_archive_deadline",
        },
        {
            "sourceName": "Opportunities For Africans",
            "url": "https://www.opportunitiesforafricans.com/category/scholarships/",
            "listItemSelector": "article.post",
            "titleSelector": "h2.penci-entry-title a",
            "linkSelector": "h2.penci-entry-title a",
            "deadlineSelector": "",
        },
        {
            "sourceName": "Opportunity Desk",
            "url": "https://opportunitydesk.org/category/fellowships-and-scholarships/",
            "listItemSelector": "article",
            "titleSelector": "h2.post-title a",
            "linkSelector": "h2.post-title a",
            "deadlineSelector": "",
        },
        {
            "sourceName": "Scholarship Corner",
            "url": "https://scholarshipscorner.website/category/scholarships/",
            "listItemSelector": "article.elementor-post",
            "titleSelector": ".elementor-post__title a",
            "linkSelector": ".elementor-post__title a",
            "deadlineSelector": "",
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("maryse_gahou/africa-opportuscan").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 '{
  "sources": [
    {
      "sourceName": "GreatYOP (bourses, francophone)",
      "url": "https://greatyop.com/category/bourses/",
      "listItemSelector": "article",
      "titleSelector": "h2.entry-title a",
      "linkSelector": "h2.entry-title a",
      "deadlineSelector": ".gy-pcard-bottom p"
    },
    {
      "sourceName": "OYA Opportunities",
      "url": "https://oyaop.com/opportunities/scholarships-and-fellowships",
      "listItemSelector": "article.single_archive_detail",
      "titleSelector": "h5.single_archive_title",
      "linkSelector": "a[href*='\''/opportunity/'\'']",
      "deadlineSelector": ".single_archive_deadline"
    },
    {
      "sourceName": "Opportunities For Africans",
      "url": "https://www.opportunitiesforafricans.com/category/scholarships/",
      "listItemSelector": "article.post",
      "titleSelector": "h2.penci-entry-title a",
      "linkSelector": "h2.penci-entry-title a",
      "deadlineSelector": ""
    },
    {
      "sourceName": "Opportunity Desk",
      "url": "https://opportunitydesk.org/category/fellowships-and-scholarships/",
      "listItemSelector": "article",
      "titleSelector": "h2.post-title a",
      "linkSelector": "h2.post-title a",
      "deadlineSelector": ""
    },
    {
      "sourceName": "Scholarship Corner",
      "url": "https://scholarshipscorner.website/category/scholarships/",
      "listItemSelector": "article.elementor-post",
      "titleSelector": ".elementor-post__title a",
      "linkSelector": ".elementor-post__title a",
      "deadlineSelector": ""
    }
  ]
}' |
apify call maryse_gahou/africa-opportuscan --silent --output-dataset

```

## MCP server setup

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

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/v2K5gsJVn4ncPDtoh/builds/Gh8NhEx4PKjT5C3uk/openapi.json
