【ITニュース解説】Filtering Freelance Leads: Recency Windows and Job‑Board Rules in My Home‑Hosted Scanner
2026年10月31日に「Dev.to」が公開したITニュース「Filtering Freelance Leads: Recency Windows and Job‑Board Rules in My Home‑Hosted Scanner」について初心者にもわかりやすく解説しています。
ITニュース概要
フリーランスの求人情報を効率的に探すため、ラズパイ上で動作するNode.jsシステムを開発。複数の求人サイトから情報を自動収集し、鮮度やサイト特有のノイズを除去するフィルタリングを適用。最新かつ関連性の高い求人のみをSlackに通知し、不要な情報に惑わされずに仕事探しができる仕組みを解説した記事。
ITニュース解説
フリーランスとして仕事を探す際、多くの人が古い求人情報や自分には関係のない情報に埋もれてしまい、本当に価値のある案件を見つけるのに苦労するという課題に直面する。また、複数の求人サイトを利用すると、それぞれ情報の形式が異なり、効率的な情報収集が難しいという問題も生じる。この記事では、これらの課題を解決し、常に新鮮で自分に合った仕事の機会を自動的に見つけ出し、通知するシステムの構築方法が解説されている。
このシステムは、自宅に設置された小型コンピューター「ラズベリーパイ」上で動作する。具体的には、30分ごとにNode.jsというプログラミング言語で書かれたスクリプトが自動的に実行されるよう設定されている。このスクリプトは、まず複数のフリーランス向け求人サイト(Upwork、Freelancer、Guruなど)から求人情報を取得する。次に、取得した形式の異なる情報を、システム内で統一的に扱える共通の形に「正規化」する。その後、正規化された情報の中から不要なものを排除する「フィルター処理」を適用し、最終的にフィルターを通過した本当に価値のある情報だけを、日頃使っているコミュニケーションツールであるSlackに自動で通知する仕組みである。これにより、利用者は手作業なしで常に最新の仕事の機会を得ることができる。
システムの第一段階は、求人情報の取得とその「正規化」である。各求人サイトは異なるAPI(情報取得の窓口)を提供しているため、それぞれに対応した方法で情報を取得する必要がある。ここで重要なのが「正規化」のプロセスだ。例えば、各サイトから得られる求人情報には、案件のID、タイトル、投稿日時、予算、詳細な説明、案件のURLといった項目が含まれるが、これらの項目の名前やデータの形式はサイトによって異なる。このシステムでは、取得したすべての情報を、id、title、board(どのサイトから来たかを示す)、postedAt(投稿日時)、budget(予算)、description(詳細)、url(リンク)という共通のフィールド名を持つ統一された形式に変換する。この正規化により、その後のフィルター処理のコードを、どの求人サイトの情報であっても同じように適用できるようになり、システム全体の柔軟性が向上する。フィルター処理のロジックは、filters.jsという一つのファイルに集約されており、管理や修正がしやすいように工夫されている。
次に、取得した情報の中から「古い情報」を除外するための「鮮度ウィンドウ」というフィルターが適用される。これは、「投稿されてから指定された時間(例えばN分)以内に限って、その求人情報を有効なものとして残す」というシンプルなルールである。求人サイトはそれぞれ情報の更新頻度が異なるため、この鮮度ウィンドウの時間もサイトごとに調整する必要がある。例えば、Upworkからの情報は過去60分以内、Freelancerは過去30分以内、Guruは過去120分以内といった具体的な時間を、recency.jsonという設定ファイルに記述しておく。システムはこのJSONファイルを読み込むことで、求人情報がそれぞれのサイトに設定された鮮度ウィンドウ内にあるかを判断する。この方法の大きな利点は、鮮度基準を変更したい場合に、プログラムのソースコードを修正することなく、この設定ファイルを編集するだけで済む点にある。これにより、システムの運用が非常に柔軟になり、状況に合わせて素早く調整できる。
鮮度フィルターだけでなく、各求人サイトにはそれぞれ特有の「ノイズ」、つまり応募には不適当な情報や誤解を招くパターンが存在する。このシステムでは、そのような「サイトごとの癖」に対応するための個別のルールも用意されている。例えば、Upworkでは予算が「0ドル」と表示される求人が多いが、これらは通常「時給非公開」を意味し、具体的な予算が不明なため応募しにくい。そのため、タイトルに「固定価格(fixed-price)」というキーワードが含まれていない限り、予算が0ドルの求人は除外するルールが設けられている。また、FreelancerのAPIからは、同じプロジェクトにもかかわらず異なるURLを持つ「重複した求人情報」が送られてくることが頻繁にある。このような場合は、最初に見つかったものだけを有効とし、それ以降の重複は破棄する。Guruサイトでは、募集がすでに「closed(終了)」しているにもかかわらずフィードに表示される案件があるため、求人のステータスフィールドを確認し、「closed」と判断されたものは除外するルールを追加する。これらのルールは、それぞれ小さな判断を行う関数として実装され、特定の求人サイトの情報が該当するかどうかを効率的に判定する。
これらの「鮮度ウィンドウ」フィルターと「サイト固有のルール」は、「フィルターパイプライン」という形で連携して適用される。まず、すべての正規化された求人情報が「鮮度ウィンドウ」フィルターを通過し、古い情報が除外される。次に、生き残った情報に対して、その情報がどの求人サイトから来たものかに応じて、適切なサイト固有のルールが適用される。例えば、Freelancerの重複検出ルールでは、既に処理済みの求人IDを記録する一時的なリストを活用し、同じIDの求人が再度現れたらそれを除外するといった処理が実行される。このように複数のフィルターを段階的に適用することで、最終的に残るのは、新しく、かつ各サイトのノイズも排除された、本当に価値のある求人情報だけとなる。この多段階のフィルター処理が、収集した生データの中から必要な情報を正確に選び出す上で不可欠な役割を果たす。
構築されたシステムは、自宅のラズベリーパイ上で安定して動作するよう工夫されている。Node.jsスクリプトはcrontabというツールによって30分ごとに自動実行されるようスケジュールされており、またpm2というツールは、スクリプトが万が一停止しても自動的に再起動してくれるため、システムが常に稼働し続けることが保証される。システムのソースコードは、Gitというバージョン管理システムを使ってラズベリーパイ上で管理されている。もしプログラムを更新する必要が生じても、git pullコマンドで最新のコードを取得し、pm2 restartコマンドで簡単にシステムを再起動するだけで変更が適用される。Slackへの通知に必要なウェブフックURLのような機密情報は、ソースコード内に直接記述するのではなく、環境変数として設定することで、セキュリティを保ちつつ、運用環境に合わせた柔軟な設定変更が可能になっている。
このシステムを開発し運用する中で、いくつかの重要な知見が得られた。一つは「フィルター関数の純粋性」を保つことである。フィルター関数内で外部とのやり取り(ファイル読み書きやネットワーク通信)を行わず、ひたすら「入力されたデータが条件を満たすか」を判断するだけのシンプルな役割に徹することで、個々のフィルターを独立してテストしやすくなり、ルール変更時の不意のバグ発生を防ぐことができる。二つ目は「設定をコードから分離する」ことの重要性だ。頻繁に調整する可能性がある鮮度ウィンドウのような値は、JSONファイルなどの設定ファイルで管理することで、プログラム本体を変更せずに、設定だけを調整するだけで済むようになり、システムの運用効率が大幅に向上する。そして三つ目は、「求人サイトのAPIは変化する」という点への対応である。APIの仕様は時間とともに変わる可能性があるため、月に一度「健全性チェック」を行い、APIの変更点や新しいフィールドがないかを確認し、必要に応じてフィルターのルールを更新していくことが、システムを長期的に機能させる上で非常に重要となる。
結論として、この自動化システムは、古く不要な求人情報に埋もれることなく、価値のある仕事の機会を見つけるための効果的なソリューションを提供する。情報を取得する部分、共通の形式に整える部分、そしてフィルター処理を行う部分という各機能を明確に分離して設計することで、システムは拡張しやすく、信頼性が高く、そして安価な自宅サーバー上で効率的に運用できるものとなった。このようなモジュール化された設計は、将来的に新しい求人サイトを追加したり、より複雑なフィルター条件を導入したりする際にも、システム全体の安定性を保ちながら柔軟に対応できる強固な基盤となる。