# 91Porn Video Downloader (`easy-scrap/91porn-video-downloader`) Actor

Download 91Porn videos and metadata with browser-based URL extraction

- **URL**: https://apify.com/easy-scrap/91porn-video-downloader.md
- **Developed by:** [Easy Scrap](https://apify.com/easy-scrap) (community)
- **Categories:** Videos
- **Stats:** 5 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.01 / result-hit-cache

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 91Porn Video Downloader

[中文说明](#中文说明) · [English](#english)

### 中文说明

这是一个用于下载视频、封面和元信息的 Apify Actor。Actor 会在真实浏览器中运行页面 JavaScript，读取播放器最终生成的视频地址，同时获取视频封面，并在后台归档这些文件。

请仅处理你有权访问、保存和再分发的内容。使用前请确认符合源站、Apify、代理服务、存储服务以及所在地的法律和平台规则。不得使用本 Actor 处理未成年人或未经授权的内容。

#### 主要功能

- 执行页面 JavaScript，获取播放器实际使用的视频地址。
- 获取视频封面并与视频一起归档。
- 对源站返回的替代资源进行识别，并在页面时长与媒体实际时长不一致时自动重试。
- 使用所有调用者共享的缓存保存已归档的视频、封面和元信息，重复运行时优先复用已有文件。
- 支持多个 `viewKey` 并发处理。
- 不限制视频最大时长或文件大小；实际处理时间和存储费用取决于视频大小。

#### 快速开始

在 Actor 的 **Input** 页面输入一个或多个完整视频 URL 或 `viewKey`：

```json
{
  "videos": [
    "https://91porn.com/view_video.php?viewkey=462207736",
    "b499b68eee656977a01f"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 2
}
```

运行完成后，在 **Dataset** 页面查看结果。成功结果会包含视频和封面的临时下载地址。

#### 输入参数

| 参数 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `videos` | 字符串数组 | 必填 | 要处理的完整视频 URL 或 `viewKey`，至少一个。URL 必须包含 `viewkey` 查询参数，重复值会自动去重。 |
| `proxyConfiguration` | 对象 | `{"useApifyProxy": true}` | 是否使用运行者账号的 Apify 共享数据中心代理池。设置为 `false` 时直接访问源站。代理和相关平台流量费用由运行此次 Actor 的账号承担。 |
| `maxConcurrency` | 整数 | `2` | 同时处理的视频数，允许范围为 `1–4`。 |

#### 并发建议

默认并发数为 `2`。如果一次提交多个视频，可以提高到 `3` 或 `4`，但并发越高，源站风控、代理请求、浏览器资源和后台存储操作竞争也会增加。遇到失败或替代资源错误时，建议降低 `maxConcurrency` 后重试。

#### 输出结果

归档成功时，Dataset 结果通常包含：

```json
{
  "viewkey": "462207736",
  "title": "视频标题",
  "duration": "00:01:01",
  "status": "archived",
  "videoDownloadUrl": "临时视频下载地址",
  "videoDownloadUrlExpiresAt": "2026-08-18T12:00:00.000Z",
  "coverDownloadUrl": "临时封面下载地址",
  "coverDownloadUrlExpiresAt": "2026-08-18T12:00:00.000Z",
  "cacheHit": false
}
```

常见状态：

- `archived`：视频和封面已成功归档。
- `error`：当前视频处理失败，`errorMsg` 字段包含原因；其他视频仍会继续处理。

下载地址约 24 小时后过期。过期后可以再次运行 Actor；如果文件已经缓存，Actor 会跳过重新抓取和下载，只生成新的 24 小时下载地址。

#### 缓存行为

- 已归档的视频、封面和元信息会保存在 Actor 的后台缓存中。
- 默认情况下，缓存命中不会请求源站或重复下载文件。
- 如果缓存记录不存在，或缓存对应的视频、封面文件已经不存在，Actor 会自动补齐缺失内容。
- 只要 B2 中的视频和封面可用，Dataset 结果就标记 `cacheHit: true`，即使本次运行的 KVS 记录刚好未命中。
- 缓存查询顺序为共享 KVS，然后是元数据缓存；两种命中情况都会返回完整元信息。

#### 常见问题

**为什么没有拿到视频地址？**

源站可能返回替代资源、临时错误或触发风控。Actor 会自动重试；仍然失败时，可以稍后重试或降低 `maxConcurrency`。

**为什么下载地址打不开？**

下载地址是临时地址，可能已经过期。重新运行 Actor 即可获得新地址。

#### 计费和存储

计费方式和价格以 Actor 页面当前显示为准。使用 Pay-per-event 时，`result-hit-cache` 表示返回一个已经归档的视频和封面链接，`result-not-hit-cache` 表示成功补齐或归档一个视频。新视频抓取、浏览器运行、视频下载、封面下载、文件归档和带宽使用会产生实际资源消耗；缓存命中通常比重新抓取和下载消耗更少。

请根据自己的使用量关注 Apify 运行费用以及文件存储和下载费用。Actor 不会向用户暴露后台凭据。

### English

This Apify Actor downloads videos, cover images, and metadata. It runs the page's JavaScript in a real browser, reads the final URL generated by the player, obtains the video cover, and archives both files in its backend storage.

Only process content that you are authorized to access, store, and redistribute. You are responsible for complying with the source website, Apify, proxy providers, storage providers, and applicable laws and platform policies. Do not use this Actor for minors or unauthorized content.

#### Features

- Executes page JavaScript and reads the URL actually used by the player.
- Retrieves and archives the video cover together with the video.
- Detects replacement media and retries when the page duration does not match the actual media duration.
- Uses a cache shared by all callers to reuse archived videos, covers, and metadata on later runs.
- Processes multiple `viewKey` values concurrently.
- Does not impose a maximum video duration or file size; processing time and storage costs depend on the video size.

#### Quick start

Enter one or more full video URLs or `viewKey` values on the Actor's **Input** page:

```json
{
  "videos": [
    "https://91porn.com/view_video.php?viewkey=462207736",
    "b499b68eee656977a01f"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 2
}
```

When the run finishes, open the results in the **Dataset** page. Each successful result includes temporary download URLs for both the video and its cover.

#### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `videos` | string array | Required | Full video URLs or `viewKey` values to process. URLs must contain a `viewkey` query parameter; duplicates are removed. |
| `proxyConfiguration` | object | `{"useApifyProxy": true}` | Choose whether to use the Apify shared datacenter proxy pool belonging to the account running the Actor. Set it to `false` for direct source access. Proxy and related platform traffic costs are charged to the run owner. |
| `maxConcurrency` | integer | `2` | Maximum number of videos processed at the same time; allowed range is `1–4`. |

#### Concurrency guidance

The default concurrency is `2`. For multiple videos, you can increase it to `3` or `4`, but higher concurrency also increases source-site defenses, proxy requests, browser resource usage, and backend storage contention. If failures or replacement-media errors occur, lower `maxConcurrency` and retry.

#### Output

A successful archive result usually contains:

```json
{
  "viewkey": "462207736",
  "title": "Video title",
  "duration": "00:01:01",
  "status": "archived",
  "videoDownloadUrl": "temporary video download URL",
  "videoDownloadUrlExpiresAt": "2026-08-18T12:00:00.000Z",
  "coverDownloadUrl": "temporary cover download URL",
  "coverDownloadUrlExpiresAt": "2026-08-18T12:00:00.000Z",
  "cacheHit": false
}
```

Common statuses:

- `archived`: the video and cover were archived successfully.
- `error`: processing failed for this video; `errorMsg` contains the reason. Other videos continue independently.

Download URLs expire after about 24 hours. Run the Actor again to obtain fresh URLs. If the files are already cached, the Actor skips scraping and downloading and only creates new 24-hour URLs.

#### Cache behavior

- Archived videos, covers, and metadata are stored in the Actor's backend cache.
- By default, a cache hit does not request the source page or download the files again.
- If the cache record is missing, or either cached file is missing, the Actor automatically fills in the missing content.
- A Dataset result has `cacheHit: true` whenever the video and cover are available, even if the current run misses the KVS record.
- Cache lookup uses the shared KVS first and then the metadata cache; both paths return complete metadata.

#### Troubleshooting

**Why was no video URL returned?**

The source may return replacement media, a temporary error, or trigger anti-bot defenses. The Actor retries automatically; if it still fails, try again later or lower `maxConcurrency`.

**Why does a download URL not work?**

Download URLs are temporary and may have expired. Run the Actor again to obtain fresh URLs.

#### Pricing and storage

Pricing is determined by the current price shown on the Actor page. With pay-per-event pricing, `result-hit-cache` represents returning links for an already archived video and cover, while `result-not-hit-cache` represents successfully filling or archiving one video. Fresh scraping, browser execution, video and cover downloads, file archiving, and bandwidth use consume resources; cache hits usually consume less than a fresh archive.

Monitor your Apify usage and file storage and download costs based on your workload. The Actor never exposes backend credentials to users.

# Actor input Schema

## `videos` (type: `array`):

One or more full video URLs or viewkeys. URLs must contain a viewkey query parameter.

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

Choose whether the browser uses the Apify shared datacenter proxy pool. Proxy usage and related platform traffic are charged to the account running this Actor.

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

Maximum number of videos processed at the same time.

## Actor input object example

```json
{
  "videos": [
    "b499b68eee656977a01f"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 2
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset items produced by the Actor for each requested video.

# 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 = {
    "videos": [
        "b499b68eee656977a01f"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("easy-scrap/91porn-video-downloader").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 = { "videos": ["b499b68eee656977a01f"] }

# Run the Actor and wait for it to finish
run = client.actor("easy-scrap/91porn-video-downloader").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 '{
  "videos": [
    "b499b68eee656977a01f"
  ]
}' |
apify call easy-scrap/91porn-video-downloader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,easy-scrap/91porn-video-downloader"
        }
    }
}
```

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/ljTbHZQhXymnyJ8HD/builds/bINc7AtPQKJBzAoUE/openapi.json
