파이썬과 자바스크립트는 스크래핑 산업 전체를 주도합니다. 성능이나 이식성이 필요하다면 스칼라가 강력한 대안을 제공합니다. 스칼라는 컴파일 가능하고 이식성 있으며 강력한 타입 시스템을 갖춘 기반을 제공합니다.
오늘은 Scala와jsoup을 사용한 스크래핑 방법을 살펴보겠습니다. Python을 이용한 웹 스크래핑만큼 자주 다루어지지는 않지만, Scala는 강력한 기반과 괜찮은 스크래핑 도구를 제공합니다.
왜 스칼라인가?
파이썬이나 자바스크립트 대신 스칼라를 선택할 만한 이유는 꽤 많습니다.
- 성능: 스칼라는 JVM(자바 가상 머신)으로 컴파일됩니다. 컴파일러가 코드를 기계가 실행 가능한 바이트코드로 변환하므로 본질적으로 파이썬보다 빠릅니다.
- 정적 타입 검사: 타입 검사는 추가적인 안전성을 제공합니다. 많은 일반적인 버그가 프로그램이 실행되기 전에 발견됩니다.
- 이식성: 스칼라는 JVM(자바 가상 머신) 바이트코드로 컴파일됩니다. JVM 바이트코드는 자바가 설치된 어디서나 실행 가능합니다.
- Java와의 완벽한 호환성: Scala 코드에서 Java 종속성을 사용할 수 있습니다. 이는 이용 가능한 생태계를 크게 확장합니다.
시작하기
시작하기 전에 Scala가 설치되어 있는지 확인해야 합니다. 아래에 Ubuntu, macOS, Windows용 설치 안내가 있습니다.
설치에 관한 전체 문서는여기에서 확인할 수 있습니다.
Ubuntu
curl -fL https://github.com/coursier/coursier/releases/latest/download/cs-x86_64-pc-linux.gz | gzip -d > cs && chmod +x cs && ./cs setup
macOS
brew install coursier && coursier setup
Windows
Windows용 Scala 설치 프로그램을 다운로드하세요.
스크레이퍼 생성
새 프로젝트 폴더를 만들고 해당 폴더로 이동합니다.
mkdir quote-scraper
cd quote-scraper
새 Scala 프로젝트를 초기화합니다. 이 명령어는 새 폴더를 Scala 프로젝트로 변환하고 종속성을 저장할 build.sbt 파일을 생성합니다.
sbt new scala/scala3.g8
이제 build.sbt 파일을 엽니다. jsoup을 의존성으로 추가해야 합니다. 완성된 빌드 파일은 다음과 같아야 합니다.
val scala3Version = "3.6.3"
lazy val root = project
.in(file("."))
.settings(
name := "quote-scraper",
version := "0.1.0-SNAPSHOT",
scalaVersion := scala3Version,
libraryDependencies += "org.scalameta" %% "munit" % "1.0.0" % Test,
libraryDependencies += "org.jsoup" % "jsoup" % "1.18.3"
)
다음으로, 아래 코드를 Main.scala 파일에 복사하여 붙여넣으세요.
import org.jsoup.Jsoup
import scala.jdk.CollectionConverters._
@main def QuotesScraper(): Unit =
val url = "http://quotes.toscrape.com"
try
val document = Jsoup.connect(url).get()
// 페이지에서 quote 클래스를 가진 모든 객체 찾기
val quotes = document.select(".quote")
for quote <- quotes.asScala do
// "text" 클래스를 가진 첫 번째 객체 찾기 및 텍스트 반환
val text = quote.select(".text").text()
// "author" 클래스를 가진 첫 번째 객체 찾기 및 텍스트 반환
val author = quote.select(".author").text()
println(s"Quote: $text")
println(s"Author: $author")
println("-" * 50)
catch case e: Exception => println(s"Error: ${e.getMessage}")
스크레이퍼 실행
스크레이퍼를 실행하려면 프로젝트 루트 디렉터리에서 다음 명령어를 실행하세요.
sbt run
아래와 유사한 출력이 표시됩니다.
Quote: “우리가 창조한 세상은 우리의 사고 과정입니다. 우리의 사고를 바꾸지 않고서는 세상을 바꿀 수 없습니다.”
Author: Albert Einstein
--------------------------------------------------
인용: "해리, 우리의 진정한 모습을 드러내는 것은 능력보다 선택이다."
저자: J.K. 롤링
--------------------------------------------------
인용: “삶을 사는 방법은 단 두 가지뿐이다. 하나는 아무것도 기적처럼 여기지 않는 방식이고, 다른 하나는 모든 것을 기적처럼 여기는 방식이다.”
저자: 알버트 아인슈타인
--------------------------------------------------
인용: "좋은 소설에서 즐거움을 느끼지 못하는 사람은, 신사든 숙녀든, 참을 수 없을 만큼 어리석은 사람일 것이다."
저자: 제인 오스틴
--------------------------------------------------
인용: “불완전함은 아름다움이고, 광기는 천재성이다. 그리고 완전히 우스꽝스러운 사람이 되는 것이 완전히 지루한 사람이 되는 것보다 낫다.”
저자: 마릴린 먼로
--------------------------------------------------
인용: “성공한 사람이 되려 하지 마라. 차라리 가치 있는 사람이 되라.”
저자: 알베르트 아인슈타인
--------------------------------------------------
인용: “있는 그대로의 모습으로 미움받는 것이, 없는 모습으로 사랑받는 것보다 낫다.”
저자: 앙드레 지드
--------------------------------------------------
인용: "나는 실패한 것이 아니다. 단지 통하지 않는 만 가지 방법을 발견했을 뿐이다."
저자: 토머스 A. 에디슨
--------------------------------------------------
인용: "여자는 티백과 같다. 뜨거운 물에 담그기 전까지는 그 강도를 알 수 없다."
작가: 엘리너 루스벨트
--------------------------------------------------
인용: "햇빛 없는 하루는, 알다시피, 밤과 같다."
저자: 스티브 마틴
--------------------------------------------------
[성공] 총 소요 시간: 6초, 완료일: 2026년 2월 18일 오후 8:58:04
jsoup을 이용한 선택
jsoup으로 페이지 요소를 찾으려면 select() 메서드를 사용합니다. select()는 선택자에 맞는 모든 요소의 목록을 반환합니다. Quote Scraper 프로젝트에서 이 메서드가 어떻게 작동하는지 살펴보겠습니다.
이 코드에서는 document.select(".quote") 를 사용해 quote 클래스를 가진 모든 페이지 요소를 반환합니다.
val quotes = document.select(".quote")
보다 구조화된 형식인 element[attribute='some value']로 선택자를 작성할 수도 있습니다. 이렇게 하면 페이지에서 객체를 검색할 때 더 강력한 필터를 적용할 수 있습니다.
아래 줄은 동일한 페이지 객체를 반환하지만 훨씬 더 표현력이 뛰어납니다.
val quotes = document.select("div[class='quote']")
코드 내 select() 의 다른 사용 사례를 살펴보겠습니다. 각 인용문에 텍스트 요소와 저자가 하나씩만 존재하므로 select() 는 텍스트 객체 하나와 저자 객체 하나만 반환합니다. 만약 인용문 요소에 여러 텍스트나 저자가 포함되어 있다면, 각 인용문에 해당하는 모든 텍스트와 저자를 반환할 것입니다.
// "text" 클래스를 가진 객체를 찾아 텍스트 반환
val text = quote.select(".text").text()
// "author" 클래스를 가진 객체를 찾아 텍스트 반환
val author = quote.select(".author").text()
jsoup을 이용한 추출
jsoup으로 데이터를 추출하려면 다음 메서드를 사용할 수 있습니다:
text(): 페이지 요소 목록에서 텍스트를 추출합니다. 웹사이트에서 가격을 스크래핑할 때, 해당 가격은 페이지에 텍스트 형태로 표시됩니다.attr(): 단일 페이지 요소에서 특정 속성을 추출합니다. 이는 HTML 태그 내에 위치한 데이터 조각입니다. 이 메서드는 웹사이트에서 링크를 추출하는 데 흔히 사용됩니다.
text()
초기 스크래퍼 예제에서 이 메서드를 확인했습니다. text() 는 호출된 모든 요소의 텍스트를 반환합니다. 아래 예제에서 두 명의 저자를 찾는 경우, text()는 두 사람의 텍스트를 모두 추출하여 하나의 문자열로 결합합니다.
//클래스 "text"를 가진 객체를 찾아 텍스트 반환
val text = quote.select(".text").text()
//클래스 "author"를 가진 객체를 찾아 텍스트 반환
val author = quote.select(".author").text()
attr()
attr() 메서드는 text()와 다르게 동작합니다. 이 메서드는 단일 페이지 항목에서 단일 속성을 추출합니다.
//클래스 "tag"를 가진 링크 요소를 찾고 첫 번째 요소의 "href"를 추출
val firstTagLink = quote.select("a[class='tag']").attr("href")
이 줄을 추가하면 출력 결과가 다음과 같습니다.
인용문: “우리가 창조한 세상은 우리의 사고 과정이다. 우리의 사고를 바꾸지 않고서는 세상을 바꿀 수 없다.”
저자: Albert Einstein
첫 번째 태그 링크: /tag/change/page/1/
--------------------------------------------------
인용문: “해리, 우리의 진정한 모습을 보여주는 것은 능력보다 선택이다.”
저자: J.K. 롤링
첫 번째 태그 링크: /tag/abilities/page/1/
--------------------------------------------------
인용문: "인생을 사는 방법은 단 두 가지뿐이다. 하나는 아무것도 기적처럼 여기지 않는 삶이고, 다른 하나는 모든 것을 기적처럼 여기는 삶이다."
저자: 알버트 아인슈타인
첫 번째 태그 링크: /tag/inspirational/page/1/
--------------------------------------------------
인용: "좋은 소설에서 즐거움을 느끼지 못하는 사람은, 신사든 숙녀든, 참을 수 없을 만큼 어리석은 사람일 것이다."
저자: 제인 오스틴
첫 번째 태그 링크: /tag/aliteracy/page/1/
--------------------------------------------------
인용: "불완전함은 아름다움이고, 광기는 천재성이다. 그리고 완전히 우스꽝스러운 편이 완전히 지루한 편보다 낫다."
저자: 마릴린 먼로
첫 번째 태그 링크: /tag/be-yourself/page/1/
--------------------------------------------------
인용: "성공한 사람이 되려 하지 마라. 차라리 가치 있는 사람이 되라."
저자: 알베르트 아인슈타인
첫 번째 태그 링크: /tag/adulthood/page/1/
--------------------------------------------------
인용: “있는 그대로의 모습으로 미움받는 것이, 없는 모습으로 사랑받는 것보다 낫다.”
저자: 앙드레 지드
첫 번째 태그 링크: /tag/life/page/1/
--------------------------------------------------
인용: “나는 실패한 것이 아니다. 단지 1만 가지 안 되는 방법을 발견했을 뿐이다.”
저자: 토머스 에디슨
첫 번째 태그 링크: /tag/edison/page/1/
--------------------------------------------------
인용: "여자는 티백과 같다. 뜨거운 물에 담기기 전까지는 그 강도를 알 수 없다."
저자: 엘리너 루스벨트
첫 번째 태그 링크: /tag/misattributed-eleanor-roosevelt/page/1/
--------------------------------------------------
인용: "햇빛 없는 날은, 알다시피, 밤과 같아."
저자: 스티브 마틴
첫 번째 태그 링크: /tag/humor/page/1/
--------------------------------------------------
[성공] 총 소요 시간: 3초, 완료 일시: 2026년 2월 18일 오후 10:29:30
대체 웹 스크래핑 도구
- 스크래핑 브라우저: 프록시와 완벽하게 통합된 원격 브라우저로,Playwright 및 Selenium에서 사용할 수 있습니다.
- 웹 스크레이퍼 API: 당사 API 중 하나를 호출하여 스크래핑 프로세스를 자동화하세요. 스크레이퍼 API를 호출하면 당사가 사이트를 스크래핑하여 데이터를 귀하에게 전송합니다.
- 노코드 스크레이퍼: 스크레이핑할 사이트와 원하는 데이터를 알려주십시오. 나머지는 저희가 처리합니다.
- 데이터셋: 당사의 데이터셋은 아마도 모든 추출 방법 중 가장 간편할 것입니다. 수백 개의 사이트를 스크래핑하고 데이터베이스를 지속적으로 업데이트합니다. 데이터셋은 분석 준비가 완료된 깨끗한 데이터 세트를 제공합니다.
결론
Scala를 사용하면 웹 스크래핑이 매우 직관적입니다.jsoup을 활용해 페이지 요소를 선택하고 데이터를 추출하는 방법을 배웠습니다. 스크래핑이 부담스럽다면 자동화 도구를 활용해 프로세스를 지원받거나, 즉시 사용 가능한 데이터셋으로 스크래핑 과정을 완전히 생략할 수 있습니다.
지금 가입하고 무료 체험을 시작하세요!