# Blog / Dated Content Crawler (`diarmuidr/blog-content-crawler`)

Crawl an entire blog / knowledge base or filter to just the new content.
Supporting relevant AI queries by filtering pages by date

- **URL**: https://beta-securitybyobscurity.apify.com/diarmuidr/blog-content-crawler.md
- **Developed by:** [Diarmuid](https://beta-securitybyobscurity.apify.com/diarmuidr) (community)
- **Categories:** AI, Automation, Developer tools
- **Stats:** 111 total users, 21 monthly users, 100.0% runs succeeded, 9 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

# README

## Blog / Dated Content Crawler

This actor enables you to crawl blog / dated content websites.
What this means is that you can filter the content by its publish date and only keep the content that is newer than a date you select.
This is very useful for AI applications to avoid training your model or feeding your LLM with old / outdated / irrelevant data.

This is also useful for any application where you want to download data from websites such as documentation, help articles, or your knowledge base.

### How it works

- Enter the url(s) (`startUrls`) of the pages / site you want to crawl.
- Optional: Enter a start date (`startDate`) or more likely a "Relative" start date (`relativeStartDate`) to filter the content by. "Relative" means that you can enter a date like "1 month" or "2 years" and the crawler will calculate the date relative to the current date each time it runs.
- Run the crawler
- The crawler will retrieve only the pages that are newer than the start date (`startDate`) you entered or will retrieve all the pages if you don't enter a start date.

### More Details

- **[Input schema](https://apify.com/diarmuidr/blog-content-crawler/input-schema)**
- **[Usage Guide](https://apify.com/diarmuidr/blog-content-crawler/api/javascript)**

# Actor input Schema

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

URLs to start with.

## `relativeStartDate` (type: `string`):

Optional: Select relative start date by which to filter pages. Any post published before this date will be excluded. This is calculated relative to the time the crawler is run (eg: '2 weeks' would include posts from 2 weeks ago to now). Format in format 'X days' or 'X weeks' or 'X months' or 'X years'. If no time period is passed in, it will be treated as a number of seconds.

## `startDate` (type: `string`):

Optional: Select start date by which to filter pages. Any post published before this date will be excluded. Format in format YYYY-MM-DD

## `dateSelector` (type: `string`):

Optional: CSS Selector to identify where the date is located on the page. This can make the date filtering more accurate if we don't get it right on the first round. You should use this if there's multiple dates on the page.

## `includeResultsWithNoDate` (type: `boolean`):

Optional: If true, the crawler will include results where no date was detected on the page.

## `waitForSelector` (type: `string`):

CSS Selector to wait for for page load. Useful when content on the page loads asynchronously. This is optional and in most cases won't be needed.

## `removeElementsCssSelector` (type: `string`):

Optional: CSS Selector to identify elements to remove from the page. This is useful for removing elements that are not needed for the content. For example, you can remove the header and footer of the page.

## `requestTimeoutSecs` (type: `integer`):

Optional: How long the crawler will wait for a request to complete. Default is 60 seconds.

## `dynamicContentWaitSecs` (type: `integer`):

Optional: Used in conjunction with `waitForSelector`. How long the crawler will wait for the selector to appear. Default is 10 seconds.

## `useSitemaps` (type: `boolean`):

Optional: If checked, the crawler will use the sitemap.xml file to find additional URLs to crawl.

## `filterByDocumentLastModified` (type: `boolean`):

Optional: If true, the crawler will include the document's 'last modified' date in the output.

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

Select proxies to be used by your crawler.

## `crawlerType` (type: `string`):

Select the crawler type to use. Adaptive crawlers run faster by automatically switching between raw http and browser requests. Firefox is less likely to be blocked by websites but may ocassionally fail in comparison to chrome. NOTE: You cannot use the adaptive crawler options with the 'filter by document last modified' option.

## `selectUrlsBy` (type: `string`):

Optional: Select URLs by different kinds of patterns. This is similar to includeUrlGlobs but allows for simpler selection. If `includeUrlGlobs` is provided, this option is ignored.
Subpath (default): Selects URLs that are under the path of the startUrls provided.
All: Selects all URLs found.
Same Hostname: Selects URLs that have the same hostname (does not include subdomains).
Same Domain: Selects URLs that have the same domain (i.e includes subdomains).
Same Origin: Selects URLs that have the same hostname and protocol (http/https).

## `includeUrlGlobs` (type: `array`):

Optional: An array of URL globs to include in the crawl. If not provided, the crawler will include only urls under the path of the startUrls provided. You can test globs on https://www.digitalocean.com/community/tools/glob.

## `excludeUrlGlobs` (type: `array`):

Optional: An array of URL globs to exclude from the crawl in order to avoid crawling a particular page or set of pages.

## `maxCrawlPages` (type: `integer`):

Optional: The maximum number of pages to visit. This is useful for limiting the crawl to a specific number of pages to avoid overspending.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.gymshark.com/blog/article/interval-running"
    }
  ],
  "includeResultsWithNoDate": false,
  "removeElementsCssSelector": "nav, footer, script, style, noscript, svg, img[src^='data:'],\n[role=\"alert\"],\n[role=\"banner\"],\n[role=\"dialog\"],\n[role=\"alertdialog\"],\n[role=\"region\"][aria-label*=\"skip\" i],\n[aria-modal=\"true\"]",
  "requestTimeoutSecs": 60,
  "dynamicContentWaitSecs": 10,
  "useSitemaps": true,
  "filterByDocumentLastModified": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "crawlerType": "adaptive:firefox",
  "selectUrlsBy": "subpath"
}
```

# 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.gymshark.com/blog/article/interval-running"
        }
    ],
    "dateSelector": "",
    "waitForSelector": "",
    "removeElementsCssSelector": `nav, footer, script, style, noscript, svg, img[src^='data:'],
        [role="alert"],
        [role="banner"],
        [role="dialog"],
        [role="alertdialog"],
        [role="region"][aria-label*="skip" i],
        [aria-modal="true"]`,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("diarmuidr/blog-content-crawler").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.gymshark.com/blog/article/interval-running" }],
    "dateSelector": "",
    "waitForSelector": "",
    "removeElementsCssSelector": """nav, footer, script, style, noscript, svg, img[src^='data:'],
[role=\"alert\"],
[role=\"banner\"],
[role=\"dialog\"],
[role=\"alertdialog\"],
[role=\"region\"][aria-label*=\"skip\" i],
[aria-modal=\"true\"]""",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("diarmuidr/blog-content-crawler").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 '{
  "startUrls": [
    {
      "url": "https://www.gymshark.com/blog/article/interval-running"
    }
  ],
  "dateSelector": "",
  "waitForSelector": "",
  "removeElementsCssSelector": "nav, footer, script, style, noscript, svg, img[src^='\''data:'\''],\\n[role=\\"alert\\"],\\n[role=\\"banner\\"],\\n[role=\\"dialog\\"],\\n[role=\\"alertdialog\\"],\\n[role=\\"region\\"][aria-label*=\\"skip\\" i],\\n[aria-modal=\\"true\\"]",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call diarmuidr/blog-content-crawler --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=diarmuidr/blog-content-crawler",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Blog / Dated Content Crawler",
        "description": "Crawl an entire blog / knowledge base or filter to just the new content.\nSupporting relevant AI queries by filtering pages by date",
        "version": "0.0",
        "x-build-id": "sDYyGhXIWhbZTNVlj"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/diarmuidr~blog-content-crawler/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-diarmuidr-blog-content-crawler",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/diarmuidr~blog-content-crawler/runs": {
            "post": {
                "operationId": "runs-sync-diarmuidr-blog-content-crawler",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/diarmuidr~blog-content-crawler/run-sync": {
            "post": {
                "operationId": "run-sync-diarmuidr-blog-content-crawler",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "startUrls"
                ],
                "properties": {
                    "startUrls": {
                        "title": "Start URLs",
                        "type": "array",
                        "description": "URLs to start with.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "relativeStartDate": {
                        "title": "Date",
                        "pattern": "^(\\d+)(\\s*(day|week|month|year)s?)?$",
                        "type": "string",
                        "description": "Optional: Select relative start date by which to filter pages. Any post published before this date will be excluded. This is calculated relative to the time the crawler is run (eg: '2 weeks' would include posts from 2 weeks ago to now). Format in format 'X days' or 'X weeks' or 'X months' or 'X years'. If no time period is passed in, it will be treated as a number of seconds."
                    },
                    "startDate": {
                        "title": "Date",
                        "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$",
                        "type": "string",
                        "description": "Optional: Select start date by which to filter pages. Any post published before this date will be excluded. Format in format YYYY-MM-DD"
                    },
                    "dateSelector": {
                        "title": "Date selector",
                        "type": "string",
                        "description": "Optional: CSS Selector to identify where the date is located on the page. This can make the date filtering more accurate if we don't get it right on the first round. You should use this if there's multiple dates on the page."
                    },
                    "includeResultsWithNoDate": {
                        "title": "Include results with no date",
                        "type": "boolean",
                        "description": "Optional: If true, the crawler will include results where no date was detected on the page.",
                        "default": false
                    },
                    "waitForSelector": {
                        "title": "Wait for selector",
                        "type": "string",
                        "description": "CSS Selector to wait for for page load. Useful when content on the page loads asynchronously. This is optional and in most cases won't be needed."
                    },
                    "removeElementsCssSelector": {
                        "title": "Remove HTML elements",
                        "type": "string",
                        "description": "Optional: CSS Selector to identify elements to remove from the page. This is useful for removing elements that are not needed for the content. For example, you can remove the header and footer of the page.",
                        "default": "nav, footer, script, style, noscript, svg, img[src^='data:'],\n[role=\"alert\"],\n[role=\"banner\"],\n[role=\"dialog\"],\n[role=\"alertdialog\"],\n[role=\"region\"][aria-label*=\"skip\" i],\n[aria-modal=\"true\"]"
                    },
                    "requestTimeoutSecs": {
                        "title": "Request Timeout",
                        "minimum": 1,
                        "maximum": 600,
                        "type": "integer",
                        "description": "Optional: How long the crawler will wait for a request to complete. Default is 60 seconds.",
                        "default": 60
                    },
                    "dynamicContentWaitSecs": {
                        "title": "Wait for dynamic content",
                        "minimum": 1,
                        "maximum": 60,
                        "type": "integer",
                        "description": "Optional: Used in conjunction with `waitForSelector`. How long the crawler will wait for the selector to appear. Default is 10 seconds.",
                        "default": 10
                    },
                    "useSitemaps": {
                        "title": "Use Sitemaps",
                        "type": "boolean",
                        "description": "Optional: If checked, the crawler will use the sitemap.xml file to find additional URLs to crawl.",
                        "default": true
                    },
                    "filterByDocumentLastModified": {
                        "title": "Filter by document last modified",
                        "type": "boolean",
                        "description": "Optional: If true, the crawler will include the document's 'last modified' date in the output.",
                        "default": false
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Select proxies to be used by your crawler."
                    },
                    "crawlerType": {
                        "title": "Crawler Type",
                        "enum": [
                            "adaptive:firefox",
                            "adaptive:chrome",
                            "playwright:firefox",
                            "playwright:chrome"
                        ],
                        "type": "string",
                        "description": "Select the crawler type to use. Adaptive crawlers run faster by automatically switching between raw http and browser requests. Firefox is less likely to be blocked by websites but may ocassionally fail in comparison to chrome. NOTE: You cannot use the adaptive crawler options with the 'filter by document last modified' option.",
                        "default": "adaptive:firefox"
                    },
                    "selectUrlsBy": {
                        "title": "Select URLs by",
                        "enum": [
                            "subpath",
                            "all",
                            "same-hostname",
                            "same-domain",
                            "same-origin"
                        ],
                        "type": "string",
                        "description": "Optional: Select URLs by different kinds of patterns. This is similar to includeUrlGlobs but allows for simpler selection. If `includeUrlGlobs` is provided, this option is ignored.\n Subpath (default): Selects URLs that are under the path of the startUrls provided.\n All: Selects all URLs found.\n Same Hostname: Selects URLs that have the same hostname (does not include subdomains).\n Same Domain: Selects URLs that have the same domain (i.e includes subdomains).\n Same Origin: Selects URLs that have the same hostname and protocol (http/https).",
                        "default": "subpath"
                    },
                    "includeUrlGlobs": {
                        "title": "Include URL globs",
                        "type": "array",
                        "description": "Optional: An array of URL globs to include in the crawl. If not provided, the crawler will include only urls under the path of the startUrls provided. You can test globs on https://www.digitalocean.com/community/tools/glob.",
                        "items": {
                            "type": "object",
                            "required": [
                                "glob"
                            ],
                            "properties": {
                                "glob": {
                                    "type": "string",
                                    "title": "Glob of a web page"
                                }
                            }
                        }
                    },
                    "excludeUrlGlobs": {
                        "title": "Exclude URL globs",
                        "type": "array",
                        "description": "Optional: An array of URL globs to exclude from the crawl in order to avoid crawling a particular page or set of pages.",
                        "items": {
                            "type": "object",
                            "required": [
                                "glob"
                            ],
                            "properties": {
                                "glob": {
                                    "type": "string",
                                    "title": "Glob of a web page"
                                }
                            }
                        }
                    },
                    "maxCrawlPages": {
                        "title": "Maximum number of pages to crawl",
                        "type": "integer",
                        "description": "Optional: The maximum number of pages to visit. This is useful for limiting the crawl to a specific number of pages to avoid overspending."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
