문서

문서

ActiCrawl을 사용하여 웹 스크래핑 워크플로를 자동화하는 방법을 알아보세요

웹 크롤링

ActiCrawl의 강력한 크롤링 엔진으로 현대적인 JavaScript 중심 사이트, 동적 콘텐츠, 복잡한 네비게이션 패턴을 효과적으로 크롤링하는 방법을 알아보세요.

웹 크롤링 이해하기

웹 크롤링은 웹사이트를 체계적으로 탐색하고 데이터를 추출하는 프로세스입니다. ActiCrawl은 다음을 수행할 수 있는 정교한 크롤링 엔진을 제공합니다:

  • 여러 페이지를 자동으로 탐색
  • JavaScript 렌더링 콘텐츠 처리
  • 링크 따라가기 및 새 페이지 발견
  • robots.txt 및 크롤링 지연 준수
  • 세션 및 인증 관리

단일 페이지 스크래핑

단일 페이지를 스크래핑하려면 기본 스크래핑 엔드포인트를 사용하세요:

javascript
const result = await client.scrape({
  url: 'https://example.com/page',
  format: 'markdown'
});

다중 페이지 크롤링

링크 따라가기

도메인 내의 링크를 자동으로 따라가며 크롤링:

javascript
const crawler = await client.crawl({
  startUrl: 'https://example.com',
  followLinks: true,
  maxPages: 100,
  linkSelector: 'a[href]', // 따라갈 링크의 CSS 선택자
  sameDomain: true, // 같은 도메인의 링크만 따라가기
  format: 'json'
});

// 크롤링된 페이지 처리
crawler.on('page', (page) => {
  console.log(`크롤링됨: ${page.url}`);
  console.log(`${page.links.length}개의 링크 발견`);
});

crawler.on('complete', (results) => {
  console.log(`${results.length}개 페이지 크롤링 완료`);
});

URL 패턴

특정 URL 패턴 정의하여 크롤링:

python
from acticrawl import ActiCrawl

client = ActiCrawl(api_key='YOUR_API_KEY')

crawler = client.create_crawler({
    'start_url': 'https://example.com/products',
    'url_patterns': [
        r'^https://example\.com/products/[\w-]+$',  # 제품 페이지
        r'^https://example\.com/category/[\w-]+$'   # 카테고리 페이지
    ],
    'max_pages': 500
})

results = crawler.run()

사이트맵 크롤링

사이트맵을 사용하여 효율적으로 크롤링:

ruby
crawler = client.crawl_sitemap(
  sitemap_url: 'https://example.com/sitemap.xml',
  filter: ->(url) { url.include?('/blog/') }, # 블로그 포스트만 크롤링
  concurrency: 5,
  format: 'markdown'
)

crawler.each do |page|
  puts "제목: #{page['metadata']['title']}"
  puts "콘텐츠: #{page['content']}"
end

고급 크롤링 전략

깊이 우선 vs 너비 우선

사이트 구조에 따라 크롤링 전략 선택:

javascript
// 너비 우선 (기본값) - 각 레벨의 모든 페이지 발견에 적합
const bfsCrawler = await client.crawl({
  startUrl: 'https://example.com',
  strategy: 'breadth-first',
  maxDepth: 3
});

// 깊이 우선 - 특정 경로를 깊게 따라가기에 적합
const dfsCrawler = await client.crawl({
  startUrl: 'https://example.com',
  strategy: 'depth-first',
  maxDepth: 10
});

페이지네이션 처리

페이지네이션된 콘텐츠 자동 처리:

python
crawler = client.create_crawler({
    'start_url': 'https://example.com/listings?page=1',
    'pagination': {
        'type': 'query_param',
        'param': 'page',
        'max_pages': 50,
        'increment': 1
    }
})

# 또는 다음 버튼 클릭으로
crawler = client.create_crawler({
    'start_url': 'https://example.com/results',
    'pagination': {
        'type': 'click',
        'selector': 'button.next-page',
        'wait_after_click': 2000,
        'max_clicks': 20
    }
})

무한 스크롤

무한 스크롤 페이지 처리:

javascript
const result = await client.scrape({
  url: 'https://example.com/feed',
  infinite_scroll: {
    enabled: true,
    max_scrolls: 10,
    scroll_delay: 1000, // 스크롤 간 1초 대기
    element_count_selector: '.feed-item', // 새 항목이 없으면 중지
    timeout: 30000
  }
});

세션 관리

로그인 상태 유지

인증된 영역 크롤링:

javascript
// 먼저 로그인
const session = await client.createSession({
  loginUrl: 'https://example.com/login',
  credentials: {
    username: 'user@example.com',
    password: 'password'
  },
  selectors: {
    username: '#username',
    password: '#password',
    submit: 'button[type="submit"]'
  }
});

// 세션으로 크롤링
const crawler = await client.crawl({
  startUrl: 'https://example.com/dashboard',
  sessionId: session.id,
  followLinks: true
});

쿠키 관리

기존 쿠키를 사용하여 크롤링:

python
cookies = [
    {'name': 'session_id', 'value': 'abc123', 'domain': 'example.com'},
    {'name': 'auth_token', 'value': 'xyz789', 'domain': 'example.com'}
]

crawler = client.create_crawler({
    'start_url': 'https://example.com/protected',
    'cookies': cookies,
    'follow_links': True
})

크롤링 규칙 및 필터

URL 필터링

크롤링할 URL 제어:

javascript
const crawler = await client.crawl({
  startUrl: 'https://example.com',
  urlFilters: {
    include: [
      /\/products\//,  // 제품 페이지 포함
      /\/blog\//       // 블로그 포스트 포함
    ],
    exclude: [
      /\/admin\//,     // 관리자 페이지 제외
      /\.pdf$/,        // PDF 파일 제외
      /#/              // URL 프래그먼트 제외
    ]
  }
});

콘텐츠 필터링

콘텐츠 기반 페이지 필터링:

python
def should_process(page):
    # 특정 콘텐츠가 있는 페이지만 처리
    return (
        page['metadata'].get('language') == 'ko' and
        len(page['content']) > 1000 and
        '제품' in page['content'].lower()
    )

crawler = client.create_crawler({
    'start_url': 'https://example.com',
    'content_filter': should_process
})

성능 최적화

동시 크롤링

동시성으로 크롤링 속도 향상:

javascript
const crawler = await client.crawl({
  startUrl: 'https://example.com',
  concurrency: 10, // 10개 페이지 동시 크롤링
  requestDelay: 1000, // 요청 간 1초 대기
  respectRobotsTxt: true
});

캐싱

변경되지 않은 페이지 재크롤링 방지:

python
crawler = client.create_crawler({
    'start_url': 'https://example.com',
    'cache': {
        'enabled': True,
        'ttl': 86400,  # 24시간 캐시
        'key_by': 'url_and_content_hash'
    }
})

선택적 추출

처리 감소를 위해 필요한 데이터만 추출:

javascript
const crawler = await client.crawl({
  startUrl: 'https://example.com/catalog',
  extract: {
    title: 'h1',
    price: '.price',
    description: '.product-description',
    image: 'img.product-image@src'
  },
  skipFullContent: true // 전체 HTML 저장 안 함
});

오류 처리 및 재시도

자동 재시도

재시도 동작 구성:

python
crawler = client.create_crawler({
    'start_url': 'https://example.com',
    'retry': {
        'max_attempts': 3,
        'delay': 2000,
        'exponential_backoff': True,
        'on_errors': [429, 500, 502, 503, 504]
    }
})

오류 복구

오류 후에도 크롤링 계속:

javascript
const crawler = await client.crawl({
  startUrl: 'https://example.com',
  errorHandling: {
    continueOnError: true,
    maxConsecutiveErrors: 5,
    errorLog: true
  }
});

crawler.on('error', (error) => {
  console.error(`크롤링 오류 ${error.url}: ${error.message}`);
  // 사용자 정의 오류 처리
});

모니터링 및 진행 상황

실시간 진행 상황

크롤링 진행 상황 추적:

python
crawler = client.create_crawler({
    'start_url': 'https://example.com',
    'progress_callback': lambda p: print(f"진행률: {p['crawled']}/{p['total']}")
})

# 또는 웹훅 사용
crawler = client.create_crawler({
    'start_url': 'https://example.com',
    'webhook': {
        'url': 'https://your-app.com/crawl-progress',
        'events': ['page_crawled', 'error', 'complete']
    }
})

크롤링 통계

상세 통계 확인:

javascript
const stats = await crawler.getStats();
console.log({
  totalPages: stats.totalPages,
  successfulPages: stats.successful,
  failedPages: stats.failed,
  averageResponseTime: stats.avgResponseTime,
  totalDataExtracted: stats.dataSize
});

모범 사례

1. 웹사이트 정책 존중

  • 항상 robots.txt 확인 및 준수
  • 요청 간 적절한 지연 구현
  • 합리적인 동시성 제한 사용

2. 선택자 최적화

  • 더 나은 성능을 위해 특정 CSS 선택자 사용
  • 너무 많은 요소와 일치하는 광범위한 선택자 피하기
  • 대규모 크롤링 전 선택자 테스트

3. 동적 콘텐츠 처리

  • 추출 전 콘텐츠 로드 대기
  • JavaScript에 적절한 대기 전략 사용
  • 중요한 페이지는 스크린샷 검증 고려

4. 리소스 사용량 모니터링

  • 최대 페이지 제한 설정
  • 장시간 실행되는 크롤링에 타임아웃 구현
  • 폴링 대신 장시간 크롤링에는 웹훅 사용

예제: 이커머스 사이트 크롤러

이커머스 사이트 크롤링 완전한 예제:

javascript
async function crawlEcommerceSite() {
  const crawler = await client.crawl({
    startUrl: 'https://shop.example.com',

    // 크롤링 규칙
    urlFilters: {
      include: [/\/products\//, /\/category\//],
      exclude: [/\/cart/, /\/checkout/, /\/account/]
    },

    // 성능 설정
    concurrency: 5,
    maxPages: 1000,
    requestDelay: 2000,

    // 추출 규칙
    extract: {
      title: 'h1.product-title',
      price: '.price-now',
      originalPrice: '.price-was',
      description: '.product-description',
      images: 'img.product-image@src',
      inStock: '.availability',
      reviews: {
        selector: '.review',
        multiple: true,
        extract: {
          rating: '.rating@data-rating',
          text: '.review-text',
          author: '.review-author'
        }
      }
    },

    // 오류 처리
    retry: {
      maxAttempts: 3,
      delay: 5000
    },

    // 진행 상황 추적
    webhook: {
      url: 'https://your-app.com/crawl-webhook',
      events: ['page_crawled', 'complete', 'error']
    }
  });

  return crawler.run();
}

다음 단계