ブログに戻ります

Activepieces + Scrapeless: コード不要のローカルリードフロー

Isabella Garcia
Isabella Garcia

Web Data Collection Specialist

20-Aug-2026

TL;DR:

  • Activepiecesは、組み込みのHTTPピースを使用してライブ検索データにアクセスできるため、リードフローにはカスタムピース、公開パッケージ、ホスティングサービスが不要です。
  • Google Searchアクターは、リクエストごとに約20のローカルビジネスを返します — 20、21、22の場所にキャプチャされました — したがって、ローカルフローは通常、1回の呼び出しと重複排除キーが必要であり、ページネーションループは不要です。
  • 解析されたレスポンスはbodyの下にあり、{{step_1.body.local_results.places}}が作業参照になります; bodyを削除するとフロー内でループはゼロ回実行されますが、成功としてレポートされます。
  • phoneフィールドは、約半数のレコードに電話番号を保持しています — 残りは営業時間またはサービスラベルを持っています — したがって、コードピースは単にそれを切り取るのではなく、検証する必要があります。
  • APIキーは、ヘッダーフィールドに入力するのではなく、プロジェクトレベルの値として保存してください。フローはエクスポートされ、共有されるからです。

What This Flow Gives You

カテゴリと都市をローカルビジネスの行に変換する作業中のActivepiecesフロー — 名前、カテゴリ、評価、レビュー数、電話 — CRM、シート、またはデータベース用に準備されています。

Activepiecesはアプリをうまくオーケストレーションし、ページを取得しません。検索結果は、scraper.google.searchアクターを通じてDeep SerpApiから取得され、解析されたローカルパックがJSONとして返されます。以下のフローは、piece-http 0.11.18を使用した自己ホスティングのActivepieces 0.82.0インスタンス上で構築されました。

Prerequisites

  • Activepiecesインスタンス、クラウドまたは自己ホスティング
  • Scrapeless APIキー — 無料アカウントを作成する
  • 行の宛先ピース: Google Sheets、Airtable、Postgres、またはあなたのCRM

キーをプロジェクトレベルの値または接続に入れ、ステップのヘッダーフィールドには入力しないでください。フローディフィニションはそのリテラルフィールド値を持ち、フローはエクスポート、複製、プロジェクト間で共有されます。

Configure the HTTP Step

HTTP → Send HTTP requestを追加し、5つのフィールドを入力します:

Field Value
Method POST
URL https://api.scrapeless.com/api/v1/scraper/request
Headers x-api-token → あなたのキー
Body type JSON
Body 以下のオブジェクト
json Copy
{
  "actor": "scraper.google.search",
  "input": {
    "q": "plumbers in Austin, TX",
    "tbm": "lcl"
  }
}

tbmlclに設定すると、ビジネスがウェブページの代わりに返されます。クエリはローカルな意図を必要とします: "plumbers in Austin, TX"はローカルパックを返し、シンプルな"plumbing"はしばしば返しません。

フローの残りを配線する前に、ビルダーの外でリクエストを確認してください。シェルから同じ呼び出しを行うと、空の結果がクエリのせいかフローのせいかを教えてくれます:

bash Copy
curl -sS -X POST https://api.scrapeless.com/api/v1/scraper/request \
  -H 'Content-Type: application/json' \
  -H "x-api-token: $SCRAPELESS_API_KEY" \
  -d '{"actor":"scraper.google.search","input":{"q":"plumbers in Austin, TX","tbm":"lcl"}}' \
  | python3 -c 'import json, sys
data = json.load(sys.stdin)
places = (data.get("local_results") or {}).get("places") or []
print(len(places), "places")
if places:
    print("raw phone:", repr(places[0]["phone"]), "| raw type:", repr(places[0]["type"]))
else:
    print("no local pack in this response; top-level keys were", sorted(data))'

それは、場所のカウントと最初のレコードの生のphoneおよびtypeを表示します — 受け取られた2つのフィールドはパディングされています。elseブランチのキーを読むのは、local_resultsに直接インデックスするのではなく、フローが必要とする同じ習慣です: アドレスに入る前に、期待する形状が存在するかを確認してください。

What Comes Back

成功した実行は、local_results.placesの下に約20の場所を返します。各々はtitletyperatingreviewsphone、およびaddressを持っています。キャプチャは、同じクエリの20、21、22の場所に到達したため、ページサイズは固定ではなくおおよそと考えてください: 次のページのために"start": 20inputオブジェクトに追加し、名前と電話で重複排除を行い、正確なページ境界を仮定しないでください。

tbmlclに設定されている場合、封筒はlocal_resultsmetadatapagination、およびsearch_informationです — organic_resultsはなく、related_searchesもありません。拒否された呼び出しは、結果がなくてもcodeおよびmessageを含む封筒を返します。これは、フローがHTTPステータスだけでなくlocal_resultsの存在に基づいて分岐すべき理由です。

参照パスは正確に取得する価値があります。Activepiecesでは、解析されたJSONはbodyの下に存在します:

Reference Result
{{step_1.body.local_results.places}} 場所の配列
{{step_1.body.organic_results}} tbmが省略された場合のウェブ結果
{{step_1.organic_results}} 何もなし — エラーなし、警告なし

最後の行は高価なものです。bodyセグメントが欠落した参照は何も解決せず、Loop on Itemsステップはゼロ回実行され、実行は成功として終了します。クエリが何も返さなかったか、参照が間違っていたかに関わらず、空の宛先テーブルは同じように見えるため、まずパスを確認してください。

{{step_1.body.local_results.places}}上でLoop on Itemsを追加して、各ビジネスが単一のセルに書き込まれた1つの塊としてではなく、各独自のアイテムとして処理されるようにします。
このフリープランで構築することで、完全なローカルパックレスポンスに達するのに十分です — Scrapelessアカウントを作成する と、プロジェクト値にキーを保持してください。

保存前の正規化

使用可能な行かどうかを決定するのは二つの振る舞いであり、二つ目はリードフローにコードが必要な理由です。

文字列はパディングされて到着します。 phonetype、および hours は先頭にスペースを持ちます — " Plumber"" (512) 690-4935"。これは見た目の問題ではありません: デデュプリケーションキーとして使用されるパディングされた電話番号は、次の実行で同じビジネスのための二つ目のレコードを作成し、"Plumber" に対するカテゴリフィルターは何も一致しません。ITU-T番号計画勧告 は、電話番号を同定子になる前に標準形に正規化する理由です。

いくつかのフィールドは存在しますが、使用可能なものはありません。 同じキャプチャ内で、place_idthumbnail、および lsig は20のレコードすべてで空でした。gps_coordinates は罠です: {"latitude": 0, "longitude": 0} として存在しているため、真偽チェックが通り、マッピングステップはすべてのビジネスを赤道上の同じ位置にプロットします。address から位置を取得し、両方の値がゼロでない限り座標ペアを存在しないものとして扱ってください。

phone フィールドは常に電話番号ではありません。 "plumbers in Austin, TX" に対する20のキャプチャの中で、11のレコードのみが電話のような値を持っていました。他の9つは、" Closes 6 PM " のような営業時間テキストや、"Online estimates" のようなサービスラベルを保持していました。そのフィールドをCRM列に直接マッピングすると、ほぼ半分の行が使用不可能になり、フロー内にエラーはどこにもありません。そのいくつかの営業時間文字列は、普通のスペースではなく狭い改行のないスペース(U+202F)も含んでいるため、" " での単純な分割はトリミング後も予期しない動作をします。

フィールドの名前を信頼するのではなく、フィールドを検証し、破棄するテキストを削除せずに保持してください:

リクエストと宛先の間に コード ピースを追加します。Activepiecesはボディを export const code = async (inputs) => { … } としてラップします; 内部のロジックはプレーンJavaScriptです:

javascript Copy
// `phone` sometimes carries opening hours or a service label instead of a number,
// so the value is validated before it becomes a contact field.
const PHONE = /\(?\d{3}\)?[ -]?\d{3}-?\d{4}/;

const code = async (inputs) => {
  const clean = (value) => (typeof value === 'string' ? value.trim() : value);
  const places = inputs.response?.local_results?.places ?? [];
  return places.map((place) => {
    const contact = clean(place.phone) ?? '';
    const isPhone = PHONE.test(contact);
    return {
      name: clean(place.title),
      category: clean(place.type),
      rating: place.rating ?? null,
      reviews: place.reviews ?? 0,
      phone: isPhone ? contact : null,
      phone_field_note: isPhone ? null : contact,
      address_snippet: clean(place.address),
    };
  });
};

const sample = {
  response: {
    local_results: {
      places: [
        {
          title: 'Radiant Plumbing, Air Conditioning, & Electrical',
          type: ' Plumber',
          rating: 4.8,
          reviews: 18000,
          phone: ' (512) 690-4935',
          address: '25+ years in business \u00b7 Austin, TX',
        },
        {
          title: 'Beyond Wow Plumbing & Drains',
          type: ' Plumber',
          rating: 4.9,
          phone: ' Closes 6\u202fPM ',
          address: 'Austin, TX',
        },
      ],
    },
  },
};

code(sample).then((rows) => console.log(JSON.stringify(rows, null, 2)));

{{step_1.body}} をピースの response 入力に渡します。ここで重要な二つの詳細があります。?? 0 デフォルトは、レビューのないビジネスにはreviewsキーが全くないため存在し、数値ディスティネーション列は undefined を拒否し 0 を受け入れます。phone_field_note は、数字でないときにフィールドを占めていたものを保持するので、オペレーターは行が電話番号ではなく営業時間があることを確認できます。

評価とレビュー数は、数値を保持する価値のある二つのフィールドです。それ以外はすべてテキストであり、フローがデータベースではなくスプレッドシートエクスポートで終了する場合、カンマ区切り値フォーマット仕様 が、カンマを含むビジネス名がラウンドトリップから生き残る方法を決定します。

ビジネス連絡データを責任を持って扱う

このフローはビジネス連絡の詳細を集めますので、いくつかの義務が伴います。公共の検索結果からのみ収集し、ワークフローが必要とするフィールドのみを収集してください。連絡データを保存するための合法的な基盤を保持し、オプトアウトリクエストを尊重してください。ビジネスの電話番号は個人を特定することができるためです — 一般データ保護規則 は商業的文脈においても個人データに適用され、他の法域にも同等の規則が存在します。各宛先プラットフォームのインポートされた連絡先に関する条件を尊重し、行を無限に保持するのではなく、保持期間を設定し、連絡を取っている国のマーケティング同意規則に従ってください。これらは法的アドバイスではありません; アウトリーチを実行する前に自分自身の義務を確認してください。

結論

全体のフローを構成するのは三つのピースです: アクターを呼び出すためのHTTP、フィールドをトリミングおよびデフォルト化するためのコード、ビジネスごとに1行を書き込むためのItemsのループ。監視すべき失敗モードは参照パスにあります: body を削除し、成功した実行は空のテーブルを書き込みます。

ここからは、クエリを都市のリストに置き換えることで、同じフローがテリトリー構築になります。Make統合ウォークスルー は、別のノーコードビルダーからの同じリクエストをカバーし、Difyモニタリング構築 は同じアクターのエージェント駆動バージョンを示しています。
準備はできましたか?Deep SerpApi ドキュメントを確認して、完全なパラメータセットを理解し、プランと含まれるボリュームを比較無料プランを開始してください。

FAQ

Q: Scrapelessを使用するためにカスタムActivepiecesピースが必要ですか?

いいえ。組み込みのHTTPピースがすべてのアクターをカバーしています。APIは単一の POSTactor フィールドと input オブジェクトを取得します。カスタムピースは、リクエストを生のままで見るべきではないチーム向けに型付けされたフィールドを持つブランド化されたステップが必要な場合にのみ役立ちます。これは能力の選択ではなく、パッケージングの決定です。

Q: HTTPステップが成功したとき、なぜ私のアイテムのループステップは0回反復しますか?

解析されたレスポンスは body の下にネストされているため、{{step_1.local_results.places}} は何も返さず、{{step_1.body.local_results.places}} は配列に解決します。参照が欠けていてもエラーは発生しないため、フローは空のループで成功を報告します。クエリを調査する前に参照パスを確認してください。

Q: 1つのリクエストが返す結果の数はどれくらいで、どうやってもっと取得しますか?

ローカルパックリクエストは約20の場所を返します。1つのクエリの繰り返しキャプチャは20、21、22を返しました。次のページには "start": 20 を、次々のページには input オブジェクトに "start": 40 を追加します。ページサイズは正確に固定されていないため、オフセットを信頼するのではなく、名前と電話番号で重複排除を行い、短い最終ページをセットの終わりと見なしてください。

Q: なぜ place_idgps_coordinates はローカル結果では使えないのですか?

place_idthumbnail、および lsig はすべてのローカルパックレコードで空になりますので、place_id が必要なフローは20の結果をすべて破棄します。gps_coordinates は異なる挙動をし、より危険です: それは空のチェックを生き延びつつ、すべてのビジネスを同じ座標に指し示している {"latitude": 0, "longitude": 0} で満たされています。位置には address を使用し、両方の数字がゼロでないときのみ座標ペアを信頼してください。

Q: APIキーはActivepiecesフローのどこに配置するべきですか?

プロジェクトレベルの値または接続内で、ヘッダーフィールドから参照されます。フロー定義はリテラルフィールド値を持ち、プロジェクト間でエクスポートおよび複製されるので、ステップに直接入力されたキーはすべてのコピーと共に移動します。

Q: このフローはWebhookの代わりにスケジュールで実行できますか?

はい。トリガーを スケジュール に切り替えると、フローの残りは変更されず、通常はテリトリーのリフレッシュに使用されます。ローカルランキングが実際にどれくらい頻繁に動くかに合わせて実行頻度を保ってください; 毎日がほとんどのカテゴリには十分であり、遅いリズムはボリュームを予測可能に保ちます。

Q: 同じフローはビジネスではなくウェブ結果に対して機能しますか?

はい。tbminput オブジェクトから削除すると、結果が {{step_1.body.organic_results}} の下に到着し、それぞれ titlelink、および snippet を持ちます。コードピースはそのパスをマッチするように更新する必要があり、ウェブ結果にはトリミングは不要です。

Scrapelessでは、適用される法律、規制、およびWebサイトのプライバシーポリシーを厳密に遵守しながら、公開されているデータのみにアクセスします。 このブログのコンテンツは、デモンストレーションのみを目的としており、違法または侵害の活動は含まれません。 このブログまたはサードパーティのリンクからの情報の使用に対するすべての責任を保証せず、放棄します。 スクレイピング活動に従事する前に、法律顧問に相談し、ターゲットウェブサイトの利用規約を確認するか、必要な許可を取得してください。

最も人気のある記事

カタログ