통합

Shifter와 함께 사용 Apify

Shifter의 레지덴셜 및 ISP 프록시를 모든 Apify Actor에 적용하세요. Crawlee가 큐잉과 재시도를 처리하고, Shifter가 레지덴셜 IP를 처리합니다. ProxyConfiguration은 Shifter URL을 기본적으로 지원합니다.

빠른 시작

설치

npm install apify crawlee

기본 사용법

// main.js (an Apify Actor)
import { Actor } from "apify";
import { CheerioCrawler, ProxyConfiguration } from "crawlee";

await Actor.init();

const proxyConfiguration = new ProxyConfiguration({
  proxyUrls: [
    "customer-USERNAME-country-us-sid-123ABC:PASSWORD@p.shifter.io:443",
  ],
});

const crawler = new CheerioCrawler({
  proxyConfiguration,
  async requestHandler({ request, $, log }) {
    log.info(`${request.url} -> ${$("h1").text().trim()}`);
  },
});

await crawler.run(["https://example.com"]);
await Actor.exit();

기능

Crawlee의 네이티브 ProxyConfiguration 지원, Shifter URL 또는 newUrlFunction을 전달하세요
CheerioCrawler, PuppeteerCrawler, PlaywrightCrawler, BasicCrawler와 호환
Crawlee의 세션 풀을 통한 세션별 스티키 IP, 차단 시 오래된 세션을 자동으로 폐기합니다
195개국 이상 Geo 타겟팅 - Actor 입력 스키마를 통해 country 매개변수화
Apify Console 예약 실행, Apify Cloud 자동 스케일링, 자체 호스팅 Crawlee에 그대로 적용
전체 Apify SDK와 호환 — pushData, key-value store, request queue, 데이터셋 지속성

예시

Crawlee + 세션별 로테이션

Crawlee는 차단과 세션 만료를 자동으로 처리합니다. newUrlFunction을 사용하여 세션마다 새로운 Shifter URL을 생성하세요. Crawlee가 차단으로 인해 세션을 종료하면 다음 세션은 깨끗한 레지덴셜 IP를 받습니다.

import { Actor } from "apify";
import { CheerioCrawler, ProxyConfiguration } from "crawlee";

await Actor.init();

const proxyConfiguration = new ProxyConfiguration({
  // Each session asks for a fresh URL — and Crawlee bumps the session
  // on bans, so stale IPs get cycled out automatically.
  newUrlFunction: () => {
    const sid = Math.random().toString(36).slice(2, 10);
    return `customer-USERNAME-country-uk-sid-${sid}-ttl-300:PASSWORD@p.shifter.io:443`;
  },
});

const crawler = new CheerioCrawler({
  proxyConfiguration,
  useSessionPool: true,
  persistCookiesPerSession: true,
  maxConcurrency: 8,

  async requestHandler({ request, $, enqueueLinks, log, session }) {
    log.info(`Session ${session.id} -> ${request.url}`);

    $(".product-card").each((_, el) => {
      // Push to dataset (auto-persisted by Apify)
      Actor.pushData({
        url:   request.url,
        title: $(el).find("h2").text().trim(),
        price: $(el).find(".price").text().trim(),
      });
    });

    await enqueueLinks({ selector: "a.next-page", strategy: "same-domain" });
  },

  failedRequestHandler({ request, log }) {
    log.error(`Failed after retries: ${request.url}`);
  },
});

await crawler.run(["https://example.co.uk/products"]);
await Actor.exit();

PuppeteerCrawler (JS 중심 대상)

대상에 실제 브라우저가 필요할 때는 CheerioCrawler를 PuppeteerCrawler로 교체하세요. 동일한 ProxyConfiguration이 그대로 연결됩니다 — Crawlee가 Shifter URL을 Puppeteer의 launch 인자에 전달합니다.

import { Actor } from "apify";
import { PuppeteerCrawler, ProxyConfiguration } from "crawlee";

await Actor.init();

const proxyConfiguration = new ProxyConfiguration({
  newUrlFunction: () => {
    const sid = Math.random().toString(36).slice(2, 10);
    return `customer-USERNAME-country-de-city-berlin-sid-${sid}:PASSWORD@p.shifter.io:443`;
  },
});

const crawler = new PuppeteerCrawler({
  proxyConfiguration,
  useSessionPool: true,
  launchContext: {
    launchOptions: { headless: "new" },
  },
  maxConcurrency: 4,

  async requestHandler({ request, page, log }) {
    log.info(`Visiting ${request.url}`);
    await page.waitForSelector(".product");

    const products = await page.$$eval(".product", (els) =>
      els.map((el) => ({
        title: el.querySelector("h2")?.textContent?.trim(),
        price: el.querySelector(".price")?.textContent?.trim(),
      })),
    );

    await Actor.pushData(products);
  },
});

await crawler.run(["https://example.de/categories/electronics"]);
await Actor.exit();

입력 스키마가 있는 국가별 액터

country를 Apify Actor 입력값으로 노출하세요. Actor는 시작 시 이를 읽어 해당 지역에 맞는 레지덴셜 풀로 Shifter를 구성합니다. 동일한 Actor 코드가 모든 지역에서 동작합니다.

// .actor/input_schema.json
{
  "title": "Localized Scraper Input",
  "type": "object",
  "schemaVersion": 1,
  "properties": {
    "startUrl": { "type": "string", "title": "Start URL", "default": "https://example.com" },
    "country":  { "type": "string", "title": "Country",   "enum": ["us","uk","de","jp","fr","br"], "default": "us" },
    "maxPages": { "type": "integer", "title": "Max Pages", "default": 100, "minimum": 1, "maximum": 5000 }
  },
  "required": ["startUrl", "country"]
}

// main.js
import { Actor } from "apify";
import { CheerioCrawler, ProxyConfiguration } from "crawlee";

await Actor.init();

const { startUrl, country, maxPages } = await Actor.getInput();

const proxyConfiguration = new ProxyConfiguration({
  newUrlFunction: () => {
    const sid = Math.random().toString(36).slice(2, 10);
    return `customer-USERNAME-country-${country}-sid-${sid}-ttl-300:PASSWORD@p.shifter.io:443`;
  },
});

const crawler = new CheerioCrawler({
  proxyConfiguration,
  maxRequestsPerCrawl: maxPages,
  useSessionPool: true,

  async requestHandler({ request, $, enqueueLinks }) {
    await Actor.pushData({
      country,
      url:   request.url,
      title: $("title").text().trim(),
      h1:    $("h1").first().text().trim(),
    });
    await enqueueLinks({ strategy: "same-domain" });
  },
});

await crawler.run([startUrl]);
await Actor.exit();

Crawlee 없이 Apify SDK 사용 (커스텀 로직)

Crawlee가 당신의 방식에 맞지 않는다면, ProxyConfiguration에서 Shifter 프록시 URL을 가져와 어떤 HTTP 클라이언트와도 사용할 수 있습니다. 세션, 재시도, 지속성 모두 그대로 작동합니다.

import { Actor } from "apify";
import { ProxyConfiguration } from "crawlee";
import { gotScraping } from "got-scraping";

await Actor.init();

const proxyConfiguration = new ProxyConfiguration({
  newUrlFunction: () => {
    const sid = Math.random().toString(36).slice(2, 10);
    return `customer-USERNAME-country-fr-sid-${sid}:PASSWORD@p.shifter.io:443`;
  },
});

// Pull a fresh proxy URL per logical task
async function fetchTarget(url) {
  const proxyUrl = await proxyConfiguration.newUrl();

  const html = await gotScraping({
    url,
    proxyUrl,
    headerGeneratorOptions: {
      browsers: [{ name: "chrome", minVersion: 120 }],
      locales:  ["en-US"],
    },
  }).text();

  return html;
}

const urls = [
  "https://example.fr/api/v1/products?page=1",
  "https://example.fr/api/v1/products?page=2",
  // ...
];

for (const url of urls) {
  try {
    const html = await fetchTarget(url);
    await Actor.pushData({ url, length: html.length });
  } catch (err) {
    console.error(`Failed ${url}: ${err.message}`);
  }
}

await Actor.exit();
자주 묻는 질문

자주 묻는 질문

Apify와 Shifter 사용에 관한 일반적인 질문.

`proxyUrls` 배열(하나 이상의 Shifter URL) 또는 세션마다 새로운 Shifter URL을 반환하는 `newUrlFunction`을 사용하여 Crawlee의 ProxyConfiguration 클래스를 사용하세요. 이 설정을 크롤러에 전달하면 모든 요청이 자동으로 Shifter를 경유합니다.

Apify Proxy와 Shifter는 독립적인 제품입니다. Shifter를 사용하려면 `useApifyProxy` 옵션을 건너뛰고 Shifter URL로 자체 ProxyConfiguration을 제공하세요. 여전히 둘을 혼합할 수 있습니다. 일부 Actor는 워밍업에 Apify Proxy를, 프로덕션 스크래핑에는 Shifter를 사용합니다.

크롤러에서 `useSessionPool: true`를 활성화하세요. Crawlee는 각 요청에 세션을 태그하고 해당 세션 내 요청 전반에 걸쳐 동일한 프록시 URL(따라서 동일한 Shifter sid)을 재사용합니다. 세션이 차단을 유발하면 Crawlee는 해당 세션을 폐기하고 새 IP로 새 세션을 시작합니다.

예. Actor의 input_schema.json에 `country` 필드를 정의하고 시작 시 `Actor.getInput()`으로 읽으세요. newUrlFunction 내에서 이를 Shifter 사용자 이름(예: `country-${input.country}`)에 포함시키세요. 동일한 Actor 코드가 모든 지역에서 작동합니다.

예. ProxyConfiguration은 Cheerio, JsdomCrawler, Puppeteer, Playwright의 네 가지 Crawlee 크롤러 모두에 연결됩니다. Crawlee는 헤드리스 Chromium에서의 인증을 포함하여 프록시 협상을 투명하게 처리합니다.

예. Apify Console은 클라우드에서 Actor 소스를 실행합니다. Shifter 자격 증명을 Actor 시크릿(Settings > Environment variables)으로 저장하고, 코드에서 `process.env.SHIFTER_USER` 등을 통해 참조하면, Actor는 예약된 모든 실행에서 Shifter를 경유합니다.

시작하기

Shifter 사용을 함께 시작하기 Apify

Apify Actors를 Shifter의 205M+ 레지덴셜 및 ISP 프록시를 통해 실행하세요. 네이티브 Crawlee ProxyConfiguration, 세션별 고정 IP, Cheerio / Puppeteer / Playwright 크롤러의 완전한 지원을 제공합니다.

Shifter 무료로 체험하기몇 분 만에 설정. 언제든지 취소 가능.