주석이 달린 기사 중심 테스트 세트에서 newspaper4k는 22개 모든 fixtures에서 결과를 만들어 냈고, 채점 대상 기사 단위의 **98.65%**를 복원했으며, 라벨이 붙은 보일러플레이트 토큰은 단 하나도 섞지 않았습니다. 이 세 가지 결과만 놓고 보면 이번 테스트의 우선순위에서는 아주 강력한 후보지만, 그렇다고 곧바로 모든 상황에서의 승자라는 뜻은 아닙니다.
이 세 가지 관찰 결과를 모두 동시에 만족한 도구는 이 세트에서 다른 어떤 것도 없었습니다. Mozilla Readability는 채점 대상 콘텐츠 단위를 전부 복원했지만 보일러플레이트가 더 많이 섞였고, goose3는 라벨된 보일러플레이트를 넣지 않았지만 두 번은 빈 문자열을 반환했습니다. 어떤 기준으로 보느냐에 따라 더 맞는 라이브러리는 달라질 수 있습니다.
배포 전에 꼭 짚고 넘어가야 할 기본 설정이 하나 있습니다.
newspaper4k란 무엇인가
newspaper4k는 newspaper3k의 유지보수 포크이며, newspaper3k는 원래 newspaper의 Python 3 계열 후속 버전이었습니다. 이 계보는 도움말을 찾을 때 꽤 중요합니다. 온라인에서 찾는 자료 대부분이 이전 버전을 기준으로 하고 있고, 일부 API는 위치가 달라졌기 때문입니다.
공식 저장소: newspaper4k 공식 저장소.

이 라이브러리를 가장 흔하게 잘못 쓰는 방식은 예를 들어 set_html()을 호출하는 것입니다. 그런 메서드는 없습니다. HTML은 download()로 넣어야 합니다:
from newspaper import Article
a = Article(url="https://example.com/story")
a.download(input_html=html) # not set_html()
a.parse()
text = a.text
저도 첫 실행에서 이 부분을 잘못 써서, 원인이 제 쪽인지 확인하기 전에는 22개 fixtures 중 0개로 채점했습니다. 결국 제 실수였습니다.
반환되는 건 단순한 텍스트만이 아닙니다. Article 객체는 text, title, authors, publish_date, top_image, images, movies, meta_description, meta_lang, tags, article_html 같은 필드를 제공합니다. keywords와 summary는 아래에 설명한 선택적 NLP 설치와 말뭉치 설정이 필요합니다. 필드 자체는 확인했지만 메타데이터 정확도는 채점하지 않았습니다.
테스트 버전: 0.9.6, MIT 라이선스, GitHub 별 1,135개, 저장소 푸시 날짜는 2026-07-31입니다. 이 날짜 기반 활동은 현재 시점의 한 스냅샷일 뿐, 유지보수 상태 전체를 평가한 것은 아닙니다. Python 3.14.2.
결과
| 라이브러리 | 기사 재현율(22개 전체) | 보일러플레이트 유입 | 콘텐츠 토큰 정밀도 | 섞여 들어간 토큰 | 결과 생성 |
|---|---|---|---|---|---|
| Readability | 1.0000 | 0.2353 | 0.9109 | 35 | 22/22 |
| trafilatura | 0.9865 | 0.0588 | 0.9411 | 4 | 22/22 |
| newspaper4k | 0.9865 | 0.0000 | 0.9452 | 0 | 22/22 |
| resiliparse | 0.9054 | 0.0588 | 0.9381 | 7 | 22/22 |
| jusText | 0.8378 | 0.4706 | 0.8760 | 74 | 19/22 |
| goose3 | 0.8243 | 0.0000 | 1.0000 | 0 | 20/22 |
sixway-scores.json. 각 fixture의 모든 단위에는 고유한 센티넬 토큰이 들어 있어, “복원됨”과 “유입됨”은 유사도 점수가 아니라 정확한 부분 문자열 포함 여부를 뜻합니다. 재현율은 22개 전체 fixture 기준이며, 유입률과 정밀도는 기사와 보일러플레이트가 함께 있는 11개 fixture 기준입니다.
세 개의 열은 따로 떼어 봐야 합니다.
모든 페이지에 응답했습니다. goose3와 jusText는 그렇지 못했습니다. 각각 20개, 19개였습니다. 표만 보면 사소해 보일 수 있지만, 이 차이는 꽤 중요합니다. 이 표에서 정밀도와 F1은 출력을 생성한 경우에만 의미가 있기 때문입니다. 빈 문자열을 반환한 라이브러리는 비율의 어느 쪽에도 기여하지 않으니, 아예 응답하지 않는 게 공짜처럼 보일 수 있습니다. goose3의 1.0000 정밀도는 11개 중 10개 fixture 기준으로 계산된 것이고, newspaper4k의 0.9452는 11개 중 11개 기준입니다. 같은 측정값이라고 보긴 어렵습니다.
보일러플레이트를 전혀 새지 않았습니다. fixtures에는 일부러 까다롭게 만든 보일러플레이트가 들어 있습니다. 기사 옆에 붙은 중립 클래스 프로모션 블록, 멀쩡해 보이는 class 이름을 쓴 댓글 스레드, ad라고 적지 않은 광고 블록 등이 그렇습니다. Readability의 sibling-append 휴리스틱은 몇 개를 흡수했지만, newspaper4k는 하나도 섞어 넣지 않았습니다.
74개 중 1개만 놓쳤고, 그 놓친 항목도 다른 라이브러리와 겹칩니다.
놓친 것은 비서술형(non-prose) fixture입니다. 문단 중심이 아니라 표, 코드 블록, 짧은 항목, 이미지 캡션으로 구성된 페이지인데, 여기서 빠진 단위는 캡션입니다. newspaper4k만 그런 것은 아닙니다.
| 라이브러리 | 비서술형 페이지 재현율 | 누락된 단위 |
|---|---|---|
| Readability | 1.000 | — |
| jusText | 1.000 | — |
| trafilatura | 0.875 | 캡션 |
| resiliparse | 0.875 | 캡션 |
| newspaper4k | 0.875 | 캡션 |
| goose3 | 0.250 | 두 표, 코드 블록, 짧은 항목 2개, 캡션 |
세 라이브러리가 같은 캡션만 놓치고 다른 항목은 놓치지 않았다는 점은, 서로 다른 세 버그라기보다 캡션의 가치를 공통적으로 낮게 보는 상속된 가정처럼 보입니다. 문서, 레시피, 또는 캡션이 문단보다 더 많은 정보를 담는 콘텐츠라면, 적용 전에 꼭 테스트해 볼 가치가 있습니다. Readability와 jusText는 이 캡션을 유지했습니다.
같은 fixture에서 goose3는 사실상 완전히 무너졌고, 페이지의 4분의 3을 잃었습니다. 즉 “비서술형 콘텐츠”는 헤드라인 표보다 훨씬 더 크게 라이브러리 차이를 드러내는 축입니다.
속도 면에서 newspaper4k의 22개 fixture 기준 중앙 추출 시간은 2.69 ms로, 6개 중 가장 느렸고 최악의 경우는 199.81 ms였습니다. resiliparse의 0.06 ms 중앙값과 비교하면 이번 통제 실행에서는 45배 차이입니다. 단일 페이지 워크플로에서는 중앙값이 작아 보여도, 처리량과 부하 상황의 tail latency는 따로 보지 않았습니다. 차가운 import 시간은 아래에서 별도로 측정했습니다.
첫 줄에서 바꾸고 싶은 기본값

공식 문서: newspaper4k 문서.
기본 제공 Configuration 객체를 읽어 보면 22개의 설정이 있습니다. 그중 하나가 바로 이것입니다:

_honor_robotstxt = False
newspaper4k는 별도로 지정하지 않으면 robots.txt를 따르지 않습니다. Article(url).download()처럼 input_html 없이 가져오게 두면, 사이트의 robots 파일이 뭐라고 하든 지정한 URL을 그대로 가져옵니다.
이미 가지고 있는 HTML을 파싱하는 것이 주 용도인 라이브러리로서는 충분히 설명 가능한 기본값이지만, 프로덕션에서 천 개 URL을 겨냥한 뒤에야 발견하면 곤란한 기본값이기도 합니다. Configuration에서 honor_robotstxt=True로 바꾸거나, 제가 이 테스트에서 그랬듯 input_html을 넘기고 직접 가져오세요.
추가로 알아둘 점 두 가지:
number_threads = 10. 여러 문서를 한꺼번에 처리하는 도우미의 기본 병렬도는 10입니다. 동시성은 초당 요청 수와 같지 않지만, 호스트별 제한과 스케줄링을 명시하지 않으면 동시에 요청이 몰릴 수 있습니다.
fetch_images = True. 이미지 가져오기가 기본 활성화되어 있어 오프라인 사용 시점에 의문이 생길 수 있습니다. socket.connect를 차단한 상태에서, 테스트한 newspaper4k 0.9.6 경로—즉 download(input_html=…) 후 parse()를 한 번 보관된 HTML 입력에 대해 실행한 경로—는 완료됐고, 1,292자를 반환했으며, 네트워크 연결 시도는 0건이었습니다. 이는 이 정확한 경로를 지지하는 결과이지, 모든 설정·플러그인·콘텐츠 타입·향후 릴리스를 모두 보장하는 것은 아닙니다.
나머지 값들은 무난합니다. min_word_count 300, min_sent_count 7, max_text 100,000, http_success_only True, memorize_articles True, follow_meta_refresh False, allow_binary_content False.
설치 현실
pip install newspaper4k는 약 6초 만에 22개 패키지와 47.5 MiB를 내려받습니다. 새 subprocess에서의 차가운 import는 2.812초로, 비교 대상 중 가장 느렸습니다.
| 라이브러리 | 패키지 수 | site-packages | 차가운 import | 추출 p50 |
|---|---|---|---|---|
| resiliparse | 5 | 21.0 MiB | 0.015 s | 0.06 ms |
| jusText | 3 | 22.4 MiB | 0.777 s | 0.56 ms |
| goose3 | 16 | 44.3 MiB | 2.181 s | 1.85 ms |
| newspaper4k | 22 | 47.5 MiB | 2.812 s | 2.69 ms |
| trafilatura | 17 | 69.9 MiB | 1.584 s | 0.51 ms |
install-and-import.json. 각 라이브러리는 서로 의존성을 물려받지 않는 완전히 비어 있는 가상환경에서 실행했습니다.
가져오는 데 2.812초는 resiliparse의 15밀리초보다 187배 느립니다. 오래 도는 워커에서는 한 번만 치르면 되니 큰 문제 아닐 수도 있습니다. 하지만 서버리스 함수에서는 콜드 스타트마다 치러야 하므로, 추출 품질이 아무리 좋아도 newspaper4k가 안 맞는 경우가 있습니다.
설치할 때 조금 거슬리는 점도 있습니다. import하면 경고가 뜹니다:
UserWarning: nltk is not installed. Some NLP features will be unavailable. Install it with: pip install 'newspaper4k[nlp]'
이번 테스트에서는 그 기능들이 필요하지 않았고, NLP 없이도 추출은 잘 됐습니다. 다만 기본 설치가 완전한 설치는 아니며, newspaper4k[nlp]는 훨씬 더 무거운 의존성 트리와 말뭉치 다운로드를 불러옵니다. 키워드와 요약이 필요할 때만 그 비용을 감수하세요.
메모리, 그리고 깨진 HTML이 메모리에 미치는 영향
이번 비교군의 모든 리뷰에서 “미측정”으로 남아 있던 두 가지를 이제 측정했습니다.
더 넓은 스트레스 테스트 맥락은 10개 라이브러리의 메모리 및 잘못된 HTML 비교에 있습니다.
최대 상주 메모리는 /usr/bin/time -l로 측정했으며, 각 셀마다 새 프로세스를 사용했습니다. import 하한은 라이브러리가 로드되어 유휴 상태일 때 드는 비용이고, peak에는 문서 자체가 포함됩니다.
| 라이브러리 | 런타임 | import 하한(MiB) | 226 KB HTML peak(MiB) | 10 MB HTML peak(MiB) |
|---|---|---|---|---|
| html2text | python3.14 | 18.7 | 19.9 | 71.2 |
| pyquery | python3.14 | 30.3 | 33.9 | 172.5 |
| resiliparse | python3.14 | 20.5 | 25.1 | 225.1 |
| markdownify | python3.14 | 23.9 | 28.9 | 278.5 |
| goose3 | python3.14 | 44.1 | 52.4 | 398.5 |
| cheerio | node22 | 66.8 | 76.5 | 398.5 |
| justext | python3.14 | 30.3 | 36.6 | 431.2 |
| newspaper4k | python3.14 | 52.6 | 61.8 | 668.5 |
| trafilatura | python3.14 | 52.5 | 64.8 | 927.1 |
| turndown | node22 | 47.8 | 68.4 | 2947.1 |
memory-results.json. Python과 Node의 기준선은 서로 직접 비교할 수 없습니다. 두 경우 모두 인터프리터가 포함되어 있기 때문입니다.
newspaper4k의 하한은 52.6 MiB이고, 10 MB HTML에서의 peak는 668.5 MiB입니다. Python 라이브러리 중에서는 두 번째로 무겁습니다. 일반적인 페이지에서는 둘 다 큰 문제 아닐 수 있지만, 메모리 제한이 있는 워커에서 큰 문서를 배치 처리할 때는 중요해집니다.
깨진 HTML. 정확히 한 가지씩만 망가진 12개 문서—닫히지 않은 태그, 잘못 중첩된 인라인 요소, 공백이 있는 따옴표 없는 속성, 남는 닫는 태그, <html> 자체가 없음, 중복 속성, 태그 도중 잘린 문서, 잘못된 엔티티, 닫히지 않은 <script>, 거짓 charset 선언, 마크업을 담은 주석, 600단계 중첩—에 더해, 같은 크기의 정상 문서 2개를 넣었습니다. “아무것도 반환하지 않았다”는 말이 잘못된 HTML 때문인지 알려면, 같은 크기의 깨끗한 문서에도 라이브러리가 침묵하지 않아야 하기 때문입니다.
정상 문서와 깨진 문서는 원시 결과에서 확실히 갈립니다:
| 그룹 | 문서 수 | 예외 발생 | 빈 출력 | 채점 가능한 센티넬 복원 |
|---|---|---|---|---|
| 정상 형식의 일치 제어군 | 2 | 0 | 0 | malformed 점수에는 사용하지 않음 |
| 깨진 fixtures | 12 | 0 | 10 | 5/33, 닫히지 않은 <script> 사례 제외 |
두 개의 제어군은 각각 70자와 1,351자를 생성했고, 12개 깨진 입력 중 10개는 빈 문자열을 반환했습니다. 이 설계에서는 침묵을 단순히 입력이 짧아서가 아니라 malformed 때문이라고 볼 수 있습니다. 채점기는 11개의 적격 malformed 문서에서 heading, paragraph, link 센티넬을 검사합니다. 닫히지 않은 \<script> fixtures는 HTML5 파서 규칙상 뒤따르는 마크업이 script 내용으로 남기 때문에 제외했습니다. malformed-results.json를 참고하세요. 이는 단순히 “예외를 던지지 않았다” 수준이 아니라, 선택에 반드시 반영해야 할 중요한 복원 한계입니다.
장단점
장점. 이번 비교에서 라벨된 보일러플레이트 토큰이 없었고, 22개 통제 기사 fixture 모두에서 출력을 생성했으며, 채점된 기사 재현율은 0.9865였습니다. 기사 텍스트와 메타데이터 필드를 노출하지만 메타데이터 정확도는 테스트하지 않았습니다. socket.connect를 차단한 상태에서 보관 HTML 경로는 네트워크 시도를 하지 않았습니다. 확인 시점에 저장소에는 최근 날짜의 푸시가 있었습니다. 다만 전반적인 유지보수 상태는 평가하지 않았습니다.
단점. 이 세트에서 가장 무거운 콜드 import인 2.812초와, 측정된 site-packages 47.5 MiB / 22개 패키지가 부담입니다. honor_robotstxt 기본값은 False이고, 여러 문서를 다루는 도우미는 기본적으로 10개 스레드를 씁니다. 기본 설치는 NLTK 부재 경고를 내므로, 키워드와 요약을 쓰려면 더 무거운 선택 설치가 필요합니다. 가장 중요한 점은, 두 개의 정상 형식 제어군은 텍스트를 생성했는데도 12개의 malformed fixture 중 10개가 빈 출력을 냈다는 사실입니다.
누가 써야 하고, 누가 피해야 하나
newspaper4k를 고려할 만한 경우는 다음 순서의 우선순위를 가질 때입니다: 통제된 기사 중심 코퍼스에서 비어 있지 않은 텍스트를 만들 것, 그 코퍼스에서 라벨된 보일러플레이트를 최소화할 것, 그리고 더 느린 콜드 import를 감수할 것. 이 명시적 기준 아래에서는 이번 fixture 비교의 선두였습니다. 다른 기준을 쓰면 최대 채점 콘텐츠 보존을 원할 때 Readability를, 시작 속도와 중앙 추출 속도를 원할 때 resiliparse를 고를 수 있습니다.
다음 상황에서는 쓰지 않거나, 배포 전에 아주 신중히 검증하세요. 콜드 스타트가 핵심인 경우, 측정된 site-packages 47.5 MiB가 부담되는 경우, 또는 malformed 복원이 중요할 때입니다. 여기서는 resiliparse가 187배 더 빨리 import되었지만, 품질 열 전부에서 trafilatura와 동률은 아니었습니다. trafilatura가 기사 재현율은 더 높았고, 유입과 정밀도 프로필도 달랐습니다. newspaper4k는 기사 중심 도구이며, 상품 목록이나 대시보드는 테스트하지 않았으므로 그쪽 동작은 여기서 주장하지 않습니다.
어떤 경우든 가져오기 기능을 쓴다면 honor_robotstxt는 반드시 설정하세요. 이건 성능 관련 메모가 아닙니다.
관리형 API가 들어갈 자리
newspaper4k는 호출자가 제공한 HTML을 파싱할 수 있고, 가져오기 경로도 있습니다. 관리형 추출 서비스는 수집, 렌더링, 스키마 작업을 벤더 경계 뒤로 옮깁니다. 우리는 Thunderbit를 만들고 있지만, 이번 fixture 세트에서는 실행하지 않았기 때문에 품질, 렌더링, 안티봇, 지연, 비용 비교를 제공하지 않습니다. 보관된 기사 HTML에 관해서는 여기의 증거는 newspaper4k 자체에만 해당하며, 기사 이외의 대상은 별도 평가가 필요합니다.
같은 fixtures를 6개 추출기 전체에 대해 비교한 내용은 6개 라이브러리 추출 비교를 보세요.
호스티드 서비스 관점은 웹 스크래핑 API 총정리가 더 넓은 그림이고, 자체 호스팅 대안은 오픈소스 스크래퍼 핵심 가이드를 참고하세요. 텍스트를 모델에 넣을 계획이라면 Python에서 HTML을 Markdown으로 변환하기에서 fidelity가 어디서 손실되는지도 다룹니다.
newspaper4k를 써야 할까?
HTML을 이미 가지고 있는 상태에서 기사 텍스트 추출이 필요하다면 newspaper4k를 유력한 후보로 보고, 실제 사이트 코퍼스로 사전 검증한 뒤 도입하세요. 통제된 세트에서는 높은 채점 기사 재현율, 라벨된 보일러플레이트 없음, 그리고 22개 기사 중심 fixture 모두에서 비어 있지 않은 출력이 확인됐습니다. 다만 실제 페이지나 메타데이터 정확도는 다루지 않았고, 12개 malformed fixture 중 10개는 빈 출력을 냈습니다.
가져오기 경로를 쓴다면 honor_robotstxt=False, 10개 스레드 병렬성, 호스트별 속도 제한을 반드시 검토하세요. 콜드 스타트나 의존성 크기가 중요하다면, 2.812초의 로컬 import와 47.5 MiB의 site-packages를 배포 환경 기준으로 직접 측정해 보세요. 범용 컨테이너 비용으로 그냥 넘기면 안 됩니다.
웹 데이터 추출용 Thunderbit 사용해 보기 Get Started Free
자주 묻는 질문
왜 set_html()이 작동하지 않나요?
newspaper4k에는 그 메서드가 없기 때문입니다. HTML은 download(input_html=html)로 넣고, 그다음 parse()를 호출해야 합니다. 검색 결과에 newspaper3k 예시가 섞여 나와 이런 실수를 하기 쉽습니다. 저도 첫 실행에서 그렇게 했고, 채점 전에 하네스를 고쳤습니다.
newspaper4k는 robots.txt를 따르나요?
기본적으로는 따르지 않습니다. honor_robotstxt 기본값이 False입니다. 라이브러리가 직접 가져오게 둘 경우 Configuration에서 True로 바꾸세요. 아니면 input_html을 넘기고 직접 가져오면 됩니다. 여러 문서를 다루는 작업도 기본적으로 10개 스레드를 씁니다. 이는 선택되지 않은 병렬성이지 고정 요청 속도가 아니므로, 가져오기는 호스트별 제한을 명시하세요.
parse()가 네트워크 요청을 하나요?
newspaper4k 0.9.6에서, socket.connect를 차단한 상태로 테스트한 download(input_html=…) + parse() 경로는 보관된 HTML 입력 1개에 대해 연결 시도를 0번만 했습니다. 이것이 모든 파서 설정, 플러그인, 콘텐츠 타입, 미래 릴리스를 네트워크 없이 처리한다는 뜻은 아닙니다.
import 시 나오는 NLTK 경고는 무엇인가요?
기본 설치에는 NLTK가 들어 있지 않아서, 키워드 추출과 요약 기능을 사용할 수 없고 라이브러리도 import 시 이를 알려 줍니다. 추출 자체는 영향을 받지 않습니다. 여기서 측정한 모든 항목은 기본 설치로 실행했습니다. pip install 'newspaper4k[nlp]'를 설치하면 더 무거운 의존성 트리와 말뭉치 다운로드가 추가됩니다.
이번 리뷰에서 무엇을 테스트하지 않았나요? 실제 웹페이지는 테스트하지 않았습니다. 이것들은 라벨이 붙은 단위가 있는 통제된 fixtures입니다. 메타데이터 필드는 제목, 작성자, 날짜, 이미지 정확도 관점에서 확인만 했고 점수화하지 않았습니다. 다국어 추출, NLP 추가 기능, 멀티스레드 소스 크롤링, 부하 시 처리량도 테스트하지 않았습니다. 프로세스 peak 메모리는 226 KB와 10 MB HTML 입력 각각 1회씩만 측정했으며, 동시성이나 지속 부하 환경에서는 측정하지 않았습니다.


