Laravel을 활용한 웹 스크래핑: 단계별 가이드

Laravel을 활용한 웹 스크래핑 수행 방법을 배우세요. 스크래핑 API 설정부터 강력한 라이브러리 활용까지, 윤리적 스크래핑을 위한 모범 사례를 준수하면서 진행합니다.
1 분 읽기
Web Scraping With Laravel blog image

이 튜토리얼에서는 Laravel을 활용한 웹 스크래핑을 탐구하고 다음을 배웁니다:

  • 웹 스크래핑에 Laravel이 적합한 이유
  • 최고의 Laravel 스크래핑 라이브러리는 무엇인가
  • Laravel 웹 스크래핑 API를 처음부터 구축하는 방법

시작해 보겠습니다!

Laravel에서 웹 스크래핑을 수행할 수 있을까요?

간단히 말해: 네, 라라벨은 웹 스크래핑에 적합한 기술입니다.

Laravel은 우아하고 표현력 있는 구문으로 유명한 강력한 PHP 프레임워크입니다. 특히 웹에서 데이터를 실시간으로 스크래핑하는 API를 생성할 수 있게 해줍니다. 이는 페이지에서 데이터를 가져오는 과정을 단순화하는 다양한 스크래핑 라이브러리의 지원 덕분에 가능합니다. 더 자세한 안내는 PHP 웹 스크래핑 관련 글을 참고하세요.

확장성, 다른 도구와의 쉬운 통합, 광범위한 커뮤니티 지원 덕분에 Laravel은 웹 스크래핑에 탁월한 선택입니다. 강력한 MVC 아키텍처는 스크래핑 로직을 체계적으로 구성하고 유지 관리하기 쉽게 합니다. 이는 복잡하거나 대규모 스크래핑 프로젝트를 구축할 때 유용합니다.

Laravel 웹 스크래핑을 위한 최고의 라이브러리

Laravel로 웹 스크래핑을 수행하는 데 가장 적합한 라이브러리는 다음과 같습니다:

  • BrowserKit: Symfony 프레임워크의 일부로, HTML 문서와 상호작용하기 위해 웹 브라우저의 API를 시뮬레이션합니다. HTML 문서 탐색 및 스크래핑에는 DomCrawler를 사용합니다. 이 라이브러리는 PHP에서 정적 페이지의 데이터를 추출하는 데 이상적입니다.
  • HttpClient: HTTP 요청을 전송하는 Symfony 컴포넌트입니다. BrowserKit과 원활하게 통합됩니다.
  • Guzzle: 서버에 웹 요청을 전송하고 응답을 효율적으로 처리하는 강력한 HTTP 클라이언트입니다. 웹 페이지와 관련된 HTML 문서를 가져오는 데 유용합니다. Guzzle에서 프록시를 설정하는 방법을 알아보세요.
  • Panther: 웹 스크래핑을 위한 헤드리스 브라우저를 제공하는 Symfony 컴포넌트입니다. 렌더링이나 상호작용에 자바스크립트가 필요한 동적 사이트와 상호작용할 수 있게 해줍니다.

필수 조건

Laravel에서 웹 스크래핑을 위한 이 튜토리얼을 따라하려면 다음 전제 조건을 충족해야 합니다:

PHP 코딩을 위한 IDE도 권장됩니다. PHP 확장 기능이 설치된 Visual Studio Code나 WebStorm이 모두 훌륭한 선택입니다.

Laravel에서 웹 스크래핑 API 구축 방법

이 단계별 섹션에서는 Laravel 웹 스크래핑 API를 구축하는 방법을 살펴보겠습니다. 대상 사이트는 Quotes 스크래핑 샌드박스 사이트이며, 스크래핑 엔드포인트는:

  1. 페이지에서 인용문 HTML 요소를 선택합니다
  2. 해당 요소에서 데이터 추출
  3. 스크래핑된 데이터를 JSON 형식으로 반환

대상 사이트의 모습은 다음과 같습니다:

Quotes to scrape page

아래 지침을 따라 Laravel에서 웹 스크래핑을 수행하는 방법을 배워보세요!

1단계: Laravel 프로젝트 설정

터미널을 엽니다. 그런 다음 아래의 Composer create 명령어를 실행하여 Laravel 웹 스크래핑 애플리케이션을 초기화하세요:

composer create-project laravel/laravel laravel-scraper

이제 lavaral-scraper 폴더에 빈 Laravel 프로젝트가 생성됩니다. 선호하는 PHP IDE에서 로드하세요.

현재 백엔드의 파일 구조는 다음과 같습니다:

file structure in the backend

훌륭합니다! 이제 Laravel 프로젝트가 준비되었습니다.

2단계: 스크래핑 API 초기화

프로젝트 디렉터리에서 아래 Artisan 명령어를 실행하여 새로운 Laravel 컨트롤러를 추가하세요:

php artisan make:controller HelloWorldController

그러면 /app/Http/Controllers 디렉터리에 다음과 같은 ScrapingController.php 파일이 생성됩니다:

<?php

namespace AppHttpControllers;

use IlluminateHttpRequest;

class ScrapingController extends Controller

{

//

}

ScrapingController 파일에 다음 scrapeQuotes() 메서드를 추가하세요:

public function scrapeQuotes(): JsonResponse

{

// 스크래핑 로직...

return response()->json('Hello, World!');

}

현재 이 메서드는 'Hello, World!'라는 JSON 메시지를 반환합니다. 곧 Laravel에서 스크래핑 로직이 포함될 예정입니다.

다음 임포트 문 추가를 잊지 마세요:

use IlluminateHttpJsonResponse;

다음 줄을 routes/api.php에 추가하여 scrapeQuotes() 메서드를 전용 엔드포인트에 연결하세요:

use AppHttpControllersScrapingController;

Route::get('/v1/scraping/scrape-quotes', [ScrapingController::class, 'scrapeQuotes']);

좋습니다! 이제 Laravel 스크래핑 API가 원하는 대로 작동하는지 확인할 시간입니다. Laravel API는 /api 경로 아래에서 사용할 수 있다는 점을 기억하세요. 따라서 전체 API 엔드포인트는 /api/v1/scraping/scrape-quotes입니다.

다음 명령어로 Laravel 애플리케이션을 실행하세요:

php artisan serve

이제 서버가 로컬 포트 8000에서 대기 중입니다.

cURL을 사용하여 /api/v1/scraping/scrape-quotes 엔드포인트에 GET 요청을 수행하세요:

curl -X GET 'http://localhost:8000/api/v1/scraping/scrape-quotes'

참고: Windows에서는 curl을 curl.exe로 대체하세요. 자세한 내용은 웹 스크래핑을 위한 cURL 가이드에서 확인하세요.

다음과 같은 응답을 받아야 합니다:

"Hello, World!"

훌륭합니다! 샘플 스크래핑 API가 완벽하게 작동합니다. 이제 Laravel로 스크래핑 로직을 정의할 차례입니다.

3단계: 스크래핑 라이브러리 설치

패키지를 설치하기 전에, 어떤 Laravel 웹 스크래핑 라이브러리가 여러분의 요구에 가장 적합한지 결정해야 합니다. 이를 위해 브라우저에서 대상 사이트를 엽니다. 페이지에서 마우스 오른쪽 버튼을 클릭하고 “검사”를 선택하여 개발자 도구를 엽니다. 그런 다음 “네트워크” 탭으로 이동하여 페이지를 다시 로드하고 “Fetch/XHR” 섹션에 접근합니다:

accessing the 'Fetch XHR' section

보시다시피, 해당 웹페이지는 AJAX 요청을 수행하지 않습니다. 이는 클라이언트 측에서 데이터를 동적으로 로드하지 않음을 의미합니다. 따라서 모든 데이터가 HTML 문서에 내장된 정적 페이지입니다.

페이지가 정적이기 때문에 스크래핑에 헤드리스 브라우저 라이브러리가 필요하지 않습니다. 브라우저 자동화 도구를 사용할 수는 있지만 불필요한 오버헤드만 발생시킬 뿐입니다. 권장되는 접근 방식은 Symfony의 BrowserKitHttpClient 컴포넌트를 사용하는 것입니다.

다음 명령어로 프로젝트 의존성에 symfony/browser-kitsymfony/http-client 컴포넌트를 추가하세요:

composer require symfony/browser-kit symfony/http-client

잘하셨습니다! 이제 Laravel에서 데이터 스크래핑을 수행하는 데 필요한 모든 것을 갖추셨습니다.

4단계: 대상 페이지 다운로드

ScrapingController에서 BrowserKitHttpClient를 임포트하세요:

use SymfonyComponentBrowserKitHttpBrowser;

use SymfonyComponentHttpClientHttpClient;

scrapeQuotes()에서 새로운 HttpBrowser 객체를 초기화합니다:

$browser = new HttpBrowser(HttpClient::create());

이를 통해 브라우저 동작을 시뮬레이션하여 HTTP 요청을 수행할 수 있습니다. 동시에, 실제 브라우저에서 요청을 실행하지 않는다는 점을 기억하세요. HttpBrowser는 쿠키 및 세션 처리와 같은 브라우저와 유사한 기능만 제공합니다.

request() 메서드를 사용하여 대상 페이지의 URL로 HTTP GET 요청을 수행합니다:

$crawler = $browser->request('GET', 'https://quotes.toscrape.com/');

결과는 서버에서 반환된 HTML 문서를 자동으로 파싱하는 Crawler 객체가 됩니다. 이 클래스는 노드 선택 및 데이터 추출 기능도 제공합니다.

크롤러에서 페이지의 HTML을 추출하여 위 로직이 작동하는지 확인할 수 있습니다:

$html = $crawler->outerHtml();

테스트를 위해 API가 이 데이터를 반환하도록 설정하세요.

이제 scrapeQuotes() 함수는 다음과 같이 보일 것입니다:

public function scrapeQuotes(): JsonResponse

{

// 브라우저와 유사한 HTTP 클라이언트 초기화

$browser = new HttpBrowser(HttpClient::create());

// 대상 페이지의 HTML 다운로드 및 파싱

$crawler = $browser->request('GET', 'https://quotes.toscrape.com/');

// 페이지 외부 HTML을 가져와 반환

$html = $crawler->outerHtml();

return response()->json($html);

}

대단하네요! 이제 API는 다음과 같이 반환할 것입니다:

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>스크래핑할 인용문</title>

<link rel="stylesheet" href="/static/bootstrap.min.css">

<link rel="stylesheet" href="/static/main.css">

</head>

<!-- 간결함을 위해 생략 ... -->

5단계: 페이지 콘텐츠 검사

데이터 추출 로직을 정의하려면 대상 페이지의 HTML 구조를 검토하는 것이 필수적입니다.

브라우저에서 Quotes To Scrape 페이지를 엽니다. 그런 다음 인용문 HTML 요소를 마우스 오른쪽 버튼으로 클릭하고 “검사” 옵션을 선택합니다. 브라우저의 개발자 도구에서 HTML을 확장하고 분석을 시작하세요:

Inspecting the quote elements

여기서 각 인용문 카드는 다음을 포함하는 .quote HTML 노드임을 확인하세요:

  1. 인용문 텍스트가 포함된 .text 요소
  2. 저자의 이름을 포함한 .author 노드
  3. 단일 태그를 표시하는 여러 개의 .tag 요소

CSS 선택자들로 Laravel에서 웹 스크래핑을 수행하는 데 필요한 모든 요소를 확보했습니다. 이 선택자들을 활용해 관심 있는 DOM 요소를 타겟팅하고 다음 단계에서 데이터를 추출하세요!

6단계: 웹 스크래핑 준비

대상 페이지에는 여러 인용문이 포함되어 있으므로, 스크래핑된 데이터를 저장할 데이터 구조를 생성하세요. 배열이 이상적입니다:

quotes = []

그런 다음 Crawler 클래스의 filter() 메서드를 사용하여 모든 인용문 요소를 선택합니다:

$quote_html_elements = $crawler->filter('.quote');

이는 지정된 .quote CSS 선택자와 일치하는 페이지의 모든 DOM 노드를 반환합니다.

다음으로, 이들을 반복 처리하며 각각에 데이터 추출 로직을 적용할 준비를 합니다:

foreach ($quote_html_elements as $quote_html_element) {

    // 새 quote 크롤러 생성
    $quote_crawler = new Crawler($quote_html_element);

    // 스크래핑 로직...
}

filter() 가 반환하는 DOMNode 객체는 노드 선택 메서드를 제공하지 않습니다. 따라서 특정 HTML 인용문 요소로 제한된 로컬 크롤러 인스턴스를 생성해야 합니다.

위 코드가 작동하려면 다음 임포트를 추가하세요:

use SymfonyComponentDomCrawlerCrawler;

DomCrawler 패키지를 수동으로 설치할 필요는 없습니다. 이는 BrowserKit 컴포넌트의 직접적인 종속성이기 때문입니다.

대단합니다! Laravel 웹 스크래핑 목표에 한 걸음 더 가까워졌습니다.

7단계: 데이터 스크래핑 구현

foreach 루프 내부에서:

  1. .text, .author, .tag 요소에서 관심 있는 데이터를 추출합니다
  2. 추출한 데이터로 새로운 $quote 객체를 생성합니다
  3. $quote 객체를 $quotes에 추가하세요

먼저 HTML quote 요소 내부의 .text 요소를 선택합니다. 그런 다음 text() 메서드를 사용하여 내부 텍스트를 추출합니다:

$text_html_element = $quote_crawler->filter('.text');

$raw_text = $text_html_element->text();

각 인용문은 "" 특수 문자로 둘러싸여 있습니다. PHP의 str_replace() 함수를 사용하여 다음과 같이 제거할 수 있습니다:

$text = str_replace(["u{201c}", "u{201d}"], '', $raw_text);

마찬가지로 저자 정보는 다음과 같이 추출합니다:

$author_html_element = $quote_crawler->filter('.author');

$author = $author_html_element->text();

태그 추출은 조금 더 까다로울 수 있습니다. 하나의 인용문에 여러 태그가 포함될 수 있으므로 배열을 정의하고 각 태그를 개별적으로 추출해야 합니다:

$tag_html_elements = $quote_crawler->filter('.tag');

$tags = [];

foreach ($tag_html_elements as $tag_html_element) {

$tag = $tag_html_element->textContent;

$tags[] = $tag;

}

filter() 가 반환하는 DOMNode 요소는 text() 메서드를 노출하지 않습니다. 대신 textContent 속성을 제공합니다.

Laravel 데이터 스크래핑 로직 전체는 다음과 같습니다:

// 새 인용문 크롤러 생성

$quote_crawler = new Crawler($quote_html_element);

// 데이터 추출 로직 수행

$text_html_element = $quote_crawler->filter('.text');

$raw_text = $text_html_element->text();

// 원본 텍스트 정보에서 특수 문자 제거

$text = str_replace(["u{201c}", "u{201d}"], '', $raw_text);

$author_html_element = $quote_crawler->filter('.author');

$author = $author_html_element->text();

$tag_html_elements = $quote_crawler->filter('.tag');

$tags = [];

foreach ($tag_html_elements as $tag_html_element) {

    $tag = $tag_html_element->textContent;

    $tags[] = $tag;

}

자, 이제 거의 다 왔습니다!

8단계: 스크랩된 데이터 반환

스크랩한 데이터로 $quote 객체를 생성하고 $quotes에 추가합니다:

$quote = [

'text' => $text,

'author' => $author,

'tags' => $tags

];

$quotes[] = $quote;

다음으로, $quotes 목록으로 API 응답 데이터를 업데이트합니다:

return response()->json(['quotes' => $quotes]);

스크래핑 루프가 끝날 때, $quotes에는 다음이 포함됩니다:

array(10) {

[0]=>

array(3) {

["text"]=>

string(113) "우리가 창조한 세상은 우리의 사고 과정이다. 우리의 사고를 바꾸지 않고서는 세상을 바꿀 수 없다."

["author"]=>

string(15) "알버트 아인슈타인"

["tags"]=>

array(4) {

[0]=>

string(6) "change"

[1]=>

string(13) "deep-thoughts"

[2]=>

string(8) "thinking"

[3]=>

string(5) "world"

}

}

// 생략...

[9]=>

array(3) {

["text"]=>

string(48) "햇빛 없는 하루는, 알다시피, 밤과 같아."

["author"]=>

string(12) "Steve Martin"

["tags"]=>

array(3) {

[0]=>

string(5) "humor"

[1]=>

string(7) "obvious"

[2]=>

string(6) "simile"

}

}

}

좋아요! 이 데이터는 이후 JSON으로 직렬화되어 Laravel 스크래핑 API를 통해 반환됩니다.

9단계: 모든 것을 통합하기

Laravel의 ScrapingController 파일 최종 코드는 다음과 같습니다:

<?php

namespace AppHttpControllers;

use IlluminateHttpRequest;

use IlluminateHttpJsonResponse;

use SymfonyComponentBrowserKitHttpBrowser;

use SymfonyComponentHttpClientHttpClient;

use SymfonyComponentDomCrawlerCrawler;

class ScrapingController extends Controller

{

public function scrapeQuotes(): JsonResponse

{

// 브라우저와 유사한 HTTP 클라이언트 초기화

$browser = new HttpBrowser(HttpClient::create());

// 대상 페이지의 HTML 다운로드 및 파싱

$crawler = $browser->request('GET', 'https://quotes.toscrape.com/');

// 스크랩된 데이터 저장 위치

$quotes = [];

// 페이지 내 모든 quote HTML 요소 선택

$quote_html_elements = $crawler->filter('.quote');

// 각 quote HTML 요소를 반복 처리하며

// 스크래핑 로직 적용

foreach ($quote_html_elements as $quote_html_element) {

// 새 인용문 크롤러 생성

$quote_crawler = new Crawler($quote_html_element);

// 데이터 추출 로직 수행

$text_html_element = $quote_crawler->filter('.text');

$raw_text = $text_html_element->text();

// 원본 텍스트 정보에서 특수 문자 제거

$text = str_replace(["u{201c}", "u{201d}"], '', $raw_text);

$author_html_element = $quote_crawler->filter('.author');

$author = $author_html_element->text();

$tag_html_elements = $quote_crawler->filter('.tag');

$tags = [];

foreach ($tag_html_elements as $tag_html_element) {

    $tag = $tag_html_element->textContent;

    $tags[] = $tag;

}

// 스크랩된 데이터로 새 인용문 객체 생성

$quote = [

'text' => $text,

'author' => $author,

'tags' => $tags

];

// 인용문 객체를 quotes 배열에 추가

$quotes[] = $quote;

}

var_dump($quotes);

return response()->json(['quotes' => $quotes]);

}

}

테스트해 볼 시간입니다!

Laravel 서버 시작:

php artisan serve

그런 다음 /api/v1/scraping/scrape-quotes 엔드포인트에 GET 요청을 수행하세요:

curl -X GET 'http://localhost:8000/api/v1/scraping/scrape-quotes'

다음과 같은 결과를 얻을 수 있습니다:

{

"quotes": [

{

"text": "우리가 창조한 세상은 우리의 사고 과정이다. 사고를 바꾸지 않고서는 세상을 바꿀 수 없다.",

"author": "Albert Einstein",

"tags": [

"change",

"deep-thoughts",

"thinking",

"world"

]

},

// 간결함을 위해 생략...

{

"text": "햇빛 없는 하루는, 말하자면, 밤과 같습니다.",

"author": "Steve Martin",

"tags": [

"humor",

"obvious",

"simile"

]

}

]

}

자, 이제 끝! 100줄도 안 되는 코드로 Laravel에서 웹 스크래핑을 수행했습니다.

다음 단계

여기서 구축한 API는 Laravel로 웹 스크래핑을 수행할 때 달성할 수 있는 기본적인 예시일 뿐입니다. 프로젝트를 한 단계 업그레이드하려면 다음 개선 사항을 고려해 보세요:

  • 웹 크롤링 구현: 대상 사이트에는 여러 페이지에 걸쳐 여러 인용문이 있습니다. 이는 완전한 데이터 수집을 위해 웹 크롤링이 필요한 일반적인 시나리오입니다. 웹 크롤러의 정의에 관한 저희 글을 읽어보세요.
  • 스크래핑 작업 예약: 정기적으로 API를 호출하고 데이터를 데이터베이스에 저장하여 항상 최신 데이터를 확보할 수 있도록 스케줄러를 추가하세요.
  • 프록시 통합: 동일 IP에서 다중 요청 시 스크래핑 방지 조치로 차단될 수 있습니다. 이를 방지하려면 PHP 스크래퍼에 주거용 프록시 통합을 고려하세요.

Laravel 웹 스크래핑 작업을 윤리적이고 존중하는 방식으로 유지하세요

웹 스크래핑은 다양한 목적으로 가치 있는 데이터를 수집하는 효과적인 방법입니다. 그러나 목표는 대상 사이트에 피해를 주지 않고 책임감 있게 데이터를 가져오는 것입니다. 따라서 적절한 예방 조치를 취하며 스크래핑에 접근하는 것이 중요합니다.

책임감 있는 Kotlin 웹 스크래핑을 위해 다음 팁을 따르세요:

  • 사이트의 이용 약관을 확인하고 준수하세요: 사이트를 스크래핑하기 전에 이용 약관을 검토하세요. 여기에는 저작권, 지적 재산권 및 데이터 사용 지침에 대한 정보가 포함되는 경우가 많습니다.
  • robots.txt 파일 준수: 사이트의 robots.txt 파일은 자동 크롤러가 페이지에 접근하는 방식을 규정합니다. 윤리적 관행을 유지하려면 이 지침을 따르세요. 웹 스크래핑을 위한 robots.txt 가이드에서 더 알아보세요.
  • 공개된 정보만 대상으로 하세요: 공개적으로 접근 가능한 데이터에 집중하세요. 로그인 자격 증명이나 기타 인증 방식으로 보호되는 페이지는 스크래핑하지 마세요. 적절한 허가 없이 사적 또는 민감한 데이터를 대상으로 하는 것은 비윤리적이며 법적 결과를 초래할 수 있습니다.
  • 요청 빈도를 제한하세요: 짧은 시간에 너무 많은 요청을 하면 서버에 과부하가 걸려 모든 사용자의 사이트 성능에 영향을 미칠 수 있습니다. 이는 속도 제한 조치로 이어져 차단될 수도 있습니다. 요청 사이에 무작위 지연을 추가하여 대상 서버에 과부하가 걸리지 않도록 하세요.
  • 신뢰할 수 있고 최신 스크래핑 도구를 사용하세요: 평판이 좋은 공급자를 선호하고, 잘 관리되며 정기적으로 업데이트되는 도구를 선택하세요. 이는 최신 윤리적 Laravel 스크래핑 관행과 부합함을 보장합니다. 확신이 서지 않는다면, 최고의 웹 스크래핑 서비스 선택 방법에 관한 저희 글을 참고하세요.

결론

이 가이드에서는 Laravel이 웹 스크래핑 API 구축에 적합한 프레임워크인 이유를 살펴보았습니다. 또한 최고의 스크래핑 라이브러리 몇 가지를 탐색할 기회도 가졌습니다. 이후 대상 페이지에서 실시간으로 데이터를 추출하는 Laravel 웹 스크래핑 API 생성 방법을 배웠습니다. 보셨듯이 Laravel을 활용한 웹 스크래핑은 간단하며 몇 줄의 코드만으로 가능합니다.

문제는 대부분의 사이트가 봇 방지 및 스크래핑 방지 솔루션으로 데이터를 보호한다는 점입니다. 이러한 기술은 자동화된 요청을 탐지하고 차단할 수 있습니다. 다행히 Bright Data는 스크래핑을 쉽게 만드는 일련의 솔루션을 제공합니다:

  • 스크래핑 브라우저: 클라우드 기반 제어 가능 브라우저로, 자바스크립트 렌더링 기능을 제공하며 CAPTCHA 처리, 브라우저 지문 인식, 자동 재시도 등을 자동으로 처리합니다. Playwright, Puppeteer 등 가장 널리 쓰이는 자동화 브라우저 라이브러리와 통합됩니다.
  • 웹 언락커(Web Unlocker): 모든 페이지의 깨끗한 HTML을 원활하게 반환하여 스크래핑 방지 조치를 우회하는 언락킹 API입니다.
  • 웹 스크래핑 API: 수십 개의 인기 도메인에서 구조화된 웹 데이터에 프로그래밍 방식으로 접근할 수 있는 엔드포인트입니다.

웹 스크래핑은 다루기 싫지만 온라인 데이터에는 여전히 관심이 있으신가요? Bright Data의 즉시 사용 가능한 데이터 세트를 살펴보세요!

지금 가입하고 무료 체험을 시작하세요.