DMMジャンル検索APIの使い方|ジャンルIDをPHPで全部取る
- タグ
- API

DMMのジャンル検索API(GenreSearch)は、フロアIDを渡すと、そのフロアのジャンルID・名前・読み仮名・作品一覧のURLを、1回に最大500件返します。FANZAのビデオ(フロアID 43)には、2026年10月17日の時点で341のジャンルがあり、1回の呼び出しで全部取れました。
ジャンル検索APIは、2023年12月のオーナーが、サイトを作る途中で使うことになったAPIです。そのときの記録を、記事担当の伊緒が今のAPIで呼び直して、書き直したのがこの記事。
確かめてみると、当時のコードのままでは取りこぼすフロアがありました。ジャンルが500件を超えるフロアがあり、1回の呼び出しでは全部取れないので、後半に、最後まで取るコードを載せています。
指定できる条件と、返ってくる項目
必ず指定するのは、API ID・アフィリエイトID・フロアID(floor_id)の3つです。フロアIDを省くと、400のエラーが返りました。
| パラメーター | 中身 | 決まり |
|---|---|---|
floor_id | フロアID(数字) | 必須。フロアAPIで調べる |
initial | 読みの頭文字 | ひらがな1文字をUTF-8で |
hits | 1回に取る件数 | 初期値100・最大500 |
offset | 何件目から取るか | 初期値1 |
output | 出力の形式 | json か xml |
hits=501 にすると、400のエラーになり、「hits は500以下にする」という意味の英語の文が返ります。initial=あ で呼ぶと、FANZAのビデオでは15件に絞られました。DMMのご利用ガイドには「一度のリクエストで取得できるのは100件まで」とありますが、ジャンル検索のリファレンスでは最大500件で、実際に341件が1回で返っています。
返ってくる項目は、フロアの情報と、ジャンルの配列(genre)です。
| 中身 | 項目名 | FANZAのビデオでの例 |
|---|---|---|
| 売り場の名前 | site_name・service_name・floor_name | FANZA(アダルト)・動画・ビデオ |
| 商品検索に渡すコード | site_code・service_code・floor_code | FANZA・digital・videoa |
| 件数 | total_count・result_count | 全体341・今回返した341 |
| ジャンルID | genre[].genre_id | 4031 |
| ジャンルの名前と読み仮名 | genre[].name・ruby | コスプレ・こすぷれ |
| 作品一覧へのリンク | genre[].list_url | コスプレの作品一覧へのアフィリエイトリンク |
コードを書くときに気をつけたいのは、値の型です。genre_id・total_count・status は文字列(“341”)で返り、result_count だけが数で返ってきました。商品検索APIの応答では、ジャンルのIDは数(4031)で入っています。=== で比べると一致しないので、(int) でそろえてから比べてください。
一覧ページのURLは、公式ドキュメントの例では www.dmm.co.jp/digital/videoa/-/list/ の形ですが、今の応答は video.dmm.co.jp/av/list/?genre=ID の形になっていました。
フロアを選んで試すなら、DMM ジャンル検索のツールが手軽です。
フロアごとのジャンルの数
FANZAの23のフロアのうち、ジャンルが500件を超えたのは同人(558件)だけでした。DMM.comでは、ホビー(1,308件)・コミック(904件)・文芸・ラノベ(580件)・DVD・Blu-ray(508件)が500件を超えています。2026年10月17日に、全39フロアを呼んだ結果です。
| サービス | フロアの名前 | フロアID | ジャンルの数 |
|---|---|---|---|
| 動画 | ビデオ | 43 | 341 |
| 動画 | 素人 | 44 | 243 |
| 動画 | 成人映画 | 45 | 192 |
| 動画 | アニメ動画 | 46 | 132 |
| 月額動画 | 見放題ch デラックス | 68 | 345 |
| 月額動画 | VRch | 91 | 254 |
| 月額動画 | 見放題ch | 98 | 0 |
| 通販 | DVD | 74 | 456 |
| 通販 | 大人のおもちゃ | 75 | 219 |
| 通販 | アニメ | 76 | 167 |
| 通販 | PCゲーム | 77 | 168 |
| 通販 | ブック | 78 | 357 |
| 通販 | フィギュア・グッズ | 94 | 172 |
| アダルトPCゲーム | アダルトPCゲーム | 80 | 347 |
| 同人 | 同人 | 81 | 558 |
| 同人 | らぶカル(BL) | 99 | 25 |
| 同人 | らぶカル(TL) | 100 | 18 |
| FANZAブックス | コミック | 82 | 289 |
| FANZAブックス | 美少女ノベル・官能小説 | 83 | 197 |
| FANZAブックス | アダルト写真集・雑誌 | 84 | 258 |
| FANZAブックス | BL | 96 | 0 |
| FANZAブックス | TL | 97 | 0 |
| FANZAブックス読み放題 | FANZAブックス読み放題 | 92 | 217 |
ジャンルが0件のフロアは、エラーにはならず、空の配列が返ります。DMM.comでも、AKB48グループの7フロアとDMMTVは0件でした。DMM TVの作品はジャンルの情報を取れないと、DMMのヘルプにも書かれています。

フロアIDは、フロアAPIで調べます。全部のフロアのIDとコードは、こちらの記事に表でまとめました。
一覧をそのまま使う前に外したいジャンル
FANZAのビデオの341件には、そのまま使うと困るジャンルが2種類ありました。過去の企画で使ったジャンルと、同じ名前でIDが違うジャンルです。
過去の企画で使ったジャンル
「AV OPEN 2014 スーパーヘビー級」から「AV OPEN 2018 マニア・フェチ部門」まで、2014〜2018年の企画のジャンルが36件残っていました。商品検索で作品の数を全部数えると0〜32件で、29件は7件以下です。オーナーは2023年の時点で「削除して使いたい」と書いていて、今もその判断のままでいいと思います。
同じ名前でIDが違うジャンル
「コスプレ」「制服」「ドラマ」など7つの名前に、IDが2つか3つずつ、合わせて16個ありました。商品検索で、FANZAのビデオのフロアに絞って作品の数を調べると、どの名前も作品があるIDは1つだけで、残りの9個は0件です。
| ジャンルの名前 | 作品があったID(件数) | 0件だったID |
|---|---|---|
| 4時間以上作品 | 6012(48,614件) | 6179 |
| コスプレ | 4031(13,233件) | 66314 |
| 制服 | 48(12,497件) | 66317 |
| ドラマ | 4114(18,681件) | 66329 |
| 和服・浴衣 | 3002(6,686件) | 3021・66318 |
| セクシー | 4098(2,529件) | 79002・66310 |
| ディルド | 6941(1,223件) | 10138 |
名前だけでIDを選ぶと、作品が1件も出ないジャンルのページができてしまうので要注意。後半のコードでは、名前が重なるジャンルだけ商品検索で数を調べて、0件のIDを外しています。

PHPのコード:ジャンルを全部取って、対応表に保存する
オーナーが2023年に書いたコードは、2026年10月17日にそのまま動かすと、FANZAのビデオの341件を警告なしで表示できました。ただ、hits を500にした1回きりの呼び出しなので、同人やホビーのような500件を超えるフロアでは、残りを取りこぼします。
直したコードは、offset をずらして最後まで取り、外したいジャンルを除いて、「ジャンルID → 名前・読み仮名」の対応表をJSONで保存する作りです。ブラウザで開くページではなく、コマンドラインで php genre.php と実行して使います。

<?php
// DMM ジャンル検索API(GenreSearch)で、1つのフロアのジャンルを全部取り、
// 「ジャンルID → 名前・読み」の対応表を JSON に保存する(コマンドラインで php genre.php と実行する)
const API_ID = 'あなたのAPI ID';
const AFFILIATE_ID = 'あなたのアフィリエイトID'; // 末尾が990〜999のもの
const FLOOR_ID = 43; // フロアAPIで調べたフロアID(43は FANZA の動画・ビデオ)
function dmm_api(string $name, array $params): array
{
$query = http_build_query(['api_id' => API_ID, 'affiliate_id' => AFFILIATE_ID, 'output' => 'json'] + $params);
$context = stream_context_create(['http' => ['ignore_errors' => true, 'timeout' => 10]]);
// 先頭の @ は、つながらなかったときの警告に API ID 入りの URL を出さないため
$body = @file_get_contents('https://api.dmm.com/affiliate/v3/' . $name . '?' . $query, false, $context);
$result = json_decode((string) $body, true)['result'] ?? null;
if (!is_array($result) || (int) ($result['status'] ?? 200) !== 200) {
exit('APIのエラー: ' . json_encode($result ?? '応答がありません', JSON_UNESCAPED_UNICODE) . "\n");
}
return $result;
}
// 1回に取れるのは500件まで。500件を超えるフロアがあるので、offset をずらして最後まで取る
$genres = [];
$offset = 1;
do {
$result = dmm_api('GenreSearch', ['floor_id' => FLOOR_ID, 'hits' => 500, 'offset' => $offset]);
foreach ($result['genre'] as $genre) {
// 過去の企画で使った「AV OPEN 2014 〜」のようなジャンルは外す
if (preg_match('/^AV OPEN \d{4}/', $genre['name'])) {
continue;
}
$genres[$genre['genre_id']] = ['name' => $genre['name'], 'ruby' => $genre['ruby']];
}
$offset += (int) $result['result_count'];
sleep(1); // 続けて呼ぶときは間を空ける
} while ($result['result_count'] > 0 && $offset <= (int) $result['total_count']);
// 同じ名前のジャンルが2つ以上あるときは、商品検索で作品が0件の ID を外す
$count = array_count_values(array_column($genres, 'name'));
foreach ($genres as $id => $genre) {
if ($count[$genre['name']] < 2) {
continue;
}
$items = dmm_api('ItemList', [
'site' => $result['site_code'],
'service' => $result['service_code'],
'floor' => $result['floor_code'],
'article' => 'genre',
'article_id' => $id,
'hits' => 1,
]);
if ((int) $items['total_count'] === 0) {
unset($genres[$id]);
}
sleep(1);
}
// 読みの50音順に並べて保存する
uasort($genres, fn($a, $b) => strcmp($a['ruby'], $b['ruby']));
file_put_contents(__DIR__ . '/genres-' . FLOOR_ID . '.json', json_encode($genres, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
echo $result['floor_name'] . ' のジャンル ' . $result['total_count'] . '件のうち、' . count($genres) . "件を保存しました\n";
2026年10月17日に動かした結果は、次のとおりです。
- FANZAのビデオ(43):341件のうち296件を保存(AV OPENの36件と、0件だった9個を外した)。20秒ほどで終わった
- FANZAの同人(81):558件を2回に分けて全部取り、名前が重なって0件だった14個を外して544件を保存。40秒ほどかかった

保存した対応表は、ジャンルの一覧ページやメニューを作るときに読み込んで使います。たとえば、50音順のリンクを並べるなら、次の数行です。
<?php
// 保存した対応表から、ジャンルのリンクを50音順に並べる(対応表は公開フォルダの外の data/ に置いた例)
$genres = json_decode(file_get_contents(__DIR__ . '/../data/genres-43.json'), true);
foreach ($genres as $id => $genre) {
echo '<a href="/genre/' . $id . '/">' . htmlspecialchars($genre['name']) . '</a>' . "\n";
}
リンク先のジャンルのページでは、商品検索APIに article=genre&article_id=ID を渡して作品を出します。対応表のJSONは、サイトの公開フォルダの外に置いてください。DMMウェブサービスの利用規約では、APIで得た情報を、不特定の人が共有できる場所に保管することが禁止されています。公開のGitHubのリポジトリに入れるのも避けたほうが安心です。
2023年のオーナーの考えを、今の仕様で見直すと
オーナーがジャンル検索を使い始めたのは、SEOを考えると、ジャンルIDではなくジャンルの名前を使いたくなったからでした。当時の考えを、今のAPIに当てはめるとこうなります。
| 項目 | オーナーが2023年に書いたこと | 2026年10月17日に確かめた結果 |
|---|---|---|
| ジャンル名 | 商品が持っているジャンルIDから、ジャンル名を取りたい | 商品検索の応答に、名前もIDと一緒に入っている。作品ページに名前を出すだけなら、ジャンル検索は要らない |
| IDでの絞り込み | ジャンルIDで絞り込めないのが残念 | 今もできない。指定できるのはフロアID・頭文字・件数・開始位置だけ |
| データベース | ジャンルのデータをデータベースに入れて対応したい | 今も有効。一覧ページやメニューを作るなら、対応表を保存して使い回すのが早い |
| 一時的なジャンル | 「AV OPEN」のようなジャンルは削除して使いたい | 今も36件残っている。名前の先頭で見分けて外せる |
ジャンル検索が本当に役に立つのは、作品を取る前に、そのフロアのジャンルを全部、読み仮名つきで並べたいときです。ジャンルごとのページを作るサイトなら、最初に一度取って保存しておけば、毎回APIを呼ばずに済みます。
ジャンルIDを使って作品を絞り込む方法は、商品検索APIの記事で書いています。
よくある質問
ジャンルIDは、フロアが違っても同じ?
FANZAの動画のビデオ(フロアID 43)と、同じ動画サービスのフロアID 44(コードは videoc)を比べると、両方にあるIDは214個で、どれも同じ名前でした。ただ、フロアによって無いジャンルもあるので、使うフロアごとに一覧を取ってください。
頭文字は、どう指定する?
initial に、ひらがなを1文字だけUTF-8で渡します。FANZAのビデオで「あ」を渡すと、読みが「あ」で始まる15件が返りました。
何回まで続けて呼んでいい?
回数の上限は、ドキュメントに数字で書かれていません。利用規約には、アクセス回数などの制約を別に定めることがある、とあります。ジャンルの一覧はめったに変わらないので、保存して使い回し、続けて呼ぶときは間を空けてください。
この記事で作ったAPIは、ツールで試せます
キーワードや条件を変えて、APIが返す実際のデータを確かめられます。



