2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【就活・転職効率化】OpenWorkで「回答者数・年収」を自動表示&右クリックで即検索できるChrome拡張を作った

Last updated at Posted at 2025-11-22

はじめに

転職活動や企業研究で OpenWork(旧Vorkers)を使っている方は多いと思います。
企業の「総合評価スコア」が一目でわかるのは非常に便利ですが、検索結果一覧を見ているときにふと気になることがありませんか?

「この高スコア、何人の回答に基づいているの?」
「平均年収はどのくらいなんだろう?」

スコアが 4.0 でも、回答者が 3人 なのか 300人 なのかで、その信頼性は大きく異なります。
また、年収情報も企業選びの重要な判断材料ですが、現在のOpenWorkの検索結果画面(企業一覧)では、回答者数(口コミ数)も平均年収も 表示されません。詳細ページに飛ばないと確認できない仕様になっています。

これでは「良さそうな企業だと思ってクリックしたら、回答数が少なすぎて参考にならなかった…」「年収が想定より低かった…」ということが頻発し、効率が悪いです。

そこで、検索結果画面に「回答者数」と「平均年収」を自動で表示するChrome拡張機能 を自作しました。
本記事では、このツールの紹介と、実装にあたって工夫した 「スクレイピングの負荷対策(Rate Limiting)」「パフォーマンス最適化(IntersectionObserver)」 の技術的なポイントを解説します。


ツール紹介

機能概要

この「OpenWork クイック検索」 拡張機能をインストールすると、OpenWorkの企業検索結果一覧において、総合スコアの横に (XX人)💰XXX万円 という形で回答者数と平均年収が自動的に追加表示されます。

微信图片_2025-11-22_121405_468.png

(※イメージ: スコアの横にバッジが表示される)

もう一つの便利機能:右クリックで一発検索

求人サイト(GreenやWantedlyなど)を見ているときに、「この会社の評判どうなんだろう?」と思うことはありませんか?
通常なら 「社名をコピー」→「OpenWorkを開く」→「検索窓にペースト」→「検索」 という手順が必要で、地味に面倒です。

この拡張機能を入れると、社名を選択して右クリックするだけ で、直接OpenWorkの検索結果に飛べるようになります。

微信图片_2025-11-22_121839_052.png

(※イメージ: 右クリックメニューに「OpenWorkで検索」が表示される)

主な特徴

  1. 自動表示: ページを開くだけで、各企業の詳細ページから回答者数を取得して表示します
  2. 右クリック検索: 任意のWebページでテキストを選択し、右クリックメニューから即座にOpenWork検索が可能です。
  3. キャッシュ機能: 一度取得したデータは localStorage に保存されます。次回以降はAPIリクエスト(詳細ページへのアクセス)が発生しないため、高速かつサーバーに優しい設計です
  4. サーバー負荷対策: 検索結果には数十件の企業が並びますが、一気に数十件のリクエストを送るとサーバーに負荷がかかり、最悪の場合IPBANされるリスクがあります。そのため、リクエストキュー(Queue) を実装し、一定間隔(例: 3秒に1回)でゆっくりデータを取得するようにしています

実装のポイント

Chrome拡張機能(Manifest V3)として実装しました。
特に「サーバーに迷惑をかけない」「ブラウザを重くしない」という点に注力しました。

1. Rate Limiting (リクエストキュー)

検索結果ページには多くの企業が表示されますが、Promise.all などで一斉に fetch すると、短期間に大量のアクセスが発生してしまいます。これを防ぐため、直列実行するキュー を作成しました。

// 簡易的な非同期キューの実装
class Queue {
  constructor(n = 1, delay = 3000) { 
    this.n = n;         // 同時実行数(今回は1)
    this.delay = delay; // 実行間隔(ms)
    this.busy = 0;
    this.q = [];
  }

  push(task) {
    this.q.push(task);
    this.run();
  }

  async run() {
    if (this.busy >= this.n || this.q.length === 0) return;
    this.busy++;
    const fn = this.q.shift();
    try {
      await fn();
    } finally {
      this.busy--;
      // 次のタスクまで指定時間待機
      setTimeout(() => this.run(), this.delay);
    }
  }
}

// 3秒に1回だけリクエストを実行するキュー
const queue = new Queue(1, 3000);

このようにすることで、ユーザーがスクロールして大量の企業が表示されても、バックグラウンドでは「3秒に1件ずつ」お行儀よくデータを取得しに行きます。

2. Lazy Loading (IntersectionObserver)

ページ下部の企業まで最初から取得する必要はありません。「ユーザーの画面に見えている企業だけ」 データを取得すれば十分です。
そこで IntersectionObserver を使い、要素が画面内に入ったタイミングでキューにタスクを追加するようにしました。

const observer = new IntersectionObserver(entries => {
  entries.forEach(e => {
    if (e.isIntersecting) {
      // 画面に入ったら処理開始
      handleCard(e.target);
      // 一度処理したら監視を解除
      observer.unobserve(e.target);
    }
  });
}, { rootMargin: "100px" }); // 少し手前で読み込み開始

// 検索結果の各カード要素を監視
document.querySelectorAll("li.box-15").forEach(c => observer.observe(c));

3. DOM解析の工夫

取得した詳細ページのHTMLから「回答者数」を抜き出す処理も、クラス名が変わってもある程度耐えられるように工夫しています。

function extractResponderCount(html) {
  const doc = new DOMParser().parseFromString(html, "text/html");

  // 1. まずは既知のCSSセレクタで探す
  const sel = '...'; // (省略)
  const el = doc.querySelector(sel);
  if (el) return parseNumber(el.textContent);

  // 2. 見つからない場合、TreeWalkerで「回答者」という文字を含むテキストノードを探す(兜底)
  const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT);
  // ... (周辺の数字を探すロジック)
}

まとめ

今回は、OpenWorkの検索結果をより便利にするChrome拡張機能を紹介しました。
技術的には Queueによる流量制御IntersectionObserverによる遅延読み込み を組み合わせることで、実用性と安全性を両立させています。

もし「自分も使ってみたい!」という方がいれば、ぜひ試してみてください。(※自己責任でお願いします)

今後の展望

  • キャッシュの有効期限(TTL)の実装
  • 取得状況(Loading/Error)のUI改善

※本記事は技術共有を目的としており、スクレイピングを推奨するものではありません。利用規約を遵守してご利用ください。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?