블로그로 돌아가기

프록시와 Puppeteer 및 Playwright 통합: 코드 예제가 포함된 완벽 가이드

Puppeteer와 Playwright에서 HTTP, HTTPS 및 SOCKS5 프록시 설정에 대한 자세한 가이드, JavaScript 및 TypeScript 코드 예제 포함.

📅2026년 2월 13일
```html

Puppeteer와 Playwright는 브라우저 자동화 및 웹 스크래핑을 위한 인기 있는 도구입니다. 대량의 요청을 처리하거나 보호된 웹사이트를 파싱할 때 프록시를 사용하는 것은 IP 차단을 피하기 위해 매우 중요합니다. 이 가이드에서는 기본 설정부터 회전 및 오류 처리와 같은 고급 시나리오까지 두 도구에서 프록시를 통합하는 모든 방법을 살펴보겠습니다.

헤드리스 브라우저에서 프록시의 기본 작업

Puppeteer와 Playwright는 DevTools 프로토콜을 통해 실제 브라우저(Chromium, Firefox, WebKit)를 제어합니다. 이는 프록시가 개별 요청이 아닌 브라우저 시작 시 설정된다는 것을 의미합니다. 두 도구 모두 HTTP, HTTPS 및 SOCKS5 프록시를 지원하지만 설정을 위한 API는 다릅니다.

일반 HTTP 라이브러리(axios, fetch)와의 주요 차이점은 다음과 같습니다:

  • 브라우저 시작 시 프록시가 설정됨 — 브라우저의 한 세션 내에서 프록시를 즉시 변경할 수 없음
  • JavaScript 및 렌더링 지원 — 프록시는 페이지의 모든 리소스(이미지, 스크립트, XHR)에 적용됨
  • 자동 리디렉션 및 쿠키 처리 — 브라우저는 실제 사용자처럼 행동함
  • 지문 인식 — 프록시를 사용하더라도 사이트는 브라우저의 특성을 통해 자동화를 식별할 수 있음

중요: IP를 자주 변경해야 하는 작업(수천 페이지 파싱, 대량 등록 등)에는 회전하는 주거용 프록시를 사용하는 것이 더 효율적입니다. 이들은 브라우저를 재시작하지 않고도 각 요청마다 IP를 변경할 수 있습니다.

Puppeteer에서 프록시 설정하기

Puppeteer는 Chrome/Chromium을 제어하기 위한 Google의 라이브러리입니다. 프록시는 --proxy-server 플래그를 사용하여 브라우저 시작 인수로 설정됩니다.

HTTP/HTTPS 프록시의 기본 설정

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: true,
    args: [
      '--proxy-server=http://proxy.example.com:8080'
    ]
  });

  const page = await browser.newPage();
  
  // IP 주소 확인
  await page.goto('https://api.ipify.org?format=json');
  const content = await page.content();
  console.log('현재 IP:', content);

  await browser.close();
})();

이 코드는 프록시 서버를 통해 브라우저를 시작합니다. 모든 HTTP 및 HTTPS 요청은 지정된 프록스를 통해 전달됩니다. 작동 확인을 위해 ipify 서비스를 사용하여 외부 IP 주소를 반환합니다.

SOCKS5 프록시 설정하기

const browser = await puppeteer.launch({
  headless: true,
  args: [
    '--proxy-server=socks5://proxy.example.com:1080'
  ]
});

// 나머지 코드는 유사함

SOCKS5 프록시는 더 낮은 수준에서 작동하며 UDP 트래픽을 지원하므로 일부 웹 애플리케이션에 유용할 수 있습니다. 구문은 HTTP 프록시와 동일하지만 URL의 프로토콜만 변경됩니다.

특정 도메인에 대한 프록시 사용하기

const browser = await puppeteer.launch({
  args: [
    '--proxy-server=http://proxy1.example.com:8080',
    '--proxy-bypass-list=localhost;127.0.0.1;*.internal.com'
  ]
});

// 로컬 요청 및 *.internal.com에 대한 요청은 직접 전달됨
// 나머지는 프록스를 통해 전달됨

--proxy-bypass-list 플래그는 특정 도메인을 프록시에서 제외할 수 있습니다. 이는 직접 요청과 프록시 요청을 조합해야 할 때 유용합니다.

Playwright에서 프록시 설정하기

Playwright는 Chromium, Firefox 및 WebKit을 지원하는 Microsoft의 최신 라이브러리입니다. 프록시는 구성 객체를 통해 설정되므로 API가 더 이해하기 쉽고 타입이 지정됩니다.

프록시의 기본 설정

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({
    proxy: {
      server: 'http://proxy.example.com:8080'
    }
  });

  const context = await browser.newContext();
  const page = await context.newPage();
  
  await page.goto('https://api.ipify.org?format=json');
  const ip = await page.textContent('body');
  console.log('프록시를 통한 IP:', ip);

  await browser.close();
})();

Playwright는 명령줄 인수 대신 proxy 객체를 사용합니다. 이는 TypeScript에서 더 나은 타입 지정을 제공하고 더 깔끔한 코드를 보장합니다.

컨텍스트 수준에서 프록시 설정하기

const browser = await chromium.launch();

// 컨텍스트 1 - 프록시와 함께
const context1 = await browser.newContext({
  proxy: {
    server: 'http://proxy1.example.com:8080'
  }
});

// 컨텍스트 2 - 다른 프록시와 함께
const context2 = await browser.newContext({
  proxy: {
    server: 'http://proxy2.example.com:8080'
  }
});

const page1 = await context1.newPage();
const page2 = await context2.newPage();

// 각 페이지는 자신의 프록시를 사용함!

Playwright의 주요 장점 중 하나는 하나의 프로세스 내에서 서로 다른 프록시를 가진 여러 브라우저 컨텍스트를 생성할 수 있다는 것입니다. 이는 많은 IP 주소를 사용할 때 리소스를 절약합니다.

프록시에서 도메인 제외하기

const browser = await chromium.launch({
  proxy: {
    server: 'http://proxy.example.com:8080',
    bypass: 'localhost,127.0.0.1,*.internal.com'
  }
});

// localhost 및 *.internal.com에 대한 요청은 직접 전달됨

로그인 및 비밀번호 인증

대부분의 상업용 프록시는 인증을 요구합니다. 두 도구 모두 인증을 지원하지만 구현 방법은 다릅니다.

Puppeteer에서 인증하기

const browser = await puppeteer.launch({
  args: ['--proxy-server=http://proxy.example.com:8080']
});

const page = await browser.newPage();

// 프록시의 자격 증명 설정
await page.authenticate({
  username: 'your_username',
  password: 'your_password'
});

await page.goto('https://httpbin.org/ip');
const content = await page.content();
console.log(content);

page.authenticate() 메서드는 이 페이지의 모든 후속 요청에 대한 자격 증명을 설정합니다. 첫 번째 page.goto()를 호출하기 전에 호출하는 것이 중요합니다.

Playwright에서 인증하기

const browser = await chromium.launch({
  proxy: {
    server: 'http://proxy.example.com:8080',
    username: 'your_username',
    password: 'your_password'
  }
});

const page = await browser.newPage();
await page.goto('https://httpbin.org/ip');

Playwright는 프록시 구성 객체에 직접 자격 증명을 지정할 수 있도록 하여 추가 메서드 호출 없이 더 편리하고 안전하게 만듭니다.

대체 방법: URL에 자격 증명 포함하기

// 두 프레임워크 모두에서 작동
const proxyUrl = 'http://username:password@proxy.example.com:8080';

// Puppeteer
const browser = await puppeteer.launch({
  args: [`--proxy-server=${proxyUrl}`]
});

// Playwright
const browser = await chromium.launch({
  proxy: { server: proxyUrl }
});

이 방법은 작동하지만 프로덕션에서는 권장되지 않습니다. 자격 증명이 로그에 기록될 수 있기 때문입니다. 민감한 데이터를 저장하기 위해 환경 변수를 사용하십시오.

팁: 상업 웹사이트를 파싱할 때는 주거용 프록시를 사용하는 것이 좋습니다. 이들은 실제 가정 사용자의 IP를 가지고 있어 안티봇 시스템에 의해 차단될 가능성이 적습니다.

프록시 회전 및 IP 풀 관리

대규모 파싱을 위해서는 IP 주소를 정기적으로 변경해야 합니다. 프록시는 브라우저 시작 시 설정되므로 회전하려면 브라우저 세션을 재시작해야 합니다.

프록시 배열을 사용한 간단한 회전 (Puppeteer)

const puppeteer = require('puppeteer');

const proxyList = [
  'http://user1:pass1@proxy1.example.com:8080',
  'http://user2:pass2@proxy2.example.com:8080',
  'http://user3:pass3@proxy3.example.com:8080'
];

async function scrapeWithRotation(urls) {
  for (let i = 0; i < urls.length; i++) {
    const proxyUrl = proxyList[i % proxyList.length];
    
    const browser = await puppeteer.launch({
      args: [`--proxy-server=${proxyUrl}`]
    });

    try {
      const page = await browser.newPage();
      await page.goto(urls[i], { waitUntil: 'networkidle0' });
      
      const data = await page.evaluate(() => {
        return {
          title: document.title,
          url: window.location.href
        };
      });
      
      console.log(`URL ${i + 1}:`, data);
    } catch (error) {
      console.error(`오류 발생 ${urls[i]}:`, error.message);
    } finally {
      await browser.close();
    }
  }
}

const urlsToScrape = [
  'https://example.com/page1',
  'https://example.com/page2',
  'https://example.com/page3',
  'https://example.com/page4'
];

scrapeWithRotation(urlsToScrape);

이 코드는 목록에서 프록시를 순환하며 각 URL에 대해 새로운 브라우저를 시작합니다. i % proxyList.length 메서드는 순환 회전을 보장합니다.

컨텍스트 풀을 사용한 회전 (Playwright)

const { chromium } = require('playwright');

const proxyList = [
  { server: 'http://proxy1.example.com:8080', username: 'user1', password: 'pass1' },
  { server: 'http://proxy2.example.com:8080', username: 'user2', password: 'pass2' },
  { server: 'http://proxy3.example.com:8080', username: 'user3', password: 'pass3' }
];

async function scrapeWithContextPool(urls) {
  const browser = await chromium.launch();
  
  // 서로 다른 프록시로 컨텍스트 풀 생성
  const contexts = await Promise.all(
    proxyList.map(proxy => browser.newContext({ proxy }))
  );

  for (let i = 0; i < urls.length; i++) {
    const context = contexts[i % contexts.length];
    const page = await context.newPage();
    
    try {
      await page.goto(urls[i], { waitUntil: 'networkidle' });
      const title = await page.title();
      console.log(`URL ${i + 1} (프록시 ${i % contexts.length}):`, title);
    } catch (error) {
      console.error(`오류 발생 ${urls[i]}:`, error.message);
    } finally {
      await page.close();
    }
  }

  await browser.close();
}

const urls = [
  'https://example.com/page1',
  'https://example.com/page2',
  'https://example.com/page3'
];

scrapeWithContextPool(urls);

Playwright는 하나의 브라우저에서 여러 컨텍스트를 생성할 수 있게 하여 각 컨텍스트가 자신의 프록시를 사용합니다. 이는 브라우저를 완전히 재시작하는 것에 비해 메모리와 시작 시간을 절약합니다.

오류 추적을 통한 스마트 회전

class ProxyRotator {
  constructor(proxyList) {
    this.proxyList = proxyList;
    this.currentIndex = 0;
    this.failedProxies = new Set();
  }

  getNext() {
    const availableProxies = this.proxyList.filter(
      (_, index) => !this.failedProxies.has(index)
    );

    if (availableProxies.length === 0) {
      throw new Error('모든 프록시가 사용할 수 없습니다');
    }

    const proxy = this.proxyList[this.currentIndex];
    this.currentIndex = (this.currentIndex + 1) % this.proxyList.length;
    
    return { proxy, index: this.currentIndex - 1 };
  }

  markFailed(index) {
    this.failedProxies.add(index);
    console.log(`프록시 ${index}가 사용할 수 없음으로 표시됨`);
  }

  resetFailed() {
    this.failedProxies.clear();
  }
}

// 사용 예
const rotator = new ProxyRotator(proxyList);

async function scrapeWithSmartRotation(url, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const { proxy, index } = rotator.getNext();
    
    const browser = await chromium.launch({ proxy });
    const page = await browser.newPage();

    try {
      await page.goto(url, { timeout: 30000 });
      const data = await page.content();
      await browser.close();
      return data;
    } catch (error) {
      console.error(`프록시 ${index}에서 오류 발생:`, error.message);
      rotator.markFailed(index);
      await browser.close();
      
      if (attempt === maxRetries - 1) {
        throw new Error(`최대 ${maxRetries}번의 시도 후 ${url}을(를) 로드할 수 없습니다`);
      }
    }
  }
}

이 클래스는 작동하지 않는 프록시를 추적하고 회전에서 제외합니다. 오류가 발생하면 자동으로 목록의 다음 프록시로 전환됩니다.

오류 처리 및 작동 확인

프록시를 사용할 때는 특정 오류가 발생할 수 있습니다: 연결 시간 초과, 인증 거부, 대상 웹사이트의 IP 차단. 오류를 올바르게 처리하는 것은 파서의 안정적인 작동을 위해 중요합니다.

일반적인 오류 및 처리 방법

async function safePageLoad(page, url, options = {}) {
  const defaultOptions = {
    timeout: 30000,
    waitUntil: 'networkidle0',
    maxRetries: 3,
    retryDelay: 2000
  };

  const config = { ...defaultOptions, ...options };

  for (let attempt = 1; attempt <= config.maxRetries; attempt++) {
    try {
      await page.goto(url, {
        timeout: config.timeout,
        waitUntil: config.waitUntil
      });
      
      return { success: true, attempt };
    } catch (error) {
      console.error(`시도 ${attempt} 실패:`, error.message);

      // 오류 유형 분석
      if (error.message.includes('ERR_PROXY_CONNECTION_FAILED')) {
        throw new Error('프록시가 사용할 수 없습니다');
      }
      
      if (error.message.includes('ERR_TUNNEL_CONNECTION_FAILED')) {
        throw new Error('프록시 터널링 오류');
      }

      if (error.message.includes('407')) {
        throw new Error('프록시 인증 오류 (407)');
      }

      if (error.message.includes('Navigation timeout')) {
        console.log(`로딩 시간 초과, ${config.retryDelay}ms 후에 재시도`);
        await new Promise(resolve => setTimeout(resolve, config.retryDelay));
        continue;
      }

      // 마지막 시도인 경우 오류를 던짐
      if (attempt === config.maxRetries) {
        throw error;
      }
    }
  }
}

프록시 작동 확인하기

async function testProxy(proxyConfig) {
  const browser = await chromium.launch({ proxy: proxyConfig });
  const page = await browser.newPage();

  const result = {
    working: false,
    ip: null,
    responseTime: null,
    error: null
  };

  const startTime = Date.now();

  try {
    await page.goto('https://api.ipify.org?format=json', { timeout: 10000 });
    const content = await page.textContent('body');
    const data = JSON.parse(content);
    
    result.working = true;
    result.ip = data.ip;
    result.responseTime = Date.now() - startTime;
  } catch (error) {
    result.error = error.message;
  } finally {
    await browser.close();
  }

  return result;
}

// 프록시 목록 테스트
async function validateProxyList(proxyList) {
  console.log('프록시 확인 중...');
  
  const results = await Promise.all(
    proxyList.map(async (proxy, index) => {
      const result = await testProxy(proxy);
      console.log(`프록시 ${index + 1}:`, result.working ? `✓ ${result.ip} (${result.responseTime}ms)` : `✗ ${result.error}`);
      return { proxy, ...result };
    })
  );

  const workingProxies = results.filter(r => r.working);
  console.log(`\n작동하는 프록시: ${workingProxies.length}/${proxyList.length}`);
  
  return workingProxies.map(r => r.proxy);
}

이 함수는 사용하기 전에 각 프록시를 확인하고 응답 시간을 측정하여 작동하는 프록시만 반환합니다. 애플리케이션 시작 시 유효성 검사를 실행하는 것이 좋습니다.

모니터링 및 로깅

class ProxyMonitor {
  constructor() {
    this.stats = {
      totalRequests: 0,
      successfulRequests: 0,
      failedRequests: 0,
      proxyErrors: 0,
      averageResponseTime: 0,
      requestsByProxy: new Map()
    };
  }

  recordRequest(proxyIndex, success, responseTime, error = null) {
    this.stats.totalRequests++;
    
    if (success) {
      this.stats.successfulRequests++;
      this.stats.averageResponseTime = 
        (this.stats.averageResponseTime * (this.stats.successfulRequests - 1) + responseTime) / 
        this.stats.successfulRequests;
    } else {
      this.stats.failedRequests++;
      if (error && error.includes('proxy')) {
        this.stats.proxyErrors++;
      }
    }

    // 각 프록시에 대한 통계
    if (!this.stats.requestsByProxy.has(proxyIndex)) {
      this.stats.requestsByProxy.set(proxyIndex, { success: 0, failed: 0 });
    }
    
    const proxyStats = this.stats.requestsByProxy.get(proxyIndex);
    success ? proxyStats.success++ : proxyStats.failed++;
  }

  getReport() {
    const successRate = (this.stats.successfulRequests / this.stats.totalRequests * 100).toFixed(2);
    
    return {
      ...this.stats,
      successRate: `${successRate}%`,
      averageResponseTime: `${this.stats.averageResponseTime.toFixed(0)}ms`
    };
  }
}

// 사용 예
const monitor = new ProxyMonitor();

async function monitoredScrape(url, proxyIndex) {
  const startTime = Date.now();
  try {
    // ... 파싱 코드 ...
    const responseTime = Date.now() - startTime;
    monitor.recordRequest(proxyIndex, true, responseTime);
  } catch (error) {
    monitor.recordRequest(proxyIndex, false, 0, error.message);
    throw error;
  }
}

고급 시나리오: 지리 위치 및 지문 인식

현대의 안티봇 시스템은 IP 주소뿐만 아니라 지리 위치, 시간대, 브라우저 언어 및 기타 매개변수의 일치를 확인합니다. 다른 국가의 프록시를 사용할 때는 이러한 모든 매개변수를 올바르게 설정하는 것이 중요합니다.

프록시에 맞춘 지리 위치 및 언어 설정하기

const { chromium } = require('playwright');

async function createContextWithGeo(proxy, geoData) {
  const browser = await chromium.launch({ proxy });
  
  const context = await browser.newContext({
    locale: geoData.locale,           // 'en-US', 'de-DE', 'fr-FR'
    timezoneId: geoData.timezone,     // 'America/New_York', 'Europe/Berlin'
    geolocation: {
      latitude: geoData.latitude,
      longitude: geoData.longitude
    },
    permissions: ['geolocation']
  });

  return { browser, context };
}

// 예: 독일의 프록시
const germanyProxy = {
  server: 'http://de-proxy.example.com:8080',
  username: 'user',
  password: 'pass'
};

const germanyGeo = {
  locale: 'de-DE',
  timezone: 'Europe/Berlin',
  latitude: 52.520008,
  longitude: 13.404954
};

const { browser, context } = await createContextWithGeo(germanyProxy, germanyGeo);
const page = await context.newPage();

await page.goto('https://www.google.com');
// Google은 베를린의 결과로 독일어 버전을 표시합니다.

이 코드는 브라우저를 독일의 실제 사용자처럼 보이도록 설정합니다: 독일어 인터페이스, 베를린 시간대 및 베를린 중심의 좌표.

지문 완전 설정하기

async function createStealthContext(proxy, profile) {
  const context = await chromium.launch({ proxy }).then(b => 
    b.newContext({
      locale: profile.locale,
      timezoneId: profile.timezone,
      userAgent: profile.userAgent,
      viewport: profile.viewport,
      deviceScaleFactor: profile.deviceScaleFactor,
      isMobile: profile.isMobile,
      hasTouch: profile.hasTouch,
      colorScheme: profile.colorScheme,
      geolocation: profile.geolocation,
      permissions: ['geolocation']
    })
  );

  return context;
}

// 미국의 Windows 10 + Chrome 프로필
const desktopUSProfile = {
  locale: 'en-US',
  timezone: 'America/New_York',
  userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
  viewport: { width: 1920, height: 1080 },
  deviceScaleFactor: 1,
  isMobile: false,
  hasTouch: false,
  colorScheme: 'light',
  geolocation: { latitude: 40.7128, longitude: -74.0060 }
};

// 영국의 iPhone 프로필
const mobileUKProfile = {
  locale: 'en-GB',
  timezone: 'Europe/London',
  userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
  viewport: { width: 390, height: 844 },
  deviceScaleFactor: 3,
  isMobile: true,
  hasTouch: true,
  colorScheme: 'light',
  geolocation: { latitude: 51.5074, longitude: -0.1278 }
};

지문을 완전히 설정하면 자동화를 발견할 가능성이 줄어듭니다. 모든 매개변수가 서로 일치해야 합니다: 예를 들어, 모바일 User-Agent는 모바일 화면 해상도와 함께 사용해야 합니다.

중요: 광고 플랫폼(Google Ads, Facebook Ads) 또는 금융 서비스와 작업할 때는 모바일 프록시를 사용하는 것이 좋습니다. 이들은 실제 모바일 운영자의 신뢰 점수를 가지고 있으며 거의 차단되지 않습니다.

WebRTC 누수 우회하기

// Puppeteer: WebRTC 차단
const browser = await puppeteer.launch({
  args: [
    '--proxy-server=http://proxy.example.com:8080',
    '--disable-webrtc',
    '--disable-webrtc-hw-encoding',
    '--disable-webrtc-hw-decoding'
  ]
});

// Playwright: WebRTC API 재정의
const context = await browser.newContext({ proxy: proxyConfig });

await context.addInitScript(() => {
  // RTCPeerConnection 차단
  window.RTCPeerConnection = undefined;
  window.RTCDataChannel = undefined;
  window.RTCSessionDescription = undefined;
  
  // getUserMedia 재정의
  navigator.mediaDevices.getUserMedia = undefined;
  navigator.getUserMedia = undefined;
});

WebRTC는 프록시를 사용하더라도 실제 IP 주소를 노출할 수 있습니다. 이 코드는 브라우저에서 WebRTC API를 완전히 비활성화합니다.

프록시 작업을 위한 Puppeteer와 Playwright 비교

기준 Puppeteer Playwright
프록시 설정 명령줄 args를 통해 구성 객체를 통해
인증 시작 후 page.authenticate() 생성 시 proxy 객체에
하나의 브라우저에서 여러 프록시 사용 불가능, 별도의 브라우저 필요 가능, 서로 다른 컨텍스트를 통해
브라우저 지원 Chromium/Chrome만 지원 Chromium, Firefox, WebKit 지원
성능 단일 브라우저의 빠른 시작 여러 컨텍스트에서 더 효율적
TypeScript @types/puppeteer를 통한 타입 TypeScript의 내장 지원
문서 좋음, 많은 예제 포함 우수함, 더 구조화됨
생태계 더 많은 플러그인 및 확장 더 빠르게 발전, 새로운 기능 추가

선택에 대한 권장 사항

Puppeteer를 선택하세요, 만약:

  • Chrome/Chromium만 사용하고 있다면
  • 한 번에 하나의 프록시를 사용해야 한다면
  • 기존 도구와의 최대 호환성이 필요하다면
  • Puppeteer에 대한 큰 코드베이스가 이미 있다면

Playwright를 선택하세요, 만약:

  • Firefox 또는 Safari(WebKit)와 작업해야 한다면
  • 여러 프록시를 동시에 사용해야 한다면
  • 확장성에서 성능이 중요하다면
  • TypeScript로 작성하고 있다면
  • 새 프로젝트를 처음부터 시작하고 있다면

프록시 회전 시 성능

테스트: MacBook Pro M1에서 10개의 프록시로 100페이지 파싱하기:

방법 실행 시간 RAM 사용량
Puppeteer (브라우저 재시작) 8분 23초 ~1.2 GB 피크
Playwright (브라우저 재시작) 7분 54초 ~1.1 GB 피크
Playwright (컨텍스트 풀) 4분 12초 ~800 MB 안정적

Playwright는 컨텍스트 풀을 사용하여 브라우저를 시작하는 데 드는 오버헤드가 없기 때문에 거의 두 배 빠릅니다. 이는 수천 페이지를 파싱할 때 중요합니다.

결론

Puppeteer와 Playwright에서 프록시 통합은 웹 스크래핑, 테스트 및 자동화의 표준 관행입니다. Puppeteer는 단순성과 광범위한 생태계를 제공하고, Playwright는 현대적인 API와 브라우저 컨텍스트를 통한 여러 프록시 작업에서 더 나은 성능을 제공합니다.

우리가 살펴본 주요 사항은 다음과 같습니다:

  • 두 프레임워크에서 HTTP, HTTPS 및 SOCKS5 프록시의 기본 설정
  • 로그인 및 비밀번호 인증
  • 대규모 파싱을 위한 프록시 회전
  • 오류 처리 및 사용 전 프록시 유효성 검사
  • 안티봇 시스템을 우회하기 위한 지리 위치 및 지문 설정
  • 다양한 접근 방식의 성능 비교

프로덕션 솔루션에는 품질 좋은 프록시와 올바른 지문 설정, 오류 처리 및 모니터링을 결합하는 것이 좋습니다. 이는 보호된 웹사이트에서도 파서의 안정적인 작동을 보장합니다.

상업 웹사이트, 마켓플레이스 또는 광고 플랫폼을 파싱할 계획이라면 주거용 프록시를 사용하는 것이 좋습니다. 이들은 실제 가정 사용자의 IP 주소를 제공하여 최대한의 익명성과 최소한의 차단 위험을 보장합니다.

```