

# Bingのキーワード順位を比較できるスナップショットとして保存する方法

Bingの各順位を、同一のクエリ、国、言語、設定、結果件数の上限、および観測日時とともに保存します。順位とは、収集したサンプル内での掲載位置を表す番号です。番号が小さいほど、その結果は先に表示されています。結果件数の上限とは、1つのクエリで保存する結果の最大件数です。これらがすべて一致するスナップショットだけを比較します。スナップショットとは、1回の実行を保存した記録です。件数に上限があるサンプルに自分のページが含まれていない場合は、そのサンプル内では見つからなかったと記録します。順位を作り上げてはいけません。Bing全体にそのページが存在しないと述べてはいけません。

## 保存するもの

Actorは、ホスティング環境で動作し、データを収集するプログラムです。この方法では、[Google Search Scraper](https://apify.com/chronometrica/google-search-scraper) Actorのビルド1.0.15を使います。Taskは、保存済みの入力設定です。現在の[Keyword Search Rank Snapshot](https://apify.com/chronometrica/google-search-scraper/examples/keyword-rank-snapshot) Taskは、入力設定の出発点にすぎません。Task自体が順位を分析するわけではありません。

Actorは、ソースから取得した行を保存します。その行を、以下の手順で比較します。

ビルド1.0.15では、enginesのリストにGoogle、Bing、Brave、DuckDuckGoを指定できます。この方法で扱うのはBingだけです。この記録表にGoogle、Brave、DuckDuckGoを含めてはいけません。保留扱いのGoogleの処理経路では、最終的なサイトが分からないリダイレクトアドレスが返されました。これらのアドレスは、リンク先URLとして採用できません。

記録表とは、スナップショットをまとめた表です。この記録表は、Google Search Consoleの平均掲載順位を示すものではありません。すべての人に表示される順位を示すものでもありません。

## Bingの入力を設定する

現在の[Keyword Search Rank Snapshot](https://apify.com/chronometrica/google-search-scraper/examples/keyword-rank-snapshot) Taskには、次の入力が保存されています。

```json
{
  "queries": ["best CRM", "small business accounting software", "AI marketing tools"],
  "engines": ["google", "bing", "brave", "duckduckgo"],
  "maxResultsPerExecutedQuery": 20,
  "country": "US",
  "language": "en",
  "safeSearch": true,
  "includeSponsoredResults": false
}
```

Bingの入力を設定する

queriesのリスト全体を置き換えます。enginesのリスト全体を置き換えます。最初の確認では、調べたいクエリを1つ使います。enginesを["bing"]に設定します。maxResultsPerExecutedQueryを2に設定します。countryとlanguageには、今後も繰り返し使う組み合わせを設定します。safeSearchはtrueのままにします。includeSponsoredResultsはfalseのままにします。

この入力には、検索を拡張する設定はありません。公開されているページ数上限のフィールドもありません。結果件数の上限はmaxResultsPerExecutedQueryです。ページ数の上限を指定するフィールドを追加してはいけません。

国を指定しても、パーソナライズはなくなりません。パーソナライズとは、Bingが人によって異なる結果を表示することです。国の指定は、その地域のすべての利用者に表示される結果を保証するものではありません。

最初の確認には、次の形式を使います。queriesには、実際に調べる検索語句を入れます。

```json
{
  "queries": ["one intended phrase"],
  "engines": ["bing"],
  "maxResultsPerExecutedQuery": 2,
  "country": "US",
  "language": "en",
  "safeSearch": true,
  "includeSponsoredResults": false
}
```

Bingの入力を設定する

countryとlanguageを変更するのは、変更後の組み合わせを今後も使い続ける場合だけにします。以後のすべてのスナップショットにも、同じ値を記録します。

最初に比較する前に、次の項目を固定します。

- クエリの正確な文字列
- country
- language
- safeSearch
- includeSponsoredResults
- maxResultsPerExecutedQuery

後から上限を変更すると、見かけの順位が変わることがあります。結果の読み取り方を後から変更した場合も同様です。比較するときは、収集範囲を同程度に保ちます。

## 検索結果の各行を読む

1行は、1つの検索エンジン、1つのクエリ、1つの検索結果ページ、1つの掲載位置で観測された1件の結果です。Actorは、1回の実行で複数のクエリを保存できます。それらをウェブサイトごとの1行にまとめることはありません。この方法では、1回の実行にBingのクエリを1つだけ含めます。

以下は、[Google Search Scraper](https://apify.com/chronometrica/google-search-scraper) Actorが出力する行の正確なフィールド名です。

- runId
- country
- language
- safeSearch
- engine
- executedQuery
- page
- rankOnPage
- rank
- title
- canonicalUrl
- resultDomain
- snippet
- isSponsored
- advertiserDomain
- observedAt
- schemaVersion

rankは、その実行で収集したサンプル内での掲載位置です。rankOnPageは、その検索結果ページ内での掲載位置です。pageは、検索結果のページ番号です。

canonicalUrlは、Actorがリンクを整形した後に保存したアドレス文字列です。これは候補となるアドレスです。確認済みのHTMLのrel=canonicalリンクではありません。元のhrefを完全にそのまま写したものでもありません。返された文字列は変更せずに保存します。その文字列がソースの証拠になります。

snippetは、検索結果に表示されたテキストです。リンク先サイトの記事本文ではありません。そのサイトの主張を証明するものでもありません。

isSponsoredは、その行が有料の検索結果かどうかを示します。オーガニック検索結果とは、広告料を支払わずに掲載される結果です。有料の行と無料で掲載される行は分けて扱います。includeSponsoredResultsをfalseに設定している場合、広告の行をオーガニック検索順位として扱ってはいけません。

広告の行にはadvertiserDomainが含まれる場合があります。これは、別のオーガニック検索順位ではありません。

各行のcountry、language、safeSearchは、リクエスト時に指定した条件です。パーソナライズされたすべての結果について保証するものではありません。

Actorはリンク先サイトを開きません。ページ内の余分なテキストをすべて取り除くわけでもありません。引用元の確認、売上の評価、次回実行のスケジュール設定も行いません。リンク先の確認が必要な場合は、自分で確認します。

## 実行サマリーを読む

OUTPUTは実行サマリーです。検索結果の各行とは別に保存されます。両方を確認します。OUTPUTには、次のフィールドがあります。

- queriesRequested
- searchesCompiled
- executionsPlanned
- enginesSuccessful
- enginesFailed
- pagesAttempted
- pagesParsed
- resultsSaved
- engineStatusCounts
- engineResultCounts
- queryResultCounts
- stopReason

このActorで現在行っているBingの対照テストでは、クエリにPython asyncio documentationを使いました。Actorは検索結果ページを1ページ取得しようとし、そのページを解析しました。保存されたのは2行です。どちらの行も、docs.python.orgへの直接URLでした。engineはbingでした。executedQueryは、その語句と完全に一致していました。pageは1でした。一方の行のrankは1で、もう一方の行のrankは2でした。各行にobservedAtがありました。

対照テストのOUTPUTは次のとおりでした。

```json
{
  "queriesRequested": 1,
  "searchesCompiled": 1,
  "executionsPlanned": 1,
  "enginesSuccessful": 1,
  "enginesFailed": 0,
  "pagesAttempted": 1,
  "pagesParsed": 1,
  "resultsSaved": 2,
  "engineStatusCounts": {"bing": {"ok": 1}},
  "engineResultCounts": {"bing": 2},
  "queryResultCounts": {"Python asyncio documentation": 2},
  "stopReason": "result_caps_reached"
}
```

実行サマリーを読む

対照テストの行で確認できている値は、次のとおりです。

| フィールド | 対照テストの値 |
| --- | --- |
| engine | bing |
| executedQuery | Python asyncio documentation |
| page | 1 |
| rank | 1と2 |
| canonicalUrl | docs.python.orgへの直接URLが2件 |
| observedAt | 各行に存在 |

stopReasonの値がresult_caps_reachedであることは、実行が結果件数の上限に達したことを意味します。Bingの検索結果が2件しかないという意味ではありません。

この対照テストで確認するのは、範囲を限定したBingのサンプルです。URL、順位、保存されたクエリ、検索結果ページ、時刻を確認します。Google、Brave、DuckDuckGoはテストしていません。すべての検索演算子をテストしているわけではありません。すべての国をテストしているわけでもありません。後から再度順位を確認していません。順位変動も測定していません。アクセス数も測定していません。リンク先サイトからの抽出も行っていません。

enginesFailedが0でない場合、対象が存在しないと判断してはいけません。失敗したクエリでは、対象が存在しないという状態は使えません。

サンプルが空でも、Bing全体を網羅したことにはなりません。上限到達、失敗、結果なしという結果が示すのは、その実行の状況だけです。

## 8つの手順でスナップショットを比較する

### 1. 対象と、少数の固定クエリのリストを決めます。

順位変動を見る前に対象を決めます。特定ページを対象にする場合は、アドレスとパスを1つ指定します。ドメインを対象にする場合は、1つのホストで対象として認めたページのうち、順位が最も高いページを使います。判断にどちらを使うかを明記します。少数の固定リストを使うとは、同じ語句で繰り返し検索することです。最初の確認では、引き続き1つの語句とBingだけを使います。語句を追加する場合は、同じ設定で、その語句専用の固定行を作ります。

範囲を限定したBingの記録表は、Google Search Consoleの平均掲載順位を示すものではありません。すべての人に表示される順位を示すものでもありません。

### 2. 検索エンジンをBingに固定し、サンプルの設定を固定します。

Taskの検索エンジンのリストを、engines ["bing"]に置き換えます。最初の確認では、サンプルのクエリを、調べたい1つのクエリに置き換えます。この試行ではmaxResultsPerExecutedQueryを2に設定します。country、language、safeSearch、includeSponsoredResults、結果件数の上限を固定します。

同じ語句でも、国が異なれば別の条件のスナップショットです。セーフサーチの有効時と無効時も別の条件のスナップショットです。上限が2の場合と10の場合も別の条件のスナップショットです。国を指定しても、その地域のすべての利用者に表示される結果を保証するものではありません。

### 3. 成功した行とOUTPUTを確認します。

成功した各行のexecutedQuery、rank、rankOnPage、page、observedAtを保存します。それらと併せて、OUTPUTの件数とstopReasonを保存します。現時点の小規模な対照テストには、検索結果の1ページ目に順位付きの直接URLが2件あります。この対照テストは、自分のページの順位変動を測定したものではありません。

クエリが失敗した場合、対象に「存在しない」という状態を割り当ててはいけません。代わりにsource_failedを保存します。

### 4. 決めた基準で対象との一致を確認します。

特定ページについては、指定したアドレスとパスの一致ルールで照合します。返されたcanonicalUrlをそのまま保存します。返された文字列を変更してはいけません。

ドメインについては、対象のホストと一致するかを確認します。そのホストの行のうち、対象として認めたオーガニック検索結果から、最も小さいrankを保存します。その最小値が、サンプル内で観測されたドメインの最高順位です。

似た会社名を同じ対象にまとめてはいけません。異なるサブドメインを同じ対象にまとめてはいけません。追跡用リダイレクトは、そのリダイレクトを確認してリンク先を対象として認めた場合を除き、同じ対象にまとめてはいけません。同一の対象かどうかが不明な場合、状態はunresolved_targetです。

### 5. 状況に合った状態を1つ保存します。架空の順位は絶対に保存しません。

対象が行と一致する場合はobserved_rankを使います。有用なサンプルとは、正常に完了し、上限が記録された実行のサンプルです。そのサンプルに対象が含まれていない場合はnot_seen_within_capを使います。収集が失敗した場合はsource_failedを使います。ある行が対象かどうかを判断できない場合はunresolved_targetを使います。

0を使ってはいけません。cap + 1を使ってはいけません。これらの数値は順位のように見えますが、観測された順位ではありません。

試行の上限が2の場合、対象が見つからなければ、上限2でのnot_seen_within_capです。そのページは、もっと後に表示されるかもしれません。実際の順位は不明のままです。後からより大きい上限に固定した場合も、同じルールを適用します。

### 6. 後日、同じ入力で再実行します。

そのための予算を使うと決めたときに、固定した入力で再実行します。新しいスナップショットは、[新しい観測記録](/ja/articles/bing%E6%A4%9C%E7%B4%A2%E7%B5%90%E6%9E%9C%E3%81%AE%E9%87%8D%E8%A4%87%E6%95%B4%E7%90%86/)として保存します。古い記録を上書きしてはいけません。

Task自体が順位を監視するわけではありません。定期実行には、別途スケジュールを明示的に設定する必要があります。同じクエリと、同じ対象の一致ルールで比較します。country、language、safeSearchには同じ値を使います。広告を含める設定を同じにし、収集範囲も同程度に保ちます。

上限が変わった場合、その組み合わせを比較可能と見なしてはいけません。結果の読み取り方が変わった場合も、その組み合わせを比較可能と見なしてはいけません。

### 7. 2つの順位が分かっている場合だけ、順位変動を計算します。

順位変動は単純な引き算で求めます。順位変動 = 以前の順位 - 新しい順位です。結果が正の値なら、新しい順位の数値が小さくなったことを意味します。その検索結果は、古いサンプルより新しいサンプルのほうで先に表示されています。

not_seen_within_capを、この引き算に含めてはいけません。source_failedとunresolved_targetも除外します。不明な値を実際の順位と一緒に平均してはいけません。0やcap + 1などの代用の数値を平均してはいけません。

このサンプル内の順位が変わっても、アクセス数の変化を証明することにはなりません。売上の変化を証明することにもなりません。コンテンツの編集がその変化を引き起こしたと証明することにもなりません。

### 8. 記録表を提出し、確認できる比較の範囲にとどめます。

クエリと対象の一致ルールの組み合わせごとに、記録表を1行作ります。取得元の実行、条件、上限、状態、比較についての注記を含めます。Googleやその他の検索エンジンは、別の場所に記録します。この記録表でそれらについて主張してはいけません。

条件が一致する1組を示して終えるか、比較結果を確定できないと記載します。推測した順位で不足を埋めてはいけません。

## 架空の順位記録表

以下の表は、説明のために独自に作った架空の例です。状態の使い分けを学ぶためのものです。Actorの実行結果ではありません。上記のBingの対照テストでもありません。架空の対象ページはhttps://garden.example/guideです。架空のドメインはgarden.exampleです。S1は古いスナップショットです。S2は新しいスナップショットです。Q1の両スナップショットは、同じBing設定と、上位10件という同じ上限を使っています。試行の上限2とは範囲が異なります。これらの上限を混在させてはいけません。日付は与えられていないため、表示していません。

Q1では、特定のガイドページを比較します。S1では順位7を観測しています。S2では順位4を観測しています。どちらの順位も、上位10件という同じ範囲のサンプル内にあります。順位変動 = 7 - 4 = +3です。この定義では、そのページはサンプルの先頭に向かって3つ順位を上げました。

Q2では、同じ特定ページと、同じ上限10を使います。S1では順位2を観測しています。S2は、上限10でのnot_seen_within_capです。新しい順位は不明です。順位変動も不明です。11を保存してはいけません。そのページは10位より後に掲載されているかもしれません。後の何位にあるかは分かりません。

Q3でも、同じ特定ページを使います。S1の順位と時刻は与えられていないため、S1は不明のままです。S2はsource_failedです。比較はできません。これは順位低下ではありません。失敗とは、新しいサンプルを収集できなかったことです。

Q4は、ドメインについての1つのスナップショットです。順位変動を調べるための2つの記録ではありません。そのドメインで対象として認めた2つのページのオーガニック検索順位は、3と8です。対象がドメインなら、観測された最高順位は3です。対象が特定のガイドページなら、そのページの順位は8である可能性があります。同時に、同じドメインの別のページが順位3である場合もあります。どちらの定義を使うかを明記します。特定ページの順位として3を報告してはいけません。

| クエリ | 対象の一致ルール | S1の状態 | S2の状態 | 順位変動 | 根拠の範囲内で言えること |
| --- | --- | --- | --- | --- | --- |
| Q1 | 特定ページ https://garden.example/guide | observed_rank 7 | observed_rank 4 | 7 - 4 = +3 | 上位10件という同じ範囲のサンプル内で、両方の順位が判明 |
| Q2 | 特定ページ、上限10 | observed_rank 2 | not_seen_within_cap 10 | 不明 | 順位11ではなく、順位変動も2 - 11ではない |
| Q3 | 特定ページ | 不明 | source_failed | 不明 | 比較不可。順位低下ではない |
| Q4 | ドメインgarden.example、または特定のガイドページ | 1つのスナップショット：対象として認めた順位は3と8 | 同じスナップショット。別の時点の記録ではない | なし | ドメインの最小順位は3。特定のガイドページは順位8の場合がある |

Q2の順位を11と作り上げる人がいるかもしれません。その人は、次に2 - 11 = -9と計算するかもしれません。その-9は観測値ではありません。Q1の+3と、その架空の-9を平均すると、誤った要約になります。まず、両方の順位が分かっている組を示します。次に、サンプルの範囲内では対象が見つからなかったことを示します。収集元での失敗も示します。不明な状態は、どの平均計算からも除外します。

これらのS1とS2の値は、説明用の記録表の状態です。対照テストの順位フィールドに実際に保存された値ではありません。その対照テストが保存した順位は、1と2だけです。順位変動は測定していません。

## 次にすること

正確なクエリ、国、言語、safeSearchの設定、広告を含める設定、結果件数の上限とともに、Bingのスナップショットを1つ保存します。対象について、状況に合った状態を1つ記録します。状態は、順位を観測済み、上限内では未確認、収集元で失敗、対象を特定できず、のいずれかです。[Google Search Scraper](https://apify.com/chronometrica/google-search-scraper) Actorと、現在の[Keyword Search Rank Snapshot](https://apify.com/chronometrica/google-search-scraper/examples/keyword-rank-snapshot) Taskから始めます。比較を始める前に、そのTaskをクエリ1つ、engines ["bing"]に変更します。

## 出典と参考資料

- [Google Search Scraper](https://apify.com/chronometrica/google-search-scraper)
- [Keyword Search Rank Snapshot](https://apify.com/chronometrica/google-search-scraper/examples/keyword-rank-snapshot)
- [https://www.reddit.com/r/SEO/comments/1dybuk8/any_tools_to_just_monitor_specific_keyword_ranking/](https://www.reddit.com/r/SEO/comments/1dybuk8/any_tools_to_just_monitor_specific_keyword_ranking/)
- [https://www.reddit.com/r/SEO/comments/1d5kve4/how_to_check_if_you_ranked_on_a_keyword/](https://www.reddit.com/r/SEO/comments/1d5kve4/how_to_check_if_you_ranked_on_a_keyword/)