求人ボードのパーシングは、HR分析、市場監視、リクルーティングの自動化のためのデータ収集シナリオの中で最も需要の高いものの一つです。しかし、求人情報サイトは自動データ収集からの保護を強化しており、50-100のリクエスト後にIPをブロックし、キャプチャを表示し、疑わしいアカウントを禁止します。この記事では、hh.ru、Superjob、LinkedInなどのサイトでの安定したパーシングのためのプロキシの正しい設定方法を説明します。
なぜ求人ボードはパーシングをブロックするのか、そして保護はどのように機能するのか
求人情報サイトはパーシングによってお金を失っています:データが競合に販売され、無許可のアグリゲーターが作成され、雇用主が有料掲載を回避します。したがって、すべての主要なサイトは自動データ収集からの多層的な保護を導入しました。
求人ボードの主な保護手段:
- IPによるレート制限 — hh.ruは1時間に80-120リクエストの後にIPをブロックし、Superjobは50-70リクエストの後にブロックします。ブロックは1時間から1日続くことがあります。
- ブラウザのフィンガープリンティング — サイトはUser-Agent、HTTPヘッダー、画面解像度、インストールされたフォントを分析します。データが実際のブラウザと一致しない場合、リクエストはブロックされます。
- JavaScriptチェック — 多くのサイトは、リクエストが本物のブラウザから来ているかどうかを確認するためにCloudflareや独自のスクリプトを使用しています。
- ハニーポットトラップ — パーサーだけが見ることができる隠れたリンクやフィールドです。ボットがそれらにアクセスすると、IPはブラックリストに登録されます。
- 疑わしい活動時のキャプチャ — 一連の迅速なリクエストの後やデータセンターのIPを使用している場合に表示されます。
プロキシなしでは、最大100-200の求人情報をパースすることができますが、その後あなたのIPは禁止されます。大規模なデータ収集(毎日数千の求人情報)のためには、プロキシは必須のツールとなります。
重要: パーシングはサイトの利用規約に準拠している必要があります。多くの求人ボードは、データへの合法的なアクセスのための公式APIを提供しています。たとえば、hh.ruには、ほとんどのタスクに適したリクエスト制限のある無料APIがあります。
求人情報のパーシングにどのプロキシタイプを選ぶべきか
プロキシの種類の選択は、パーシングの規模、予算、速度の要件によって異なります。具体的な使用シナリオを持つ3つの主要なオプションを見ていきましょう。
| プロキシタイプ | 速度 | 禁止のリスク | 使用するタイミング |
|---|---|---|---|
| データセンター | 高速(50-200 ms) | 高い | パーサーのテスト、認証なしの公開データの収集 |
| レジデンシャル | 中程度(200-800 ms) | 低い | IPローテーションを伴うhh.ru、Superjobの大規模パーシング |
| モバイル | 中程度(300-1000 ms) | 非常に低い | 認証付きのパーシング、LinkedInの厳しい保護の回避 |
パーシング用のデータセンターのプロキシ
これは最も速くて安価なオプションですが、制限があります。データセンターのIPはサイトによって簡単に認識されるため、認証なしの求人リストのパーシング、公開データの収集、レジデンシャルプロキシでの実行前のパーサーのテストなど、簡単なタスクにのみ適しています。
データセンターのプロキシが機能する場合:
- 小規模なデータのパーシング(1日あたり500件までの求人)
- 厳しい保護のないサイトからのデータ収集(小規模な地域の求人ボード)
- レート制限を回避するためのIPローテーションを伴う公式APIの使用
- RSSフィードや求人のXMLファイルのパーシング
hh.ruやSuperjobに対しては、データセンターのプロキシは不安定に機能します:20-30リクエスト後にキャプチャが表示され、多くのIPはすでにこれらのサイトのブラックリストに登録されています。
レジデンシャルプロキシ — 求人ボードに最適な選択
レジデンシャルプロキシは、実際の家庭ユーザーのIPアドレスを使用するため、サイトはそれを通常の訪問者として認識します。これは求人情報のパーシングにおける価格と品質の最適なバランスです。
求人ボードのパーシングにおける利点:
- 低いブロックリスク — hh.ruやSuperjobはレジデンシャルIPを実際のユーザーと区別できません
- 大規模なIPプール — 各リクエストごとにローテーションを設定するか、5-10分ごとに変更できます
- 地理的な関連性 — 特定の都市の求人を、その地域のIPを使用してパーシングできます
- 安定性 — 1つのレジデンシャルIPは200-500リクエストをブロックなしで処理できます
大規模なパーシング(1日あたり1000件以上の求人)には、IPローテーションを伴うレジデンシャルプロキシが標準的な解決策です。IPを5-10分ごとに変更し、リクエスト間にランダムな遅延(3-7秒)を追加することで、ブロックなしで安定したデータ収集を実現します。
LinkedInおよび認証付きパーシング用のモバイルプロキシ
モバイルプロキシは、モバイルオペレーターのIPを使用します。彼らの主な利点は、1つのIPが同時に数百の実際のユーザーによって使用されるため、サイトはそのアドレスをブロックすることができず、通常の訪問者をブロックするリスクがあります。
モバイルプロキシが必要な場合:
- LinkedInのパーシング — このプラットフォームはボットに対して最も厳しい保護を持ち、データセンターやレジデンシャルIPを積極的にブロックします
- 認証付きの作業 — 非公開の求人やプロフィールデータをパーシングする必要がある場合、モバイルIPはアカウントのブロックリスクを低減します
- 海外の求人ボードのパーシング — Indeed、Glassdoor、Monsterは高度な保護システムを使用しており、モバイルIPがより信頼性があります
- 厳しいブロックの回避 — レジデンシャルプロキシがキャプチャを受け始めた場合、モバイルに切り替えることで問題を解決できます
モバイルプロキシの欠点は、高価格と低速です。しかし、ブロックが許されない重要なタスクには、これが最良の選択です。
hh.ruのパーシングの特徴:保護と回避方法
hh.ruは、国内の求人ボードの中で最も高度なパーシング保護を持つロシア最大の求人情報サイトです。このサイトは、ボットを特定するためにレート制限、フィンガープリンティング、行動分析の組み合わせを使用しています。
hh.ruの保護の仕組み
1. IPアドレスによる制限: 1つのIPからの1時間あたり80-120リクエストの後、サイトはキャプチャを表示するか、HTTP 429(リクエストが多すぎます)を返します。ブロックは、パーシングの攻撃性に応じて1時間から6時間続きます。
2. User-Agentとヘッダーのチェック: hh.ruはHTTPリクエストのヘッダーを分析します。User-Agentが実際のブラウザに一致しない場合や、標準のヘッダー(Accept-Language、Accept-Encoding)が欠落している場合、リクエストはブロックされます。
3. JavaScriptチェック: hh.ruの一部のページは、データを読み込むためにJavaScriptの実行を必要とします。ヘッドレスブラウザなしの単純なHTTPパーサーでは完全なコンテンツを取得できません。
4. ハニーポットリンク: ページには、パーサーだけが見ることができる隠れた要素があります。スクリプトがこれらのリンクにアクセスすると、IPは24時間ブラックリストに登録されます。
プロキシを使用したhh.ruの保護回避戦略
hh.ruをブロックなしで安定してパーシングするには、次の構成を使用します:
hh.ruのパーシングに最適な設定:
- プロキシタイプ: IPローテーションを伴うレジデンシャルプロキシ(5-10分ごと)
- リクエスト間の遅延: 4-8秒(ランダムな値)
- User-Agent: 現代のブラウザ(Chrome、Firefox、Safariの最新バージョン)の実際のUser-Agentのローテーション
- ヘッダー: ブラウザの標準ヘッダーの完全なセット(Accept、Accept-Language、Accept-Encoding、Referer)
- クッキー: 同一セッション内でのリクエスト間のクッキーの保存と送信
- リクエスト制限: 1つのIPあたり60-80リクエストを超えないようにし、その後プロキシを変更
安全な行動の例:
- 必要な地域のIPを持つレジデンシャルプロキシに接続します(例:モスクワ)
- hh.ruのホームページに最初のリクエストを行い、クッキーを取得して保存します
- 5-7秒待機します(ページを読むふりをします)
- 必要なフィルターを使用して求人検索ページにリクエストを行います
- 求人リストをパーシングします(通常はページあたり20-50件)
- 各求人について、4-6秒の遅延を持って詳細ページにリクエストを行います
- 60-70リクエスト後にプロキシを変更し、サイクルを繰り返します
この戦略を使用すると、1つのスレッドから1日に1000-2000件の求人をブロックなしでパーシングできます。より多くのボリュームが必要な場合は、異なるプロキシを使用して複数の並行スレッドを起動します。
アドバイス: hh.ruは求人情報へのアクセスのための無料APIを提供しています。ほとんどのタスク(労働市場の分析、給与の監視)には、APIがHTMLパーシングよりも安定した解決策となります。プロキシはAPIを使用する際にIPをローテーションするために使用できます。
Superjob、LinkedIn、海外サイトのパーシング
Superjob:保護の特徴
Superjobはhh.ruと比較して保護が緩やかですが、それでもパーシングに対して積極的に対抗しています。主な違いは以下の通りです:
- より低いレート制限: 1時間あたり50-70リクエストの後にブロックされます(hh.ruの80-120に対して)
- ヘッダーのチェックが緩やか: 簡略化されたヘッダーセットを使用できます
- JavaScript保護がない: ほとんどのデータはヘッドレスブラウザなしの単純なHTTPリクエストでアクセス可能です
- 地域ブロック: 一部の求人は特定の地域のIPからのみアクセス可能です
Superjobには、10-15分ごとにローテーションし、リクエスト間の遅延を3-5秒に設定したレジデンシャルプロキシで十分です。これにより、1日に500-1000件の求人を安定してパーシングできます。
LinkedIn:最も厳しい保護
LinkedInは別の話です。このプラットフォームは、ボットを特定するために高度な機械学習アルゴリズムを使用しており、すべてのソーシャルネットワークや求人ボードの中で最も攻撃的な保護システムを持っています。
LinkedInの保護の特徴:
- 必須の認証: ほとんどのデータは認証されたユーザーのみがアクセス可能です
- 行動分析: LinkedInは行動パターンを分析します:スクロール速度、マウスの動き、ページ上の時間
- アカウントのブロック: 疑わしい活動があった場合、IPだけでなくアカウント自体もブロックされます
- プロフィールの閲覧制限: 無料アカウントは月に限られた数のプロフィールしか閲覧できません
- JavaScriptの実行が必須: ヘッドレスブラウザなしではパーシングは不可能です
LinkedInのパーシング戦略:
- モバイルプロキシを使用する — 最も低いブロックリスクを提供します。1つのモバイルIPは1日に100-200のプロフィールを閲覧するために使用できます。
- ヘッドレスブラウザが必須 — PuppeteerやPlaywrightを使用し、実際のブラウザのフィンガープリンティングを設定します(画面解像度、WebGL、Canvas)。
- パーシングの速度を遅くする — 1つのアカウントから1時間あたり20-30のプロフィールを超えないようにします。プロフィールの閲覧間に10-20秒の遅延を追加します。
- 実際の行動を模倣する — ページのスクロール、ランダムなクリック、プロフィールセクション間の移動。
- アカウントのウォームアップ — 新しいLinkedInアカウントはすぐにパーシングに使用できません。通常のユーザーの活動を模倣する必要があります(1-2週間)。
- アカウントのローテーション — 異なるプロキシを使用して複数のアカウントを使用し、負荷を分散します。
LinkedInのパーシングは、すべての求人ボードの中で最も難しいタスクです。このプラットフォームからデータが必要な場合は、公式のSales Navigator APIの使用や、合法的にデータを提供するサードパーティサービスの利用を検討してください。
海外の求人ボード:Indeed、Glassdoor、Monster
海外のサイトは通常、ロシアのサイト(hh.ruを除く)よりも厳しい保護を持っています。主な特徴は以下の通りです:
- Indeed — Cloudflareを使用し、JavaScriptチェックを行います。ヘッドレスブラウザと、求人をパーシングする国のレジデンシャル/モバイルプロキシが必要です。
- Glassdoor — ほとんどのデータを閲覧するために認証が必要です。データセンターのIPを積極的にブロックします。レジデンシャルプロキシと遅いパーシング速度(8-12秒の遅延)を使用してください。
- Monster — パートナー向けにAPIを提供していますが、HTMLをパーシングするには、必要な国に地理的に関連するレジデンシャルプロキシが必要です。
すべての海外プラットフォームでは、プロキシの地理的関連性が重要です。アメリカで求人をパーシングする場合は、アメリカのレジデンシャルIPを使用してください。他の国のIPからのリクエストは疑念を引き起こし、ブロックされる可能性があります。
IPのローテーションとリクエスト間の遅延の設定
プロキシのローテーションの正しい設定は、ブロックなしで安定したパーシングの鍵です。2つの主要な戦略を見ていきましょう:リクエストごとのローテーションと時間によるローテーションです。
リクエストごとのローテーション(Rotating Proxies)
このアプローチでは、各HTTPリクエストが新しいIPアドレスから行われます。これは最も安全な方法ですが、制限があります:
利点:
- 1つのIPの活動を追跡することは不可能です
- 単位時間あたりのリクエスト数を増やすことができます
- 各IPの制限を追跡する必要がありません
欠点:
- セッションを保存することはできません(IP変更時にクッキーが失われます)
- 認証付きのパーシングには適していません
- IPが頻繁に変更されると、一部のサイトがリクエストをブロックします
リクエストごとのローテーションは、認証なしでhh.ruやSuperjobの公開ページをパーシングするのに適しています。通常、プロキシプロバイダーのパラメータを介して設定されます(通常は自動ローテーション用の特別なエンドポイントです)。
時間によるローテーション(Sticky Sessions)
このアプローチでは、1つのIPが特定の時間(5-30分)使用され、その後自動的に変更されます。これは、求人ボードのパーシングタスクのほとんどに最適なオプションです。
推奨されるローテーション間隔:
| サイト | ローテーション間隔 | IPあたりの最大リクエスト数 | リクエスト間の遅延 |
|---|---|---|---|
| hh.ru | 5-10分 | 60-80 | 4-8秒 |
| Superjob | 10-15分 | 50-70 | 3-5秒 |
| 30-60分 | 20-40 | 10-20秒 | |
| Indeed | 10-20分 | 40-60 | 5-10秒 |
| Glassdoor | 15-30分 | 30-50 | 8-12秒 |
ランダムな遅延の設定
リクエスト間の固定遅延(例えば、正確に5秒)は、保護システムにとって疑わしく見えます。実際のユーザーはそのような正確さで行動することはできません。常に範囲内のランダムな遅延を使用してください。
ランダムな遅延の実装例:
// Python
import time
import random
# 4から8秒の遅延
delay = random.uniform(4, 8)
time.sleep(delay)
# より複雑なロジック:時々長いポーズを取る
if random.random() < 0.1: # 10%の確率
time.sleep(random.uniform(15, 30)) # ユーザーの気を散らす模擬
else:
time.sleep(random.uniform(4, 8))
// JavaScript / Node.js
const sleep = (min, max) => {
const delay = Math.random() * (max - min) + min;
return new Promise(resolve => setTimeout(resolve, delay * 1000));
};
// 使用例
await sleep(4, 8); // 4-8秒の遅延
// 長いポーズの確率
if (Math.random() < 0.1) {
await sleep(15, 30); // 10%の確率で長いポーズ
} else {
await sleep(4, 8);
}
ランダムな長いポーズ(15-30秒)を5-10%の確率で追加することで、パーサーの行動が電話の呼び出しや他のタスクに気を散らす実際のユーザーにさらに似たものになります。
キャプチャとその他のブロックの処理
プロキシと遅延を正しく設定しても、キャプチャやその他のブロックに直面することがあります。これらの状況に適切に対処する方法を見ていきましょう。
求人ボードのブロックタイプ
1. HTTP 429 Too Many Requests — 最も一般的なブロックタイプです。サイトは明示的にリクエスト制限を超えたことを通知します。通常、レスポンスヘッダーにはRetry-Afterが含まれており、何秒後にリクエストを再試行できるかを示します。
処理方法: すぐにプロキシを変更し、現在のIPをRetry-Afterで指定された時間(通常は1-6時間)ブラックリストに追加します。Retry-Afterがない場合は、IPを2時間ブラックリストに追加します。
2. HTTP 403 Forbidden — IPがサーバーレベルでブロックされています。これはより深刻なブロックであり、数時間から1日続くことがあります。
処理方法: プロキシを変更し、IPを長期的なブラックリスト(24時間)に追加します。ログを分析してください:おそらく、パーシングが攻撃的すぎるか、レジデンシャルが必要な場所でデータセンターのIPを使用しています。
3. キャプチャ(CAPTCHA) — サイトは「私はロボットではありません」というチェックを表示します。これは、あなたの行動が疑わしいと見なされたことを意味しますが、IPはまだ完全にブロックされていません。
処理方法: 3つのオプションがあります:
- プロキシの変更 — 最も簡単な方法です。現在のIPは6-12時間のブラックリストに追加されます。
- キャプチャの自動解決 — 2Captcha、Anti-Captcha、CapSolverなどのサービスを使用します。これらは1000解決あたり$1-3の費用がかかります。
- 手動解決 — パーシングが時間的に重要でない場合、キャプチャを手動で解決するオペレーターに送信できます。
4. Cloudflare Challenge — ブラウザでコードを実行する必要があるJavaScriptチェックです。通常のHTTPライブラリではこのチェックを通過できません。
処理方法: ヘッドレスブラウザ(Puppeteer、Playwright、Selenium)を使用し、実際のフィンガープリンティングを設定します。puppeteer-extra-plugin-stealthのようなライブラリは、ヘッドレスモードの検出を回避するのに役立ちます。
キャプチャ解決サービスの統合
自動的にキャプチャを解決することにした場合、人気のあるサービス2Captchaとの統合の例を示します:
// Pythonと2captcha-pythonライブラリを使用
from twocaptcha import TwoCaptcha
import requests
solver = TwoCaptcha('YOUR_API_KEY')
try:
# reCAPTCHA v2の解決
result = solver.recaptcha(
sitekey='6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
url='https://hh.ru/search/vacancy',
proxy={
'type': 'HTTPS',
'uri': 'login:password@ip:port'
}
)
# 解決トークンを取得
captcha_token = result['code']
# トークンを持つリクエストを送信
response = requests.post(
'https://hh.ru/search/vacancy',
data={
'g-recaptcha-response': captcha_token,
# 他のフォームパラメータ
},
proxies={
'http': 'http://login:password@ip:port',
'https': 'http://login:password@ip:port'
}
)
except Exception as e:
print(f'キャプチャ解決エラー: {e}')
1つのキャプチャを解決するのに10-30秒かかり、約$0.001-0.003の費用がかかります。大規模なパーシングには高額になる可能性があるため、キャプチャができるだけ少なくなるようにパーシングを設定するのが最善です。
監視およびアラートシステム
パーサーの安定した動作のためには、ブロックの監視と自動アラートを設定することが重要です:
監視すべきこと:
- 成功したリクエストの割合 — 90%未満に下がった場合、プロキシと設定を確認する必要があります
- 時間あたりのキャプチャの数 — 5-10を超える場合、パーシングが攻撃的すぎます
- プロキシの平均応答速度 — 急激に増加した場合、プロキシが過負荷になっている可能性があります
- 429/403エラーの数 — プロキシの品質と設定の正確さの指標です
- ブロックされたIPのリスト — 同じIPが常にブロックされている場合は、そのIPをプールから除外してください
成功したリクエストの割合が閾値を下回った場合に通知(Telegram、メール、Slack)を送信するように設定してください。これにより、問題に迅速に対応し、パーシングの時間を失うことを防ぎます。
人気のパーシングツールでのプロキシ設定
Python(requests、Scrapy)、Node.js(axios、Puppeteer)、および既製のソリューションでの求人ボードのパーシングツールでのプロキシ設定方法を見ていきましょう。
Python:requestsとScrapy
Pythonは、requests、BeautifulSoup、Scrapyライブラリのおかげで、パーシングに最も人気のある言語です。
requestsライブラリの例:
import requests
import random
import time
# プロキシのリスト(プロバイダーから取得)
PROXIES = [
'http://user:[email protected]:8080',
'http://user:[email protected]:8080',
'http://user:[email protected]:8080'
]
# ローテーション用のUser-Agentのリスト
USER_AGENTS = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
]
def parse_vacancy(url):
proxy = random.choice(PROXIES)
user_agent = random.choice(USER_AGENTS)
headers = {
'User-Agent': user_agent,
'Accept': 'text/html,application/xhtml+xml',
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive'
}
proxies = {
'http': proxy,
'https': proxy
}
try:
response = requests.get(
url,
headers=headers,
proxies=proxies,
timeout=30
)
if response.status_code == 200:
return response.text
elif response.status_code == 429:
print(f'{proxy}のレート制限、プロキシを変更します')
# 一時的にプロキシをリストから削除
return None
else:
print(f'エラー {response.status_code}')
return None
except Exception as e:
print(f'リクエストエラー: {e}')
return None
# 使用例
for i in range(100):
html = parse_vacancy('https://hh.ru/vacancy/123456')
if html:
# データ処理
pass
# ランダムな遅延
time.sleep(random.uniform(4, 8))
Scrapyの設定例:
# settings.py
# プロキシのサポートを有効にする
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110,
'scrapy_rotating_proxies.middlewares.RotatingProxyMiddleware': 610,
'scrapy_rotating_proxies.middlewares.BanDetectionMiddleware': 620,
}
# プロキシのリスト
ROTATING_PROXY_LIST = [
'http://user:[email protected]:8080',
'http://user:[email protected]:8080',
'http://user:[email protected]:8080'
]
# バンの自動検出
ROTATING_PROXY_BAN_POLICY = 'scrapy_rotating_proxies.policy.BanDetectionPolicy'
# リクエスト間の遅延
DOWNLOAD_DELAY = 5
RANDOMIZE_DOWNLOAD_DELAY = True # ±50%のランダムな遅延
# User-Agentのローテーション
DOWNLOADER_MIDDLEWARES.update({
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
'scrapy_user_agents.middlewares.RandomUserAgentMiddleware': 400,
})
# 同時リクエストの最大数
CONCURRENT_REQUESTS = 4
CONCURRENT_REQUESTS_PER_DOMAIN = 1
Node.js:プロキシを使用したPuppeteer
JavaScriptを使用したサイト(LinkedIn、Indeed)をパーシングするには、ヘッドレスブラウザが必要です。PuppeteerはNode.jsで最も人気のあるソリューションです。
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
// ヘッドレスブラウザの検出を回避するためのプラグイン
puppeteer.use(StealthPlugin());
async function parseWithProxy() {
const proxy = 'http://user:[email protected]:8080';
const browser = await puppeteer.launch({
headless: true,
args: [
`--proxy-server=${proxy}`,
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-blink-features=AutomationControlled'
]
});
const page = await browser.newPage();
// 実際のUser-Agentを設定
await page.setUserAgent(
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
);
// ここからパーシングのロジックを追加
// ...
}