PHP에서 HTML / XML을 어떻게 파싱하고 처리합니까?


답변:


1897

기본 XML 확장

PHP와 번들로 제공되는 기본 XML 확장 중 하나를 사용 하는 것이 좋습니다. 일반적으로 모든 타사 라이브러리보다 빠르며 마크 업에 필요한 모든 제어 기능을 제공합니다.

DOM

DOM 확장을 사용하면 PHP 5가 포함 된 DOM API를 통해 XML 문서에서 작업 할 수 있습니다. W3C의 Document Object Model Core Level 3은 플랫폼 및 언어 중립 인터페이스로, 프로그램과 스크립트가 동적으로 액세스하고 업데이트 할 수 있습니다. 문서의 내용, 구조 및 스타일.

DOM은 실제 (깨진) HTML을 구문 분석하고 수정할 수 있으며 XPath 쿼리를 수행 할 수 있습니다 . libxml을 기반으로 합니다.

DOM으로 생산성을 얻는 데 약간의 시간이 걸리지 만 그 시간은 IMO의 가치가 있습니다. DOM은 언어에 구애받지 않는 인터페이스이므로 여러 언어로 구현되어 있으므로 프로그래밍 언어를 변경해야 할 경우 해당 언어의 DOM API를 사용하는 방법을 이미 알고있을 것입니다.

기본적인 사용법 예제 는 A 요소의 href 속성을 잡아서 찾을 수 있으며 일반적인 개념적 개요는 PHP의 DOMDocument에서 찾을 수 있습니다.

DOM 확장을 사용하는 방법은 StackOverflow 에서 광범위하게 다루어 졌으므로 사용하도록 선택하면 스택 오버플로를 검색 / 탐색하여 발생하는 대부분의 문제를 해결할 수 있습니다.

XML 리더

XMLReader 확장은 XML 풀 파서입니다. 판독기는 문서 스트림에서 진행하면서 각 노드에서 멈추는 커서 역할을합니다.

DOM과 같은 XMLReader는 libxml을 기반으로합니다. HTML 파서 모듈을 트리거하는 방법을 모릅니다. 따라서 깨진 HTML을 구문 분석하기 위해 XMLReader를 사용할 가능성은 libxml의 HTML 파서 모듈을 사용하도록 명시 적으로 말할 수있는 DOM을 사용하는 것보다 덜 강력 할 수 있습니다.

PHP를 사용하여 h1 태그에서 모든 값을 얻는 기본 사용법 예제를 찾을 수 있습니다

XML 파서

이 확장을 사용하면 XML 구문 분석기를 작성한 후 다른 XML 이벤트에 대한 핸들러를 정의 할 수 있습니다. 각 XML 파서에는 조정할 수있는 몇 가지 매개 변수도 있습니다.

XML 파서 라이브러리는 또한 libxml을 기반으로하며 SAX 스타일 XML 푸시 파서를 구현합니다 . DOM 또는 SimpleXML보다 메모리 관리에 더 나은 선택이지만 XMLReader로 구현 된 풀 파서보다 작업하기가 더 어려울 것입니다.

SimpleXml

SimpleXML 확장은 XML을 일반 속성 선택기 및 배열 반복자로 처리 할 수있는 객체로 변환하는 매우 간단하고 쉽게 사용할 수있는 도구 집합을 제공합니다.

SimpleXML은 HTML이 유효한 XHTML임을 알고있을 때의 옵션입니다. 깨진 HTML을 구문 분석해야 할 경우, SimpleXml은 질식하기 때문에 고려하지 마십시오.

기본 사용법 예제는 xml 파일의 노드 및 노드 값을 CRUD하는 간단한 프로그램 에서 찾을 수 있으며 PHP Manual에 추가 예제많이 있습니다.


타사 라이브러리 (libxml 기반)

타사 lib를 사용하려면 문자열 구문 분석 대신 실제로 DOM / libxml 을 사용하는 lib를 사용하는 것이 좋습니다 .

FluentDom - 리포

FluentDOM은 PHP의 DOMDocument에 대해 jQuery와 같은 유창한 XML 인터페이스를 제공합니다. 선택기는 XPath 또는 CSS로 작성됩니다 (CSS를 XPath 변환기로 사용). 현재 버전은 DOM 구현 표준 인터페이스를 확장하고 DOM Living Standard의 기능을 추가합니다. FluentDOM은 JSON, CSV, JsonML, RabbitFish 등과 같은 형식을로드 할 수 있습니다. Composer를 통해 설치할 수 있습니다.

HTMLPageDom

Wa72 \ HtmlPageDom`은 HTML 문서를 사용하여 쉽게 조작 할 수있는 PHP 라이브러리입니다 . DOM 트리를 순회하려면 Symfony2 구성 요소의 DomCrawler가 필요하며 HTML 문서 의 DOM 트리를 조작하는 메소드를 추가하여이를 확장합니다.

phpQuery (몇 년 동안 업데이트되지 않음)

phpQuery는 PHP5로 작성된 jQuery JavaScript 라이브러리를 기반으로하는 서버 측 체인 가능 CSS3 선택기 기반 DOM (Document Object Model) API이며 추가 CLI (Command Line Interface)를 제공합니다.

참조 : https://github.com/electrolinux/phpquery

Zend_Dom

Zend_Dom은 DOM 문서 및 구조 작업을위한 도구를 제공합니다. 현재 XPath 및 CSS 선택기를 사용하여 DOM 문서를 쿼리하기위한 통합 인터페이스를 제공하는 Zend_Dom_Query를 제공합니다.

QueryPath

QueryPath는 XML 및 HTML 조작을위한 PHP 라이브러리입니다. 로컬 파일뿐만 아니라 웹 서비스 및 데이터베이스 리소스에서도 작동하도록 설계되었습니다. CSS 스타일 선택기를 포함하여 많은 jQuery 인터페이스를 구현하지만 서버 측 사용을 위해 크게 조정되었습니다. Composer를 통해 설치할 수 있습니다.

fDOMDocument

fDOMDocument는 표준 DOM을 확장하여 PHP 경고 나 알림 대신 오류가 발생할 때마다 예외를 사용합니다. 또한 편의성을 높이고 DOM 사용을 단순화하기 위해 다양한 사용자 정의 메소드와 단축키를 추가합니다.

세이버 / xml

sabre / xml은 XMLReader 및 XMLWriter 클래스를 래핑하고 확장하여 간단한 "xml to object / array"매핑 시스템 및 디자인 패턴을 만드는 라이브러리입니다. XML 쓰기 및 읽기는 단일 패스이므로 속도가 빠르므로 대용량 XML 파일에서 메모리가 부족합니다.

FluidXML

FluidXML은 간결하고 유창한 API로 XML을 조작하기위한 PHP 라이브러리입니다. XPath와 유창한 프로그래밍 패턴을 활용하여 재미 있고 효과적입니다.


타사 (libxml 기반 아님)

DOM / libxml을 기반으로하는 이점은 기본 확장을 기반으로하기 때문에 기본적으로 우수한 성능을 얻을 수 있다는 것입니다. 그러나 모든 타사 라이브러리가이 경로를 따르는 것은 아닙니다. 그들 중 일부는 아래에 나열되어 있습니다

PHP 간단한 HTML DOM 파서

  • PHP5 +로 작성된 HTML DOM 파서는 매우 쉬운 방법으로 HTML을 조작 할 수있게합니다!
  • PHP 5 이상이 필요합니다.
  • 잘못된 HTML을 지원합니다.
  • jQuery와 같은 선택기를 사용하여 HTML 페이지에서 태그를 찾으십시오.
  • 한 줄에 HTML에서 내용을 추출하십시오.

나는 일반적 으로이 파서를 권장하지 않습니다. 코드베이스는 끔찍하며 파서 자체는 다소 느리고 메모리가 부족합니다. 모든 jQuery 선택기 (예 : 하위 선택기 )가 가능한 것은 아닙니다 . libxml 기반 라이브러리는이 성능을 쉽게 능가해야합니다.

PHP HTML 파서

PHPHtmlParser는 jQuery와 같은 CSS 선택기를 사용하여 태그를 선택할 수있는 간단하고 유연한 HTML 파서입니다. 목표는 HTML이 유효한지 여부에 관계없이 빠르고 쉽게 HTML을 스크랩하는 도구가 필요한 도구 개발을 지원하는 것입니다! 이 프로젝트는 sunra / php-simple-html-dom-parser에 의해 원래 지원되었지만 지원이 중단 된 것으로 보이므로이 프로젝트는 이전 작업에 대한 나의 적응입니다.

다시, 나는이 파서를 추천하지 않을 것이다. CPU 사용량이 많으면 속도가 느립니다. 생성 된 DOM 객체의 메모리를 지우는 기능도 없습니다. 이러한 문제는 특히 중첩 루프에서 확장됩니다. 문서 자체는 정확하지 않으며 철자가 틀리며 4 월 14 일 이후 수정에 대한 응답이 없습니다.

가논

  • 범용 토크 나이저 및 HTML / XML / RSS DOM 파서
    • 요소와 그 속성을 조작하는 능력
    • 유효하지 않은 HTML 및 UTF8 지원
  • 요소에 대해 고급 CSS3와 같은 쿼리를 수행 할 수 있습니다 (예 : jQuery-네임 스페이스 지원)
  • HTML 꾸미기 (HTML Tidy와 같은)
    • CSS 및 자바 스크립트 축소
    • 속성 정렬, 대소 문자 변경, 들여 쓰기 수정 등
  • 확장 가능
    • 현재 문자 / 토큰을 기반으로 콜백을 사용하여 문서 파싱
    • 쉬운 오버라이드를 위해 작은 기능으로 분리 된 작업
  • 빠르고 쉬운

사용하지 마십시오. 그것이 좋은지 말할 수 없습니다.


HTML 5

위의 HTML5 구문 분석에 사용할 수 있지만 HTML5에서 허용하는 마크 업으로 인해 문제가 발생할 수 있습니다 . HTML5의 경우 다음과 같은 전용 파서를 사용하는 것이 좋습니다.

html5lib

주요 데스크탑 웹 브라우저와의 호환성을 극대화하기 위해 WHATWG HTML5 사양을 기반으로하는 HTML 파서의 Python 및 PHP 구현.

HTML5가 완성되면 더 많은 전용 파서를 볼 수 있습니다. W3의 How to To html 5 파싱에 대한 블로그 게시물도 있습니다 .


웹 서비스

PHP 프로그래밍이 마음에 들지 않으면 웹 서비스를 사용할 수도 있습니다. 일반적으로, 나는 이것들에 대한 유틸리티가 거의 없다는 것을 알았지 만 그것은 단지 나와 내 유스 케이스입니다.

ScraperWiki .

ScraperWiki의 외부 인터페이스를 사용하면 웹이나 자신의 응용 프로그램에서 사용하려는 형태로 데이터를 추출 할 수 있습니다. 스크레이퍼의 상태에 대한 정보를 추출 할 수도 있습니다.


정규식

마지막으로 추천 하는 것은 정규 표현식으로 HTML에서 데이터를 추출 할 수 있습니다 . 일반적으로 HTML에서 정규 표현식을 사용하지 않는 것이 좋습니다.

웹에서 찾을 수있는 대부분의 스 니펫은 마크 업과 일치합니다. 대부분의 경우 그들은 매우 특정한 HTML 부분에서만 작동합니다. 어딘가에 공백을 추가하거나 태그에서 속성을 추가 또는 변경하는 등의 작은 마크 업 변경은 올바르게 작성되지 않은 경우 RegEx가 실패하게 할 수 있습니다. HTML에서 RegEx를 사용하기 전에 수행중인 작업을 알아야합니다.

HTML 파서는 이미 HTML의 구문 규칙을 알고 있습니다. 당신이 쓰는 새로운 정규식마다 정규 표현을 가르쳐야합니다. 경우에 따라 RegEx는 괜찮지 만 실제로는 사용 사례에 따라 다릅니다.

당신은 보다 안정적인 파서를 쓸 수 있지만, 쓰기 완벽하고 신뢰할 수있는 정규 표현식 정의 파서은 상기 라이브러리가 이미 존재하고 이것에 훨씬 더 나은 일을 할 시간 낭비입니다.

Html The Cthulhu Way 파싱 참조


서적

돈을 쓰려면 한 번 봐

나는 PHP Architect 또는 저자와 제휴하지 않습니다.


10
당신의 요구에 따라 @Naveed. CSS Selector 쿼리가 필요하지 않으므로 XPath와 함께 DOM을 독점적으로 사용합니다. phpQuery는 jQuery 포트가되는 것을 목표로합니다. Zend_Dom은 가볍습니다. 당신은 정말로 당신이 가장 좋아하는 것을 확인하기 위해 그들을 확인해야합니다.
Gordon

2
@ Ms2ger 대체로 완벽하지는 않습니다. 위에서 지적했듯이 libxml 기반 파서를 사용할 수 있지만 질식하는 특별한 경우가 있습니다. 최대 호환성이 필요한 경우 전용 파서를 사용하는 것이 좋습니다. 나는 구별을 유지하는 것을 선호합니다.
Gordon

9
PHP를 사용하지 않는 것에 대한 요점 간단한 HTML DOM 구문 분석기
Petah 2019

3
2012 년 3 월 29 일 현재 DOM은 html5를 지원하지 않으며 XMLReader는 HTML을 지원하지 않으며 PHP 용 html5lib에 대한 마지막 커밋은 2009 년 9 월에 있습니다. HTML5, HTML4 및 XHTML을 구문 분석하는 데 무엇을 사용해야합니까?
Shiplu Mokaddim

4
@Nasha 나는 악명 높은 Zalgo rant를 의도적으로 제외 시켰습니다. 왜냐하면 그것이 자체적으로 너무 도움이되지 않고 쓰여진 이래로 꽤 많은화물 숭배로 이어지기 때문입니다. 정규식이 솔루션으로 얼마나 적합했는지에 관계없이 사람들은 그 링크로 철수했습니다. 보다 균형 잡힌 견해를 위해, 내가 대신 포함 했던 링크를 참조하고 stackoverflow.com/questions/4245008/
Gordon

322

간단한 HTML DOM 파서 사용해보기

  • 매우 쉬운 방법으로 HTML을 조작 할 수있는 PHP 5+로 작성된 HTML DOM 파서!
  • PHP 5 이상이 필요합니다.
  • 잘못된 HTML을 지원합니다.
  • jQuery와 같은 선택기를 사용하여 HTML 페이지에서 태그를 찾으십시오.
  • 한 줄에 HTML에서 내용을 추출하십시오.
  • 다운로드


예 :

HTML 요소를 얻는 방법 :

// Create DOM from URL or file
$html = file_get_html('http://www.example.com/');

// Find all images
foreach($html->find('img') as $element)
       echo $element->src . '<br>';

// Find all links
foreach($html->find('a') as $element)
       echo $element->href . '<br>';


HTML 요소를 수정하는 방법 :

// Create DOM from string
$html = str_get_html('<div id="hello">Hello</div><div id="world">World</div>');

$html->find('div', 1)->class = 'bar';

$html->find('div[id=hello]', 0)->innertext = 'foo';

echo $html;


HTML에서 컨텐츠를 추출하십시오.

// Dump contents (without tags) from HTML
echo file_get_html('http://www.google.com/')->plaintext;


긁어 모으기

// Create DOM from URL
$html = file_get_html('http://slashdot.org/');

// Find all article blocks
foreach($html->find('div.article') as $article) {
    $item['title']     = $article->find('div.title', 0)->plaintext;
    $item['intro']    = $article->find('div.intro', 0)->plaintext;
    $item['details'] = $article->find('div.details', 0)->plaintext;
    $articles[] = $item;
}

print_r($articles);

8
먼저 나쁜 DOM, Invlid 코드, DNSBL 엔진에 대한 js 분석과 같은 준비해야 할 것이 있습니다. 이는 악성 사이트 / 콘텐츠를 찾는데도 사용됩니다. 깨끗하고 읽기 쉽고 체계적으로 구성해야합니다. SimpleDim은 훌륭하지만 코드가 약간 지저분합니다
RobertPitt

9
@Robert 당신은 또한 보안 관련 것들에 대한 htmlpurifier.org 를 확인하고 싶을 수도 있습니다 .
Gordon

3
그는 한 가지 유효한 요점을 가지고 있습니다. 단순한 HTMLDOM은 확장하기가 어렵습니다. 데코레이터 패턴을 사용하지 않으면 다루기가 어렵습니다. 나는 기본 클래스 자체를 변경하는 것에 대해 스스로를 흔들었다 .
에릭

1
내가 한 것은 SimpleDOM으로 보내기 전에 깔끔하게 HTML을 실행하는 것이 었습니다.
MB34

1
현재 이것을 사용하여 수백 개의 URL을 처리하는 프로젝트의 일부로 실행하고 있습니다. 매우 느리고 규칙적인 시간 초과가 지속됩니다. 훌륭한 초보자 스크립트이며 직관적으로 배우기 쉽지만 고급 프로젝트에는 너무 기본적입니다.
luke_mclachlan

236

그냥 사용 DOMDocument-> loadHTML을 () 과 함께 할 수. libxml의 HTML 파싱 알고리즘은 상당히 좋고 빠르며 대중의 생각과 달리 잘못된 HTML을 질식시키지 않습니다.


19
진실. 또한 PHP의 내장 XPath 및 XSLTProcessor 클래스와 함께 작동하여 컨텐츠 추출에 좋습니다.
Kornel

8
실제로 엉망인 HTML의 경우 DOM으로 전달하기 전에 항상 HTMLtidy를 통해 실행할 수 있습니다. HTML에서 데이터를 긁어 야 할 때마다 항상 DOM 또는 최소한 simplexml을 사용합니다.
Frank Farmer

9
형식이 잘못된 HTML i를로드하는 또 다른 방법은 구문 분석을 중지하는 경고를 방지하기 위해 libxml_use_internal_errors (true)를 호출하는 것이 좋습니다.
Husky

6
DOMDocument를 사용하여 문제없이 약 1000 개의 HTML 소스 (다른 언어로 인코딩 된 다양한 언어로)를 구문 분석했습니다. 이것으로 인코딩 문제가 발생할 수는 있지만 극복 할 수는 없습니다. 1) loadHTML은 메타 태그의 문자 집합을 사용하여 인코딩을 결정합니다. 2) HTML 내용에이 정보가 포함되지 않은 경우 # 2는 잘못된 인코딩 감지로 이어질 수 있습니다. 3) 잘못된 UTF-8 문자가 파서를 트립 할 수 있습니다. 이러한 경우, 해결 방법으로 mb_detect_encoding ()과 Simplepie RSS Parser의 인코딩 / 변환 / 스트리핑 잘못된 UTF-8 문자 코드를 조합하여 사용하십시오.
Zero

1
DOM은 실제로 XPath를 지원 합니다. DOMXPath를 살펴보십시오 .
Ryan McCue 2012 년

147

왜 정규 표현식을 사용 하지 말아야 합니까?

먼저, 일반적인 오해 : Regexp는 HTML 을 " 구문 분석 "하는 것이 아닙니다 . 그러나 정규 표현식은 데이터를 " 추출 " 할 수 있습니다 . 추출은 그들이 만든 것입니다. 적절한 SGML 툴킷 또는 기본 XML 파서에 대한 정규식 HTML 추출의 주요 단점은 구문 노력과 다양한 안정성입니다.

다소 안정적인 HTML 추출 정규식을 만드는 것을 고려하십시오.

<a\s+class="?playbutton\d?[^>]+id="(\d+)".+?    <a\s+class="[\w\s]*title
[\w\s]*"[^>]+href="(http://[^">]+)"[^>]*>([^<>]+)</a>.+?

간단한 phpQuery 또는 QueryPath에 비해 읽기가 쉽지 않습니다.

$div->find(".stationcool a")->attr("title");

그러나 도움이 될 수있는 구체적인 사용 사례가 있습니다.

  • 많은 DOM 순회 프론트 엔드는 HTML 주석 <!--을 나타내지 않지만 때로는 추출에 더 유용한 앵커입니다. 특히 유사 HTML 변형 <$var>또는 SGML 잔기는 정규식으로 길들이기 쉽다.
  • 정규 표현식은 종종 사후 처리를 절약 할 수 있습니다. 그러나 HTML 엔터티에는 종종 수동 관리가 필요합니다.
  • 그리고 마지막으로 e <img src = url 추출과 같은 매우 간단한 작업의 경우 실제로 가능한 도구입니다. SGML / XML 파서에 비해 속도 이점은 이러한 기본적인 추출 절차에서 주로 작용합니다.

정규 표현식을 사용하여 HTML 스 니펫을 사전 추출 /<!--CONTENT-->(.+?)<!--END-->/하고 더 간단한 HTML 구문 분석기 프론트 엔드를 사용하여 나머지를 처리하는 것이 좋습니다 .

참고 : 실제로이 응용 프로그램을 가지고 있는데 , XML 파싱과 정규 표현식을 대신 사용합니다. 지난주 PyQuery 파싱이 중단되어 정규 표현식이 계속 작동했습니다. 예, 이상하고 직접 설명 할 수 없습니다. 그러나 그렇게되었습니다.
따라서 실제 고려 사항은 regex = evil meme와 일치하지 않기 때문에 투표하지 마십시오. 그러나 이것을 너무 많이 투표하지 말자. 이 주제에 대한 주석 일뿐입니다.


20
DOMComment주석을 읽을 수 있으므로 Regex를 사용할 이유가 없습니다.
Gordon

4
SGML 툴킷 또는 XML 파서는 실제 HTML을 구문 분석하는 데 적합하지 않습니다. 이를 위해서는 전용 HTML 파서 만 적합합니다.
Alohci

12
@Alohci DOMlibxml을 사용 하고 libxml에는 HTML을로드 할 때 사용되는 별도의 HTML 파서 모듈이 loadHTML()있으므로 "실제" HTML을로드 할 수 있습니다.
Gordon

6
글쎄, 당신의 "실제 고려 사항"관점에 대한 의견. 물론 HTML을 구문 분석 할 때 Regex에 유용한 상황이 있습니다. 또한 GOTO 사용에 유용한 상황이 있습니다. 변수 변수에 유용한 상황이 있습니다. 따라서 특정 구현이 코드 로트를 사용하여 결정하는 것은 아닙니다. 그러나 이것은 매우 강력한 경고 신호입니다. 그리고 일반적인 개발자는 그 차이를 알만큼 미묘한 차이가 없습니다. 따라서 일반적으로 Regex GOTO와 Variable-Variables는 모두 사악합니다. 사악하지 않은 용도가 있지만 그 예외는 예외입니다 (그리고 드물다). (IMHO)
ircmaxell

11
@mario : 실제로 정규 표현식을 사용하여 HTML '적절하게'파싱 수 있지만 일반적으로 적절한 작업을 수행하려면 몇 가지가 필요합니다. 일반적인 경우에는 왕의 고통 일뿐입니다. 입력이 잘 정의 된 특정 경우에는 사소한 것입니다. 사람들이 정규식을 사용해야 하는 경우입니다 . 크고 오래된 배고픈 무거운 파서는 실제로 일반적인 경우에 필요한 것이지만, 일반 사용자에게는 그 선을 그릴 위치가 항상 명확하지는 않습니다. 어떤 코드가 더 간단하고 쉬운 지 승리합니다.
tchrist

131

phpQueryQueryPath 는 유창한 jQuery API 복제와 매우 유사합니다. 그렇기 때문에 PHP에서 HTML 을 올바르게 구문 분석 하는 가장 쉬운 방법 중 하나입니다.

QueryPath의 예

기본적으로 먼저 HTML 문자열에서 쿼리 가능한 DOM 트리를 만듭니다.

 $qp = qp("<html><body><h1>title</h1>..."); // or give filename or URL

결과 객체에는 HTML 문서의 완전한 트리 표현이 포함됩니다. DOM 메소드를 사용하여 순회 할 수 있습니다. 그러나 일반적인 접근 방식은 jQuery와 같은 CSS 선택기를 사용하는 것입니다.

 $qp->find("div.classname")->children()->...;

 foreach ($qp->find("p img") as $img) {
     print qp($img)->attr("src");
 }

대부분 당신은 간단한 사용하려는 #id.classDIV에 대한 태그 선택기 ->find(). 그러나 때때로 더 빠른 XPath 문 을 사용할 수도 있습니다 . 또한 일반적인 jQuery 메소드 는 올바른 HTML 스 니펫 추출을 좋아 ->children()하고 ->text()특히 ->attr()단순화합니다. (그리고 이미 SGML 엔터티가 디코딩되었습니다.)

 $qp->xpath("//div/p[1]");  // get first paragraph in a div

또한 QueryPath를 사용하면 스트림에 새 태그를 삽입하고 ( ->append) 나중에 업데이트 된 문서를 출력하고 미리 정의 할 수 있습니다 ( ->writeHTML). 잘못된 HTML뿐만 아니라 다양한 XML 방언 (네임 스페이스 포함)을 구문 분석하고 HTML 마이크로 포맷 (XFN, vCard)에서 데이터를 추출 할 수도 있습니다.

 $qp->find("a[target=_blank]")->toggleClass("usability-blunder");

.

phpQuery 또는 QueryPath?

일반적으로 QueryPath는 문서 조작에 더 적합합니다. phpQuery는 또한 의사 AJAX 메소드 (HTTP 요청 만)를 구현하여 jQuery와 더 유사합니다. phpQuery는 종종 전체 기능이 적기 때문에 QueryPath보다 빠릅니다.

차이점에 대한 자세한 내용 은 tagbyte.org의 웨이 백 머신에서이 비교를 참조하십시오. . (원본 소스가 누락되었으므로 인터넷 보관 링크가 있습니다. 예, 여전히 누락 된 페이지와 사람을 찾을 수 있습니다.)

다음 은 포괄적 인 QueryPath 소개입니다. 입니다.

장점

  • 단순성과 신뢰성
  • 사용하기 쉬운 대안 ->find("a img, a object, div a")
  • 적절한 데이터 이스케이프 처리 (정규 표현식 그 리핑과 비교)

88

간단한 HTML DOM은 훌륭한 오픈 소스 파서입니다.

simplehtmldom.sourceforge

DOM 요소를 객체 지향 방식으로 처리하며 새로운 반복에는 비 호환 코드가 많이 포함됩니다. "find"함수와 같이 JavaScript에서 볼 수있는 훌륭한 기능도 있습니다.이 기능은 해당 태그 이름 요소의 모든 인스턴스를 반환합니다.

나는 이것을 여러 도구에서 사용하여 여러 유형의 웹 페이지에서 테스트했으며 훌륭하게 작동한다고 생각합니다.


61

여기서 언급하지 않은 일반적인 방법 중 하나는 Tidy를 통해 HTML을 실행하는 것입니다. 하는 것입니다. 이는 유효한 XHTML을 추출하도록 설정할 수 있습니다. 그런 다음 이전 XML 라이브러리를 사용할 수 있습니다.

그러나 특정 문제에 대해서는 다음 프로젝트를 살펴보십시오. http://fivefilters.org/content-only/- 텍스트 내용 만 추출하도록 설계된 가독성 알고리즘 의 수정 된 버전입니다. 페이지에서


56

1a와 2의 경우 : 새로운 Symfony Componet 클래스 DOMCrawler ( DomCrawler )에 투표합니다 . 이 클래스는 CSS 선택기와 유사한 쿼리를 허용합니다. 실제 사례에 대한이 프레젠테이션을 살펴보십시오. news-of-the-symfony2-world .

이 구성 요소는 독립형으로 작동하도록 설계되었으며 Symfony없이 사용할 수 있습니다.

유일한 단점은 PHP 5.3 이상에서만 작동한다는 것입니다.


jquery와 같은 CSS 쿼리는 w3c 문서에서 누락되었지만 jquery에 추가 기능으로 존재하기 때문에 잘 알려져 있습니다.
Nikola Petkanski

53

그런데 이것을 일반적으로 화면 스크래핑 이라고합니다 . 내가 사용한 라이브러리는 Simple HTML Dom Parser 입니다.


8
엄격하지는 않습니다 ( en.wikipedia.org/wiki/Screen_scraping#Screen_scraping ). 실마리는 "스크린"에 있습니다. 설명 된 경우에는 화면이 필요하지 않습니다. 물론,이 용어는 최근에 많은 오용을 겪고 있습니다.
Bobby Jack

4
화면 스크래핑이 아닌 경우 구문 분석 할 콘텐츠는 계약에 따라 콘텐츠 공급 업체가 승인합니다.
RobertPitt

41

우리는 이전에 우리의 요구에 맞는 크롤러를 많이 만들었습니다. 하루가 끝나면 일반적으로 가장 잘하는 간단한 정규 표현식입니다. 위에 나열된 라이브러리는 생성 된 이유 때문에 좋지만 찾고있는 것을 알면 정규식은 더 안전한 방법입니다. 로드되지 않으면 유효하지 않은 HTML / XHTML 구조 도 처리 할 수 ​​있습니다. 대부분의 파서를 통해.



36

이것은 W3C XPath 기술에 대한 좋은 작업 설명처럼 들립니다 . " 에 중첩 된 태그의 모든 href속성을 반환합니다 ." 와 같은 쿼리를 쉽게 표현할 수 있습니다. PHP 버프가 아니기 때문에 XPath를 어떤 형태로 사용할 수 있는지 말할 수 없습니다. HTML 파일을 처리하기 위해 외부 프로그램을 호출 할 수 있으면 XPath의 명령 행 버전을 사용할 수 있어야합니다. 빠른 소개는 http://en.wikipedia.org/wiki/XPath를 참조하십시오 .img<foo><bar><baz> elements


29

String Parsing 대신 DOM을 사용하는 SimpleHtmlDom에 대한 타사 대안 : phpQuery , Zend_Dom , QueryPathFluentDom .


3
내 의견을 이미 복사했다면 적어도 적절하게 연결하십시오.) 즉 , String Parsing 대신 DOM 을 실제로 사용 하는 SimpleHtmlDom에 대한 제안 된 타사 대안 : phpQuery , Zend_Dom , QueryPathFluentDom .
Gordon

1
좋은 답변은 훌륭한 소스입니다. stackoverflow.com/questions/3606792/…
danidacar

24

예, 목적에 simple_html_dom을 사용할 수 있습니다. 그러나 나는 특히 web scrapping을 위해 simple_html_dom으로 많은 일을 해왔으며 너무 취약한 것으로 나타났습니다. 기본 작업을 수행하지만 어쨌든 권장하지는 않습니다.

나는 컬을 목적으로 사용하지 않았지만 내가 배운 것은 컬이 훨씬 효율적으로 작업을 수행 할 수 있고 훨씬 견고하다는 것입니다.

이 링크를 확인하십시오 : scraping-websites-with-curl


2
curl은 파일을 가져올 수 있지만 HTML을 구문 분석하지는 않습니다. 어려운 부분입니다.
cHao

23

QueryPath 는 좋지만, 무슨 의미인지 모르는 경우 "추적 상태"원인에주의해야합니다. 이는 발생한 결과와 코드가 작동하지 않는 이유를 찾기 위해 많은 디버깅 시간을 낭비 할 수 있음을 의미합니다.

의미하는 것은 결과 세트의 각 호출이 객체의 결과 세트를 수정한다는 것입니다. 각 링크가 새로운 세트 인 jquery와 같이 체인화 할 수 없으며 쿼리의 결과 인 단일 세트가 있으며 각 함수 호출은 수정합니다 그 단일 세트.

jquery와 같은 동작을 얻으려면 필터 / 수정 같은 작업을 수행하기 전에 분기해야합니다. 즉, jquery에서 발생하는 일을 훨씬 더 가깝게 반영합니다.

$results = qp("div p");
$forename = $results->find("input[name='forename']");

$results이제 input[name='forename']원래 쿼리가 아닌 결과 세트가 포함되어 있습니다. "div p"내가 찾은 것은 QueryPath 가 필터를 추적하고 결과를 수정하고 객체에 저장하는 모든 것을 추적 한다는 것입니다. 대신이 작업을 수행해야합니다

$forename = $results->branch()->find("input[name='forname']")

그런 다음 $results수정되지 않으며 결과 집합을 반복해서 재사용 할 수 있습니다. 아는 지식이 많은 사람이 이것을 약간 정리할 수는 있지만 기본적으로 내가 찾은 내용과 같습니다.


20

Advanced Html Dom 은 동일한 인터페이스를 제공 하는 간단한 HTML DOM 대체물이지만 DOM 기반이므로 관련 메모리 문제가 발생하지 않습니다.

또한 jQuery 확장을 포함하여 전체 CSS를 지원 합니다.


Advanced Html Dom에서 좋은 결과를 얻었으며 허용 된 답변의 목록에 있어야한다고 생각합니다. "이 프로젝트의 목표는 PHP의 간단한 html dom 라이브러리를 DOM 기반 드롭 인으로 대체하는 것입니다. file / str_get_html을 사용하는 경우 무엇이든 바꾸십시오. " archive.is/QtSuj#selection-933.34-933.100 은 일부 비 호환성을 수용하기 위해 코드를 변경해야 할 수도 있습니다. 나는 프로젝트의 github 문제에서 나에게 알려진 4 가지를 언급했다. github.com/monkeysuffrage/advanced_html_dom/issues
ChrisJJ

일했다! 감사합니다
파이살 Shani

18

들어 HTML5 , HTML5 LIB 지금 년간 버려진되었습니다. 최근 업데이트 및 유지 관리 레코드에서 찾을 수있는 유일한 HTML5 라이브러리는 html5-php 이며, 1 주일 전에 베타 1.0으로 변경되었습니다.


17

GB 파일을 쉽게 처리 할 수있는 범용 XML 파서를 작성했습니다. XMLReader를 기반으로하며 사용이 매우 쉽습니다.

$source = new XmlExtractor("path/to/tag", "/path/to/file.xml");
foreach ($source as $tag) {
    echo $tag->field1;
    echo $tag->field2->subfield1;
}

여기 github 저장소가 있습니다 : XmlExtractor


17

라는 도서관을 만들었습니다 jQuery를 사용하는 것처럼 HTML5 및 XML 문서를 크롤링 할 수있는 PHPPowertools / DOM-Query.

후드 아래에서 심포니 / 돔 크롤러를 사용합니다. 으로 CSS 선택기를 XPath 선택기로 변환 를 . 적절한 성능을 보장하기 위해 한 객체를 다른 객체로 전달할 때에도 항상 동일한 DomDocument를 사용합니다.


사용 예 :

namespace PowerTools;

// Get file content
$htmlcode = file_get_contents('https://github.com');

// Define your DOMCrawler based on file string
$H = new DOM_Query($htmlcode);

// Define your DOMCrawler based on an existing DOM_Query instance
$H = new DOM_Query($H->select('body'));

// Passing a string (CSS selector)
$s = $H->select('div.foo');

// Passing an element object (DOM Element)
$s = $H->select($documentBody);

// Passing a DOM Query object
$s = $H->select( $H->select('p + p'));

// Select the body tag
$body = $H->select('body');

// Combine different classes as one selector to get all site blocks
$siteblocks = $body->select('.site-header, .masthead, .site-body, .site-footer');

// Nest your methods just like you would with jQuery
$siteblocks->select('button')->add('span')->addClass('icon icon-printer');

// Use a lambda function to set the text of all site blocks
$siteblocks->text(function( $i, $val) {
    return $i . " - " . $val->attr('class');
});

// Append the following HTML to all site blocks
$siteblocks->append('<div class="site-center"></div>');

// Use a descendant selector to select the site's footer
$sitefooter = $body->select('.site-footer > .site-center');

// Set some attributes for the site's footer
$sitefooter->attr(array('id' => 'aweeesome', 'data-val' => 'see'));

// Use a lambda function to set the attributes of all site blocks
$siteblocks->attr('data-val', function( $i, $val) {
    return $i . " - " . $val->attr('class') . " - photo by Kelly Clark";
});

// Select the parent of the site's footer
$sitefooterparent = $sitefooter->parent();

// Remove the class of all i-tags within the site's footer's parent
$sitefooterparent->select('i')->removeAttr('class');

// Wrap the site's footer within two nex selectors
$sitefooter->wrap('<section><div class="footer-wrapper"></div></section>');

[...]

지원되는 방법 :


  1. 명백한 이유로 'select'로 이름이 변경되었습니다.
  2. 'empty'는 PHP에서 예약어이므로 'void'로 이름이 변경되었습니다.

노트 :

이 라이브러리에는 PSR-0 호환 라이브러리를위한 자체 제로 구성 오토로더도 포함되어 있습니다. 포함 된 예제는 추가 구성없이 즉시 사용할 수 있습니다. 또는 작곡가와 함께 사용할 수 있습니다.


작업에 적합한 도구처럼 보이지만 Worpress의 PHP 5.6.23에서로드되지 않습니다. 올바르게 포함시키는 방법에 대한 추가 지침이 있습니까? 다음과 함께 포함됩니다 : define ( "BASE_PATH", dirname ( FILE )); define ( "LIBRARY_PATH", BASE_PATH. DIRECTORY_SEPARATOR. 'lib / vendor'); LIBRARY_PATH가 필요합니다. DIRECTORY_SEPARATOR 'Loader.php'; 로더 :: init (배열 (LIBRARY_PATH, USER_PATH)); functions.php에서
리튬 랩

15

HTML Tidy 와 같은 것을 사용하여 "깨진"HTML을 정리하고 HTML을 XHTML로 변환 한 다음 XML 파서로 구문 분석 할 수 있습니다.


15

시도 할 수있는 또 다른 옵션은 QueryPath 입니다. jQuery에서 영감을 얻었지만 PHP의 서버에서 Drupal 에서 사용되었습니다 .


12

XML_HTMLSax더 이상 유지되지 않더라도 다소 안정적입니다. 또 다른 옵션은 HTML Tidy를 통해 HTML 을 파이프 한 다음 표준 XML 도구로 구문 분석하는 것입니다.



11

가장 많이 언급 된 HTML / XML DOM을 처리하는 방법에는 여러 가지가 있습니다. 그러므로 나는 그것들을 스스로 나열하려고 시도하지 않을 것입니다.

필자는 개인적으로 DOM 확장을 사용하는 것을 선호한다고 덧붙이고 싶습니다.

  • iit은 기본 C 코드의 성능 이점을 최적으로 활용합니다.
  • 그것은 OO PHP입니다 (그리고 그것을 서브 클래스 화 할 수있게 해줍니다)
  • 그것은 다소 낮은 수준입니다 (더 높은 수준의 행동을위한 비 팽창 기반으로 사용할 수 있습니다)
  • 알려진 XML 기능 중 일부를 무시하는 SimpleXml과 달리 DOM의 모든 부분에 대한 액세스를 제공합니다.
  • DOM 크롤링에 사용되는 구문은 기본 Javascript에 사용 된 구문과 유사합니다.

I가 CSS 선택기를 사용 할 수있는 능력을 그리워 반면 DOMDocument를 서브 클래스 :이 기능을 추가 할 수있는 비교적 간단하고 편리한 방법이 DOMDocument와 JS 같은 추가 querySelectorAllquerySelector방법 하위 클래스에가.

선택기를 구문 분석하려면 Symfony 프레임 워크 에서 매우 최소한의 CssSelector 구성 요소 를 사용하는 것이 좋습니다 . 이 구성 요소는 CSS 선택기를 XPath 선택기로 변환 한 다음DOMXpath 해당 노드 목록을 검색하기 위해에 .

그런 다음이 하위 클래스를 여전히 높은 수준의 클래스를위한 기초로 사용할 수 있습니다. 매우 특정한 유형의 XML을 구문 분석하거나 더 많은 jQuery와 유사한 동작을 추가하십시오.

아래 코드는 DOM-Query 라이브러리 에서 바로 나오며 내가 설명한 기술을 사용합니다.

HTML 파싱의 경우 :

namespace PowerTools;

use \Symfony\Component\CssSelector\CssSelector as CssSelector;

class DOM_Document extends \DOMDocument {
    public function __construct($data = false, $doctype = 'html', $encoding = 'UTF-8', $version = '1.0') {
        parent::__construct($version, $encoding);
        if ($doctype && $doctype === 'html') {
            @$this->loadHTML($data);
        } else {
            @$this->loadXML($data);
        }
    }

    public function querySelectorAll($selector, $contextnode = null) {
        if (isset($this->doctype->name) && $this->doctype->name == 'html') {
            CssSelector::enableHtmlExtension();
        } else {
            CssSelector::disableHtmlExtension();
        }
        $xpath = new \DOMXpath($this);
        return $xpath->query(CssSelector::toXPath($selector, 'descendant::'), $contextnode);
    }

    [...]

    public function loadHTMLFile($filename, $options = 0) {
        $this->loadHTML(file_get_contents($filename), $options);
    }

    public function loadHTML($source, $options = 0) {
        if ($source && $source != '') {
            $data = trim($source);
            $html5 = new HTML5(array('targetDocument' => $this, 'disableHtmlNsInDom' => true));
            $data_start = mb_substr($data, 0, 10);
            if (strpos($data_start, '<!DOCTYPE ') === 0 || strpos($data_start, '<html>') === 0) {
                $html5->loadHTML($data);
            } else {
                @$this->loadHTML('<!DOCTYPE html><html><head><meta charset="' . $encoding . '" /></head><body></body></html>');
                $t = $html5->loadHTMLFragment($data);
                $docbody = $this->getElementsByTagName('body')->item(0);
                while ($t->hasChildNodes()) {
                    $docbody->appendChild($t->firstChild);
                }
            }
        }
    }

    [...]
}

Symfony의 작성자 인 Fabien Potencier의 Symfony 용 CssSelector 구성 요소 작성 결정 및 사용 방법에 대한 CSS 선택기XML 문서 구문 분석 도 참조하십시오 .


9

FluidXML 당신이 사용하는 쿼리와 반복 처리 XML 수 의 XPathCSS 선택기를 .

$doc = fluidxml('<html>...</html>');

$title = $doc->query('//head/title')[0]->nodeValue;

$doc->query('//body/p', 'div.active', '#bgId')
        ->each(function($i, $node) {
            // $node is a DOMNode.
            $tag   = $node->nodeName;
            $text  = $node->nodeValue;
            $class = $node->getAttribute('class');
        });

https://github.com/servo-php/fluidxml


7

JSON 및 XML의 배열은 세 줄로 표시됩니다.

$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);

타 다!


7

정규식으로 HTML을 구문 분석하지 않는 몇 가지 이유가 있습니다. 그러나 생성 할 HTML을 완전히 제어 할 수 있으면 간단한 정규식으로 수행 할 수 있습니다.

위의 정규식으로 HTML을 구문 분석하는 함수입니다. 이 기능은 매우 민감하며 HTML은 특정 규칙을 준수해야하지만 많은 시나리오에서 잘 작동합니다. 간단한 파서를 원하고 라이브러리를 설치하지 않으려면 다음과 같이하십시오.

function array_combine_($keys, $values) {
    $result = array();
    foreach ($keys as $i => $k) {
        $result[$k][] = $values[$i];
    }
    array_walk($result, create_function('&$v', '$v = (count($v) == 1)? array_pop($v): $v;'));

    return $result;
}

function extract_data($str) {
    return (is_array($str))
        ? array_map('extract_data', $str)
        : ((!preg_match_all('#<([A-Za-z0-9_]*)[^>]*>(.*?)</\1>#s', $str, $matches))
            ? $str
            : array_map(('extract_data'), array_combine_($matches[1], $matches[2])));
}

print_r(extract_data(file_get_contents("http://www.google.com/")));

2

https://github.com/ivopetkov/html5-dom-document-php 에서 자유롭게 사용할 수있는 HTML5DOMDocument라는 라이브러리를 만들었습니다.

쿼리 선택기를 지원하므로 귀하의 경우에 매우 도움이 될 것이라고 생각합니다. 예제 코드는 다음과 같습니다.

$dom = new IvoPetkov\HTML5DOMDocument();
$dom->loadHTML('<!DOCTYPE html><html><body><h1>Hello</h1><div class="content">This is some text</div></body></html>');
echo $dom->querySelector('h1')->innerHTML;

0

jQuery 선택기에 익숙한 경우 PHP 용 ScarletsQuery 를 사용할 수 있습니다

<pre><?php
include "ScarletsQuery.php";

// Load the HTML content and parse it
$html = file_get_contents('https://www.lipsum.com');
$dom = Scarlets\Library\MarkupLanguage::parseText($html);

// Select meta tag on the HTML header
$description = $dom->selector('head meta[name="description"]')[0];

// Get 'content' attribute value from meta tag
print_r($description->attr('content'));

$description = $dom->selector('#Content p');

// Get element array
print_r($description->view);

이 라이브러리는 일반적으로 오프라인 html을 처리하는 데 1 초 미만이 소요됩니다.
태그 속성에 잘못된 HTML 또는 누락 된 따옴표도 허용합니다.


0

XML을 구문 분석하는 가장 좋은 방법 :

$xml='http://www.example.com/rss.xml';
$rss = simplexml_load_string($xml);
$i = 0;
foreach ($rss->channel->item as $feedItem) {
  $i++;
  echo $title=$feedItem->title;
  echo '<br>';
  echo $link=$feedItem->link;
  echo '<br>';
  if($feedItem->description !='') {
    $des=$feedItem->description;
  } else {
    $des='';
  }
  echo $des;
  echo '<br>';
  if($i>5) break;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.