> ## Documentation Index
> Fetch the complete documentation index at: https://docs.olostep.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 検索 API

> 自然言語でウェブを検索し、構造化されたリンクを取得 — Olostep の AI 検索 API。

Olostep の `/v1/searches` エンドポイントを使用すると、自然言語クエリでウェブを検索し、重複排除された関連リンクのリストをタイトルと説明付きで取得できます。

* 英語でクエリを送信
* ウェブ全体から構造化されたリンクを取得
* オプションで、返されたすべての URL を一度にスクレイピングし、`markdown_content` / `html_content` をレスポンスに直接埋め込む
* ドメインでフィルタリングし、結果の数を制御し、スクレイピングのウォールクロックを制限

クエリをウェブ全体で意味的に検索し、結果を返します。

API の詳細については、[検索エンドポイント API リファレンス](/api-reference/searches/create)を参照してください。

## インストール

<CodeGroup>
  ```python Python theme={null}
  pip install olostep
  ```

  ```javascript Node theme={null}
  npm install olostep
  ```

  ```bash cURL theme={null}
  # curl は macOS、Linux、Windows でデフォルトで利用可能です
  ```

  ```javascript Node (API) theme={null}
  npm install node-fetch
  ```

  ```bash Python (API) theme={null}
  pip install requests
  ```
</CodeGroup>

## 基本的な使い方

自然言語クエリを送信し、関連リンクのリストを受け取ります。

<CodeGroup>
  ```python Python theme={null}
  from olostep import Olostep

  client = Olostep(api_key="YOUR_REAL_KEY")

  search = client.searches.create("Best Answer Engine Optimization startups")

  print(search.id, len(search.links))
  ```

  ```js Node theme={null}
  import Olostep from 'olostep'

  const client = new Olostep({ apiKey: 'YOUR_REAL_KEY' })

  const search = await client.searches.create('Best Answer Engine Optimization startups')

  console.log(search.id, search.links.length)
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.olostep.com/v1/searches" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "Best Answer Engine Optimization startups"
    }'
  ```

  ```js Node (API) theme={null}
  const res = await fetch('https://api.olostep.com/v1/searches', {
    method: 'POST',
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>', 'Content-Type': 'application/json' },
    body: JSON.stringify({
      query: 'Best Answer Engine Optimization startups'
    })
  })
  console.log(await res.json())
  ```

  ```python Python (API) theme={null}
  import requests, json

  endpoint = "https://api.olostep.com/v1/searches"
  payload = {
    "query": "Best Answer Engine Optimization startups"
  }
  headers = {"Authorization": "Bearer <YOUR_API_KEY>", "Content-Type": "application/json"}

  response = requests.post(endpoint, json=payload, headers=headers)
  print(json.dumps(response.json(), indent=2))
  ```
</CodeGroup>

## リクエストパラメータ

| フィールド             | タイプ       | 必須  | デフォルト | 説明                                                                                              |
| ----------------- | --------- | --- | ----- | ----------------------------------------------------------------------------------------------- |
| `query`           | string    | yes | —     | 自然言語での検索クエリ。                                                                                    |
| `limit`           | integer   | no  | `12`  | 重複排除後に返すリンクの最大数。`1`から`25`の間で指定可能。                                                               |
| `include_domains` | string\[] | no  | `[]`  | 結果をこれらのドメインに限定。ホスト名のみ — 先頭の `http(s)://` と末尾のスラッシュは自動的に削除されます。                                  |
| `exclude_domains` | string\[] | no  | `[]`  | これらのドメインからの結果を除外。ホスト名のみ — 先頭の `http(s)://` と末尾のスラッシュは自動的に削除されます。                                |
| `scrape_options`  | object    | no  | —     | 提供された場合、返されたすべてのリンクがスクレイピングされ、そのコンテンツがレスポンスに埋め込まれます。以下の [scrape\_options](#scrape-options) を参照。 |

### 結果の数を制限する

```json theme={null}
{
  "query": "What's going on with OpenAI's Sora shutting down?",
  "limit": 5
}
```

### ドメインでフィルタリングする

`include_domains` は結果をホワイトリストに絞り、`exclude_domains` は不要なソースを除外します。これらは組み合わせ可能です。

```json theme={null}
{
  "query": "OpenAI Sora shutdown analysis",
  "include_domains": ["nytimes.com", "wsj.com", "bbc.com"],
  "exclude_domains": ["pinterest.com"]
}
```

## scrape\_options

`scrape_options` を渡して、返されたすべての URL を並列にスクレイピングし、各リンクにレンダリングされたコンテンツを直接埋め込みます。これにより、`/v1/searches` と `/v1/scrapes` を別々に呼び出すのに比べて、結果ごとのラウンドトリップが節約されます。

```json theme={null}
{
  "query": "What's going on with OpenAI's Sora shutting down?",
  "limit": 10,
  "scrape_options": {
    "formats": ["markdown"],
    "remove_css_selectors": "default",
    "timeout": 25
  }
}
```

| フィールド                  | タイプ       | デフォルト          | 説明                                                                                                                               |
| ---------------------- | --------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `formats`              | string\[] | `["markdown"]` | 各リンクに添付する出力フォーマット。`/v1/searches` では `"html"` と `"markdown"` のみサポート。`["html", "markdown"]` を渡して両方を受け取る。                           |
| `remove_css_selectors` | string    | `"default"`    | `/v1/scrapes` に転送されます。`"default"` はナビゲーション/フッター/スクリプト/スタイル/svg/ダイアログのノイズを削除します。`"none"` を使用して無効にするか、削除するセレクタの JSON 文字列化された配列を渡す。 |
| `timeout`              | integer   | `25`           | スクレイピングフェーズ全体のウォールクロックの予算（秒単位）。`1`から`60`の間で指定可能。これが経過すると、検索は即座に終了し、完了していないリンクのコンテンツフィールドは `null` になります。                          |

### 振る舞い

* すべてのリンクは**並列に**スクレイピングされます。`timeout` は全体のバッチを制限し、各リンク個別ではありません。
* リンクごとのスクレイピング失敗（ネットワークエラー、個々のページのタイムアウト）は、そのリンクの `markdown_content` / `html_content` を `null` にし、他のリンクは通常通り返されます。
* グローバル `timeout` がすべてのスクレイピングが完了する前に経過した場合、検索は即座にリンクを持って応答します — すでに完了したスクレイピングはそのコンテンツを保持し、進行中のものは `null` コンテンツで返されます。
* `reddit.com/.../comments/...` URL の場合、リクエストは自動的に `@olostep/reddit-post` パーサーを通じてルーティングされ、構造化された JSON がクリーンなマークダウン + 基本 HTML にレンダリングされます。
* 結合されたインラインコンテンツが 9MB を超える場合、コンテンツフィールドは無効になり、`result.size_exceeded` が `true` に設定され、`result.json_hosted_url` から完全なペイロードを取得できます。

### スクレイピングの例

<CodeGroup>
  ```python Python theme={null}
  from olostep import Olostep

  client = Olostep(api_key="YOUR_REAL_KEY")

  search = client.searches.create(
      query="What's going on with OpenAI's Sora shutting down?",
      limit=5,
      scrape_options={"formats": ["markdown"], "timeout": 25},
  )

  for link in search.links:
      print(link["url"], "—", len(link.get("markdown_content") or ""), "chars")
  ```

  ```js Node theme={null}
  import Olostep, { Format } from 'olostep'

  const client = new Olostep({ apiKey: 'YOUR_REAL_KEY' })

  const search = await client.searches.create({
    query: "What's going on with OpenAI's Sora shutting down?",
    limit: 5,
    scrapeOptions: {
      formats: [Format.MARKDOWN],
      timeout: 25
    }
  })

  for (const link of search.links) {
    console.log(link.url, '—', (link.markdown_content || '').length, 'chars')
  }
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.olostep.com/v1/searches" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "What'"'"'s going on with OpenAI'"'"'s Sora shutting down?",
      "limit": 5,
      "scrape_options": {
        "formats": ["markdown"],
        "timeout": 25
      }
    }'
  ```

  ```js Node (API) theme={null}
  const res = await fetch('https://api.olostep.com/v1/searches', {
    method: 'POST',
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>', 'Content-Type': 'application/json' },
    body: JSON.stringify({
      query: "What's going on with OpenAI's Sora shutting down?",
      limit: 5,
      scrape_options: {
        formats: ['markdown'],
        timeout: 25
      }
    })
  })
  const data = await res.json()
  for (const link of data.result.links) {
    console.log(link.url, '—', (link.markdown_content || '').length, 'chars')
  }
  ```

  ```python Python (API) theme={null}
  import requests, json

  endpoint = "https://api.olostep.com/v1/searches"
  payload = {
    "query": "What's going on with OpenAI's Sora shutting down?",
    "limit": 5,
    "scrape_options": {
      "formats": ["markdown"],
      "timeout": 25
    }
  }
  headers = {"Authorization": "Bearer <YOUR_API_KEY>", "Content-Type": "application/json"}

  response = requests.post(endpoint, json=payload, headers=headers)
  data = response.json()
  for link in data["result"]["links"]:
    print(link["url"], "—", len(link.get("markdown_content") or ""), "chars")
  ```
</CodeGroup>

## レスポンス

レスポンスとして `search` オブジェクトを受け取ります。`search` オブジェクトには `id`、元の `query`、`credits_consumed`、および `links` のリストを含む `result` が含まれています。

```json theme={null}
{
  "id": "search_9bi0sbj9xa",
  "object": "search",
  "created": 1760327323,
  "metadata": {},
  "query": "What's going on with OpenAI's Sora shutting down?",
  "credits_consumed": 10,
  "result": {
    "json_content": "...",
    "json_hosted_url": "https://olostep-storage.s3.us-east-1.amazonaws.com/search_9bi0sbj9xa.json",
    "size_exceeded": false,
    "credits_consumed": 10,
    "links": [
      {
        "url": "https://www.bbc.com/news/articles/c3w3e467ewqo",
        "title": "OpenAI to shut down Sora video platform",
        "description": "OpenAI says it will discontinue its Sora app...",
        "markdown_content": "# OpenAI to shut down Sora video platform\n\nOpenAI says it will discontinue..."
      },
      {
        "url": "https://www.reddit.com/r/OutOfTheLoop/comments/1s2u847/whats_going_on_with_openais_sora_shutting_down/",
        "title": "What's going on with OpenAI's Sora shutting down?",
        "description": "Reddit thread discussing the shutdown.",
        "markdown_content": "# What's going on with OpenAI's Sora shutting down?\n\n*r/OutOfTheLoop · u/rm-minus-r · 1mo ago*\n\n..."
      }
    ]
  }
}
```

`result.links` の各リンクには以下が含まれます：

| フィールド              | タイプ    | 説明                                                                                                             |
| ------------------ | ------ | -------------------------------------------------------------------------------------------------------------- |
| `url`              | string | 検索結果の URL。                                                                                                     |
| `title`            | string | 結果ページのタイトル。                                                                                                    |
| `description`      | string | 結果を説明する短いスニペット。                                                                                                |
| `markdown_content` | string | ページのマークダウンコンテンツ。`scrape_options.formats` に `"markdown"` が含まれる場合のみ存在。スクレイピングが失敗、空、またはグローバルタイムアウトに達した場合は `null`。 |
| `html_content`     | string | ページの HTML コンテンツ。`scrape_options.formats` に `"html"` が含まれる場合のみ存在。失敗/タイムアウト時は `null`。                            |

完全な結果は `result.json_hosted_url` でホストされた JSON ファイルとしても利用可能です — `result.size_exceeded` が `true` の場合に便利です。

## 過去の検索を取得する

`GET /v1/searches/{search_id}` は、検索時に保存されたものを返します。スクレイピングされたコンテンツを含みます。これは純粋な冪等な読み取りであり、再スクレイピングや再請求はありません。`scrape_options` のない古い検索には、リンクごとのコンテンツフィールドがありません。

<CodeGroup>
  ```python Python theme={null}
  from olostep import Olostep

  client = Olostep(api_key="YOUR_REAL_KEY")

  search = client.searches.get(search_id="search_9bi0sbj9xa")
  print(search.id, len(search.links))
  ```

  ```js Node theme={null}
  import Olostep from 'olostep'

  const client = new Olostep({ apiKey: 'YOUR_REAL_KEY' })

  const search = await client.searches.get('search_9bi0sbj9xa')
  console.log(search.id, search.links.length)
  ```

  ```bash cURL theme={null}
  curl -s "https://api.olostep.com/v1/searches/search_9bi0sbj9xa" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY"
  ```
</CodeGroup>

完全な詳細については、[検索を取得](/api-reference/searches/get)を参照してください。

## 料金

各検索には、検索自体に対して**5 クレジット**がかかります。

`scrape_options` が提供されている場合、各スクレイピングされたページは標準の `/v1/scrapes` レートで請求されます（通常は 1 ページあたり 1 クレジット。一部のパーサーはそれ以上のコストがかかる場合があります）。合計は `credits_consumed` に返されます。

例：

| リクエスト                         | `credits_consumed` |
| ----------------------------- | ------------------ |
| 検索のみ                          | `5`                |
| 検索 + 5 ページのスクレイピング（各 1 クレジット） | `10`               |
