prospeo-full-export について
Claudeを使ってProspeoの人物検索結果をCSVに出力するスキルです。大規模な米国検索は州ごとに分割し、単一検索の上限を超えて取得できます。大量出力前の適合性確認も含みます。
主な機能
- 01Prospeo検索結果をページ単位でCSV出力
- 02検索条件をAPIフィルターに変換
- 03大規模な米国検索を州別に分割
- 04州別検索結果を重複排除
- 05出力前にクレジットを見積もり
活用シーン
- 01条件に合う見込み客検索を出力
- 02大規模な米国検索結果を取得
- 03営業連絡用のリストを準備
- 04検索出力に必要なAPIクレジットを見積もり
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ growthenginenowoslawski/ coldoutboundskills --skill prospeo-full-exportインストール後、Claude Code で/prospeo-full-exportを入力して読み込まれたか確認します。
詳細
Prospeo 全件検索エクスポート
Prospeo の人物検索結果をすべて CSV ファイルに抽出します。Prospeo の UI で検索を作成すると、Claude が API を使って、検索結果が 25,000 件を超える場合でも、結果をすべて取得します。
必須手順:/icp-prompt-builder で適合性を判定する(省略しないでください)
500 件を超える連絡先をエクスポートする前に、Prospeo で 50 件のサンプルを実行し、次に /icp-prompt-builder を呼び出して、各ラウンドで承認を得ながら、10 件ずつ 3~5 ラウンドにわたって適格性判定プロンプトを調整します。調整したプロンプトを全件エクスポートに適用し、適合しない候補を除外します。
必須の理由: 後続のメール情報補完には、1 人あたり $0.05~$0.15 かかります。適合しない候補が 40%含まれる 25K 件のエクスポートでは、成果につながらないメール検索に $500~$1,500 を無駄に費やすことになります。ICP プロンプトビルダーにかかる時間は 10~15 分で、40~70%の確率でそのコストを削減できます。
省略しても安全なケース: Prospeo のフィルターがすでに非常に絞り込まれている場合(例:正確な役職 5 件+業界 1 件+狭い従業員数の範囲)、かつ同じフィルターを以前に問題なく実行したことがある場合に限ります。その場合でも、確認のために 10 件のサンプルで /icp-prompt-builder を実行してください。確認コストはほぼかかりません。
このツールでできること
- Prospeo のウェブ UI で検索を作成します(役職、勤務地、業界、企業規模などのフィルターを設定します)。
- 使用したフィルターを Claude に伝えます。
- Claude がそのフィルターを Prospeo API 呼び出しに変換します。
- Claude がすべての結果ページをページネーションで取得し、CSV にエクスポートします。
- 米国内の大規模な検索(25K 件以上)では、Claude が自動的に州ごとに分割し、すべての結果を取得します。
セットアップ(初回のみ)
ステップ 1:Prospeo アカウントを作成する
- prospeo.io にアクセスして登録します。
- Search Person API が含まれるプランを選択します(ほとんどの有料プランに含まれています)。
- 結果を返す API リクエスト 1 回につき 1 クレジットを消費し、25 件の連絡先が返されます。
ステップ 2:API キーを取得する
- Prospeo にログインします。
- Settings > API に移動します(または prospeo.io/app/settings/api にアクセスします)。
- API キーをコピーします。
ステップ 3:API キーを設定する
Claude が使用できるように、環境変数として設定します。
# Add to your shell profile (~/.zshrc or ~/.bashrc)
export PROSPEO_API_KEY="your_api_key_here"
次に、ターミナルを再起動するか、source ~/.zshrc を実行します。
セキュリティに関する注意: API キーをスクリプトファイルに直接貼り付けないでください。必ず環境変数を使用してください。
使い方
ステップ 1:Prospeo の UI で検索を作成する
prospeo.io/app/search にアクセスし、フィルターを使って検索を作成します。UI では次の条件で絞り込めます。
- 役職(例:「CEO」、「VP Sales」、「Head of Marketing」)
- 勤務地(例:「United States」、「California」、「New York」)
- 企業の業界(例:「Information Technology」、「Healthcare」)
- 企業の従業員数(例:従業員数 11~500 人)
- 企業のテクノロジー(例:「Salesforce」、「HubSpot」)
- 売上高の範囲
- 連絡先情報(認証済みのメールアドレスがある、電話番号がある)
UI に表示される検索結果の合計件数をメモしてください。クレジット数の見積もりに必要です。
ステップ 2:フィルターを Claude に伝える
どのような条件で絞り込んだかを説明してください。例:
「米国の Information Technology 業界で、従業員数 11~500 人の企業に所属する CEO と CTO を検索しました。認証済みメールアドレスがある人が対象です。」
「カリフォルニア州の従業員数 50~200 人の SaaS 企業で、VP of Sales と Head of Sales を探しています。」
「HubSpot を使用する米国企業で、従業員数 20~1,000 人のマーケティングディレクターを全員取得したいです。」
ステップ 3:Claude がエクスポートを実行する
Claude は次の処理を行います。
- フィルターと推定クレジットコストを確認します。
- TypeScript スクリプトを作成します。
- スクリプトを実行し、すべての結果をページネーションで取得します。
- すべての結果を、現在のディレクトリに CSV ファイルとしてエクスポートします。
フィルターリファレンス
以下は、Prospeo API が受け付ける正確なフィルター名です。検索内容を説明すると、Claude がその説明を次の項目に対応付けます。
| UI フィルター | API フィルターキー | 形式 |
|---|---|---|
| 役職 | person_job_title | { include: ["CEO", "CTO"], exclude: ["Intern"] } |
| 所在地 | person_location_search | { include: ["California, United States #US"] } |
| 業界 | company_industry | { include: ["Information Technology"] } |
| 従業員数 | company_headcount_custom | { min: 11, max: 500 } |
| テクノロジー | company_technology | { include: ["Salesforce", "HubSpot"] } |
| 売上高 | company_revenue_custom | { min: 1000000, max: 50000000 } |
| 設立年 | company_founding_year | { min: 2010, max: 2025 } |
| 会社名 | company_name | { include: ["Acme"], exclude: ["Test"] } |
| 会社ドメイン | company_domain | { include: ["acme.com"] } |
| メールアドレスあり | person_contact_details | { email: ["VERIFIED"] } |
| 電話番号あり | person_contact_details | { mobile: ["TRUE"] } |
| 役職の完全一致 | person_job_title | { include: [...], match_only_exact_job_titles: true } |
所在地の形式
所在地は、次の正確な形式に従う必要があります。
- 国:"United States #US"、"United Kingdom #GB"、"Canada #CA"
- 州:"California, United States #US"、"Texas, United States #US"
- 市:"San Francisco, California, United States #US"
従業員数の範囲(一般的なプリセット)
| ラベル | min | max |
|---|---|---|
| 1-10 | 1 | 10 |
| 11-50 | 11 | 50 |
| 51-200 | 51 | 200 |
| 201-500 | 201 | 500 |
| 501-1000 | 501 | 1000 |
| 1001-5000 | 1001 | 5000 |
| 5001-10000 | 5001 | 10000 |
| 10001+ | 10001 | (max を省略) |
API の詳細
エンドポイント: POST https://api.prospeo.io/search-person
認証: API キーを指定した X-KEY ヘッダー
レート制限: 1 秒あたり 2 リクエスト(スクリプトが自動的に処理します)
ページネーション: 1 ページあたり 25 件、最大 1000 ページ = 1 回の検索で 25,000 件
クレジット: 1 件以上の結果を返すリクエストごとに 1 クレジット。25,000 件の検索には約 1,000 クレジットかかります。
リクエスト形式
const response = await fetch('https://api.prospeo.io/search-person', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-KEY': process.env.PROSPEO_API_KEY!,
},
body: JSON.stringify({
page: 1, // 1-1000
filters: {
person_job_title: { include: ['CEO', 'CTO'] },
person_location_search: { include: ['United States #US'] },
company_headcount_custom: { min: 11, max: 500 },
company_industry: { include: ['Information Technology'] },
person_contact_details: { email: ['VERIFIED'] },
},
}),
});
レスポンス形式
{
error: false,
results: [
{
person: {
person_id: "abc123",
first_name: "Jane",
last_name: "Smith",
full_name: "Jane Smith",
current_job_title: "CEO",
linkedin_url: "https://linkedin.com/in/janesmith",
email: "[email protected]",
email_status: "VERIFIED",
phone: "+14155551234",
location: { city: "San Francisco", state: "California", country: "United States" }
},
company: {
name: "Acme Corp",
domain: "acme.com",
linkedin_url: "https://linkedin.com/company/acme",
industry: "Information Technology",
headcount: 150,
headcount_range: "51-200",
technologies: ["Salesforce", "HubSpot"],
location: { city: "San Francisco", state: "California", country: "United States" }
}
}
],
pagination: {
current_page: 1,
total_page: 400,
total_count: 10000,
per_page: 25
}
}
25K 件の上限:州ごとの分割
Prospeo では、1 回の検索で取得できる結果は 25,000 件(1000 ページ × 1 ページあたり 25 件)までです。米国全土を対象とした検索の結果が 25K 件を超える場合、スクリプトは自動的に州ごとの 50 件の検索に分割します。
仕組み:
- 検索を 1 回実行して
total_countを確認します - 20,000 件を超える場合、州ごとのモードに切り替えます
"United States #US"を各州に置き換えます(例:"California, United States #US")- 各州の結果をページネーションで取得します
- LinkedIn URL を基準に州をまたいだ重複を除去します
これにより、1 つの検索定義から数十万件の結果を抽出できます。
米国の州(効率化のため人口順)
California, Texas, Florida, New York, Illinois, Pennsylvania,
Ohio, Georgia, North Carolina, Michigan, New Jersey, Virginia,
Washington, Arizona, Massachusetts, Tennessee, Indiana, Missouri,
Maryland, Wisconsin, Colorado, Minnesota, South Carolina, Alabama,
Louisiana, Kentucky, Oregon, Oklahoma, Connecticut, Utah, Iowa,
Nevada, Arkansas, Mississippi, Kansas, New Mexico, Nebraska,
Idaho, West Virginia, Hawaii, New Hampshire, Maine, Montana,
Rhode Island, Delaware, South Dakota, North Dakota, Alaska,
Vermont, Wyoming
スクリプトテンプレート
Claude がエクスポートスクリプトを生成するときは、次のパターンに従います。
import { writeFileSync } from 'fs';
// --- Config ---
const API_KEY = process.env.PROSPEO_API_KEY;
if (!API_KEY) {
console.error('Set PROSPEO_API_KEY environment variable first.');
process.exit(1);
}
const RATE_LIMIT_MS = 500; // 2 requests/sec
const MAX_RETRIES = 5;
// --- Types ---
interface ProspeoFilters {
person_job_title?: { include?: string[]; exclude?: string[]; match_only_exact_job_titles?: boolean };
person_location_search?: { include?: string[]; exclude?: string[] };
company_headcount_custom?: { min?: number; max?: number };
company_industry?: { include?: string[]; exclude?: string[] };
company_technology?: { include?: string[]; exclude?: string[] };
company_revenue_custom?: { min?: number; max?: number };
company_founding_year?: { min?: number; max?: number };
company_name?: { include?: string[]; exclude?: string[] };
company_domain?: { include?: string[]; exclude?: string[] };
person_contact_details?: { email?: string[]; mobile?: string[]; operator?: string };
}
// --- Rate-limited fetch ---
const sleep = (ms: number) => new Promise(r => setTimeout(r, ms));
async function searchPage(filters: ProspeoFilters, page: number, retries = 0): Promise<any> {
await sleep(RATE_LIMIT_MS);
const res = await fetch('https://api.prospeo.io/search-person', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-KEY': API_KEY! },
body: JSON.stringify({ page, filters }),
});
if (res.status === 429 && retries < MAX_RETRIES) {
const backoff = Math.min(2000 * Math.pow(2, retries), 60000);
console.log(` Rate limited, waiting ${backoff / 1000}s...`);
await sleep(backoff);
return searchPage(filters, page, retries + 1);
}
if (!res.ok) throw new Error(`API error: ${res.status} ${res.statusText}`);
return res.json();
}
// --- Deduplication ---
const seenLinkedIn = new Set<string>();
const seenEmail = new Set<string>();
function isDuplicate(person: any): boolean {
const li = person.linkedin_url;
const em = person.email;
if (li && seenLinkedIn.has(li)) return true;
if (em && seenEmail.has(em)) return true;
if (li) seenLinkedIn.add(li);
if (em) seenEmail.add(em);
return false;
}
// --- CSV helpers ---
function escapeCSV(val: any): string {
if (val == null) return '';
const s = String(val);
return s.includes(',') || s.includes('"') || s.includes('\n')
? `"${s.replace(/"/g, '""')}"` : s;
}
function resultToRow(r: any): string[] {
const p = r.person || {};
const c = r.company || {};
return [
p.first_name, p.last_name, p.full_name, p.current_job_title,
p.email, p.email_status, p.phone, p.linkedin_url,
p.location?.city, p.location?.state, p.location?.country,
c.name, c.domain, c.linkedin_url, c.industry,
c.headcount, c.headcount_range,
(c.technologies || []).join('; '),
c.location?.city, c.location?.state, c.location?.country,
];
}
const CSV_HEADERS = [
'first_name', 'last_name', 'full_name', 'job_title',
'email', 'email_status', 'phone', 'linkedin_url',
'person_city', 'person_state', 'person_country',
'company_name', 'company_domain', 'company_linkedin', 'company_industry',
'company_headcount', 'company_headcount_range',
'company_technologies',
'company_city', 'company_state', 'company_country',
];
// --- Main export ---
async function exportSearch(filters: ProspeoFilters, outputFile: string, maxResults?: number) {
console.log('Running initial search to check result count...');
const first = await searchPage(filters, 1);
if (first.error) {
console.error('API error:', first.message);
process.exit(1);
}
const totalCount = first.pagination?.total_count || 0;
const totalPages = first.pagination?.total_page || 0;
console.log(`Found ${totalCount.toLocaleString()} total results (${totalPages} pages)`);
// Check if we need state-by-state splitting
const needsSplit = totalCount > 20000
&& filters.person_location_search?.include?.some(l => l === 'United States #US');
if (needsSplit) {
console.log('Search exceeds 20K — switching to state-by-state mode...');
await exportByState(filters, outputFile, maxResults);
return;
}
// Simple pagination
const rows: string[][] = [];
const pagesToFetch = maxResults ? Math.min(Math.ceil(maxResults / 25), totalPages) : totalPages;
const creditsEstimate = pagesToFetch;
console.log(`Will fetch ${pagesToFetch} pages (~${creditsEstimate} credits)`);
// Process page 1 results we already have
for (const r of first.results || []) {
if (!isDuplicate(r.person)) rows.push(resultToRow(r));
}
console.log(` Page 1/${pagesToFetch} — ${rows.length} contacts`);
for (let page = 2; page <= pagesToFetch; page++) {
if (maxResults && rows.length >= maxResults) break;
const data = await searchPage(filters, page);
for (const r of data.results || []) {
if (!isDuplicate(r.person)) rows.push(resultToRow(r));
}
if (page % 50 === 0 || page === pagesToFetch) {
console.log(` Page ${page}/${pagesToFetch} — ${rows.length} contacts so far`);
}
}
writeCSV(outputFile, rows);
}
// --- State-by-state export ---
const US_STATES = [
'California', 'Texas', 'Florida', 'New York', 'Illinois', 'Pennsylvania',
'Ohio', 'Georgia', 'North Carolina', 'Michigan', 'New Jersey', 'Virginia',
'Washington', 'Arizona', 'Massachusetts', 'Tennessee', 'Indiana', 'Missouri',
'Maryland', 'Wisconsin', 'Colorado', 'Minnesota', 'South Carolina', 'Alabama',
'Louisiana', 'Kentucky', 'Oregon', 'Oklahoma', 'Connecticut', 'Utah', 'Iowa',
'Nevada', 'Arkansas', 'Mississippi', 'Kansas', 'New Mexico', 'Nebraska',
'Idaho', 'West Virginia', 'Hawaii', 'New Hampshire', 'Maine', 'Montana',
'Rhode Island', 'Delaware', 'South Dakota', 'North Dakota', 'Alaska',
'Vermont', 'Wyoming',
];
async function exportByState(filters: ProspeoFilters, outputFile: string, maxResults?: number) {
const rows: string[][] = [];
for (let i = 0; i < US_STATES.length; i++) {
if (maxResults && rows.length >= maxResults) break;
const state = US_STATES[i];
const stateFilters = JSON.parse(JSON.stringify(filters));
stateFilters.person_location_search.include =
stateFilters.person_location_search.include.map((loc: string) =>
loc === 'United States #US' ? `${state}, United States #US` : loc
);
const first = await searchPage(stateFilters, 1);
const stateTotal = first.pagination?.total_count || 0;
const statePages = first.pagination?.total_page || 0;
if (stateTotal === 0) {
console.log(` [${i + 1}/50] ${state}: 0 results, skipping`);
continue;
}
// Process page 1
for (const r of first.results || []) {
if (!isDuplicate(r.person)) rows.push(resultToRow(r));
}
// Paginate remaining
for (let page = 2; page <= statePages; page++) {
if (maxResults && rows.length >= maxResults) break;
const data = await searchPage(stateFilters, page);
for (const r of data.results || []) {
if (!isDuplicate(r.person)) rows.push(resultToRow(r));
}
}
console.log(` [${i + 1}/50] ${state}: ${stateTotal.toLocaleString()} results — ${rows.length.toLocaleString()} total contacts`);
}
writeCSV(outputFile, rows);
}
// --- Write CSV ---
function writeCSV(outputFile: string, rows: string[][]) {
const lines = [CSV_HEADERS.join(',')];
for (const row of rows) {
lines.push(row.map(escapeCSV).join(','));
}
writeFileSync(outputFile, lines.join('\n'), 'utf-8');
console.log(`\nExport complete!`);
console.log(` File: ${outputFile}`);
console.log(` Contacts: ${rows.length.toLocaleString()}`);
console.log(` Credits used: ~${seenLinkedIn.size + seenEmail.size > 0 ? 'see above' : rows.length / 25}`);
}
// --- Entry point ---
// Claude will fill in the filters based on your search description
const filters: ProspeoFilters = {
// FILTERS_GO_HERE
};
const outputFile = 'prospeo-export.csv';
exportSearch(filters, outputFile);
クレジットコストの見積もり
実行前に、Claude がクレジットコストを見積もります。
| 結果の合計 | ページ数 | クレジット | おおよそのコスト(プランにより異なります) |
|---|---|---|---|
| 1,000 | 40 | 40 | 約 $2 |
| 5,000 | 200 | 200 | 約 $10 |
| 25,000 | 1,000 | 1,000 | 約 $50 |
| 100,000(州ごとに分割) | 約 4,000 | 約 4,000 | 約 $200 |
Claude は、エクスポート全体を実行する前に必ず見積もりコストをお伝えし、確認を求めます。
会話例
シンプルな検索:
「カリフォルニア州の SaaS 業界にある従業員数 11~50 人の企業で、メールアドレスが検証済みの CEO をすべてエクスポートしてください。」
米国全土を対象とした大規模な検索:
「従業員数 50~500 人の米国内の企業で、営業担当副社長および営業責任者をすべて探しています。Prospeo の UI では 87,000 件の結果が表示されます。」
除外条件あり:
「米国内のマーケティングディレクターを対象に、人材派遣・採用業界を除外し、従業員数 20~200 人で、検証済みメールアドレスが必須です。」
テクノロジーによる絞り込み:
「米国内の Shopify を利用している企業の CTO。企業規模は問いません。」
トラブルシューティング
「最初に PROSPEO_API_KEY 環境変数を設定してください」
API キーが設定されていません。ターミナルで export PROSPEO_API_KEY="your_key" を実行してください。
「API エラー:401」
API キーが無効です。prospeo.io/app/settings/api で確認してください。
「API エラー:402」
クレジットが不足しています。Prospeo アカウントにクレジットを追加してください。
「API エラー:429」
レート制限に達しました。スクリプトは指数バックオフを使用して自動的に対処します。解消しない場合は、同時にリクエストしすぎています。エクスポートは一度に 1 つだけ実行してください。
結果が少ないように見える
- 地域の形式が正しいことを確認してください(
#US、#GBなどを含める必要があります) - 役職の絞り込み条件を広げてください。Prospeo はデフォルトであいまい検索を行います
person_contact_detailsフィルターを削除すると、すべての結果を確認できます(検証済みメールアドレスのある連絡先だけでなく)
州をまたいだ重複
スクリプトは LinkedIn URL を基準に自動で重複を除去します。転居した連絡先は複数の州の検索に表示されることがありますが、その重複も除去されます。
必要条件
- Node.js 18 以降(ネイティブの
fetchをサポート) - TypeScript(.ts ファイルを直接実行するには
npm install -g tsxを実行) - API クレジットのある Prospeo アカウント
ほかに依存関係は必要ありません。スクリプトは Node.js の組み込みモジュールのみを使用します。
次のステップ
50 件のサンプルで /icp-prompt-builder を実行してください(上記の必須ステップ)。調整したプロンプトをエクスポート全体に適用し、その後 /list-quality-scorecard で評価します。
次は、/campaign-copywriting → /smartlead-campaign-upload-public です。
または、待機します: Prospeo から返された連絡先が絞り込み条件で 500 件未満の場合、ICP の範囲が狭すぎる可能性があります。規模を拡大する前に、役職(類義語を追加)または業界の条件を広げてください。
関連スキル
/icp-prompt-builder— 規模を拡大する前に必須の適格性確認/list-quality-scorecard— 絞り込んだリストを評価/campaign-copywriting— メールを作成/smartlead-campaign-upload-public— DRAFT で開始