Jak parsujesz i przetwarzasz HTML / XML w PHP?

Odpowiedzi:

1896

Natywne rozszerzenia XML

Wolę używać jednego z natywnych rozszerzeń XML, ponieważ są one dostarczane w pakiecie z PHP, są zwykle szybsze niż wszystkie biblioteki innych firm i dają mi pełną kontrolę nad znacznikami.

DOM

Rozszerzenie DOM pozwala na obsługę dokumentów XML za pomocą DOM API z PHP 5. Jest to implementacja dokumentu Object Model Model Core Level 3 W3C, niezależnego od platformy i języka interfejsu, który umożliwia programom i skryptom dynamiczny dostęp i aktualizację treść, struktura i styl dokumentów.

DOM jest w stanie analizować i modyfikować (zepsuty) HTML w świecie rzeczywistym i może wykonywać zapytania XPath . Opiera się na libxml .

Wydajność pracy z DOMem zajmuje trochę czasu, ale ten czas jest tego wart IMO. Ponieważ DOM jest interfejsem niezależnym od języka, znajdziesz implementacje w wielu językach, więc jeśli musisz zmienić język programowania, prawdopodobnie już wiesz, jak korzystać z interfejsu API DOM tego języka.

Podstawowy przykład użycia można znaleźć w Chwytanie atrybutu href elementu A, a ogólny przegląd pojęć można znaleźć w DOMDocument w php

Jak korzystać z rozszerzenia DOM zostało szczegółowo omówione w StackOverflow , więc jeśli zdecydujesz się go użyć, możesz być pewien, że większość problemów, na które natrafisz, można rozwiązać, wyszukując / przeglądając przepełnienie stosu.

XMLReader

Rozszerzenie XMLReader to analizator składni XML. Czytnik działa jak kursor poruszający się do przodu w strumieniu dokumentów i zatrzymujący się w każdym węźle po drodze.

XMLReader, podobnie jak DOM, oparty jest na libxml. Nie wiem, jak uruchomić moduł parsera HTML, więc szanse na użycie XMLReadera do analizowania uszkodzonego HTML mogą być mniej niezawodne niż użycie DOM, w którym możesz jawnie nakazać mu użycie modułu parsera HTML libxml.

Podstawowy przykład użycia można znaleźć przy pobieraniu wszystkich wartości ze znaczników h1 przy użyciu php

Parser XML

To rozszerzenie pozwala tworzyć parsery XML, a następnie definiować programy obsługi różnych zdarzeń XML. Każdy parser XML ma również kilka parametrów, które można dostosować.

Biblioteka parsera XML jest również oparta na libxml i implementuje parser wypychający XML w stylu SAX . Może być lepszym wyborem do zarządzania pamięcią niż DOM lub SimpleXML, ale będzie trudniejszy do pracy niż parser pull realizowany przez XMLReader.

SimpleXml

Rozszerzenie SimpleXML zapewnia bardzo prosty i łatwy w użyciu zestaw narzędzi do konwersji XML do obiektu, który można przetwarzać za pomocą normalnych selektorów właściwości i iteratorów tablic.

SimpleXML jest opcją, gdy wiesz, że HTML jest prawidłowym XHTML. Jeśli musisz przeanalizować uszkodzony HTML, nie bierz nawet pod uwagę SimpleXml, ponieważ będzie się dusił.

Podstawowy przykład użycia można znaleźć w Prostym programie do CRUD wartości węzłów i węzłów pliku xml, i jest wiele dodatkowych przykładów w Podręczniku PHP .


Biblioteki stron trzecich (oparte na libxml)

Jeśli wolisz korzystać z biblioteki innej firmy, sugeruję użycie biblioteki lib, która faktycznie używa DOM / libxml pod spodem zamiast analizowania łańcucha.

FluentDom - Repo

FluentDOM zapewnia podobny do jQuery płynny interfejs XML dla DOMDocument w PHP. Selektory są zapisywane w XPath lub CSS (przy użyciu konwertera CSS na XPath). Obecne wersje rozszerzają DOM implementujący standardowe interfejsy i dodają funkcje z DOM Living Standard. FluentDOM może ładować formaty takie jak JSON, CSV, JsonML, RabbitFish i inne. Może być zainstalowany przez Composer.

HtmlPageDom

Wa72 \ HtmlPageDom` to biblioteka PHP do łatwej manipulacji dokumentami HTML przy użyciu. Wymaga DomCrawler ze składników Symfony2 do przechodzenia przez drzewo DOM i rozszerza go poprzez dodanie metod manipulowania drzewem DOM dokumentów HTML.

phpQuery (nie aktualizowany przez lata)

phpQuery to oparty na serwerze, łańcuchowy interfejs API Document Object Model (DOM) oparty na selektorze CSS3 oparty na bibliotece JavaScript jQuery napisanej w PHP5 i zapewniający dodatkowy interfejs wiersza poleceń (CLI).

Zobacz także: https://github.com/electrolinux/phpquery

Zend_Dom

Zend_Dom zapewnia narzędzia do pracy z dokumentami i strukturami DOM. Obecnie oferujemy Zend_Dom_Query, który zapewnia zunifikowany interfejs do wysyłania zapytań do dokumentów DOM przy użyciu zarówno selektorów XPath, jak i CSS.

QueryPath

QueryPath to biblioteka PHP do manipulowania XML i HTML. Jest przeznaczony do pracy nie tylko z plikami lokalnymi, ale także z usługami internetowymi i zasobami bazy danych. Implementuje większość interfejsu jQuery (w tym selektory w stylu CSS), ale jest mocno dostosowany do użytku po stronie serwera. Może być zainstalowany przez Composer.

fDOMDocument

fDOMDocument rozszerza standardowy DOM o stosowanie wyjątków przy każdorazowych błędach zamiast ostrzeżeń i powiadomień PHP. Dodają także różne niestandardowe metody i skróty dla wygody i uproszczenia korzystania z DOM.

szabla / xml

saber / xml to biblioteka, która otacza i rozszerza klasy XMLReader i XMLWriter, tworząc prosty system odwzorowywania „xml do obiektu / tablicy” i wzorzec projektowy. Pisanie i czytanie XML jest jednoprzebiegowe, dlatego może być szybkie i wymagać małej ilości pamięci w dużych plikach XML.

FluidXML

FluidXML to biblioteka PHP do manipulowania XML za pomocą zwięzłego i płynnego API. Wykorzystuje XPath i płynny schemat programowania, aby być zabawnym i skutecznym.


Zewnętrzne (nie oparte na libxml)

Zaletą budowania na DOM / libxml jest to, że otrzymujesz dobrą wydajność od razu po wyjęciu z pudełka, ponieważ bazujesz na natywnym rozszerzeniu. Jednak nie wszystkie biblioteki innych firm podążają tą drogą. Niektóre z nich wymienione poniżej

PHP Prosty parser DOM HTML

  • Parser DOM HTML napisany w PHP5 + pozwala manipulować HTML w bardzo łatwy sposób!
  • Wymagaj PHP 5+.
  • Obsługuje nieprawidłowy HTML.
  • Znajdź tagi na stronie HTML za pomocą selektorów takich jak jQuery.
  • Wyodrębnij zawartość z HTML w jednym wierszu.

Generalnie nie polecam tego parsera. Baza kodów jest okropna, a sam parser jest raczej powolny i głodny pamięci. Nie wszystkie selektory jQuery (takie jak selektory potomne ) są możliwe. Każda biblioteka oparta na libxml powinna z łatwością osiągać lepsze wyniki.

Parser HTML HTML

PHPHtmlParser to prosty, elastyczny parser HTML, który pozwala wybierać tagi za pomocą dowolnego selektora css, takiego jak jQuery. Celem jest pomoc w opracowaniu narzędzi wymagających szybkiego i łatwego usuwania skrawków html, bez względu na to, czy są one ważne, czy nie! Ten projekt był pierwotnie wspierany przez sunra / php-simple-html-dom-parser, ale wydaje się, że wsparcie się zatrzymało, więc ten projekt jest moją adaptacją jego poprzedniej pracy.

Ponownie nie poleciłbym tego parsera. Jest raczej powolny przy dużym zużyciu procesora. Nie ma również funkcji czyszczenia pamięci utworzonych obiektów DOM. Problemy te skalują się szczególnie w przypadku zagnieżdżonych pętli. Sama dokumentacja jest niedokładna i błędna, bez odpowiedzi na poprawki od 14 kwietnia 16.

Ganon

  • Uniwersalny tokenizer i parser DOM HTML / XML / RSS
    • Umiejętność manipulowania elementami i ich atrybutami
    • Obsługuje nieprawidłowe HTML i UTF8
  • Może wykonywać zaawansowane zapytania podobne do CSS3 na elementach (jak jQuery - obsługiwane przestrzenie nazw)
  • Upiększacz HTML (jak HTML Tidy)
    • Zminimalizuj CSS i JavaScript
    • Sortuj atrybuty, zmieniaj wielkość znaków, poprawne wcięcia itp.
  • Rozciągliwy
    • Analizowanie dokumentów za pomocą wywołań zwrotnych opartych na bieżącym znaku / tokenie
    • Operacje rozdzielone na mniejsze funkcje dla łatwego zastąpienia
  • Szybko i łatwo

Nigdy go nie użyłem. Nie mogę powiedzieć, czy to coś dobrego.


HTML 5

Możesz użyć powyższego do analizowania HTML5, ale mogą pojawić się dziwactwa ze względu na znaczniki HTML5. W przypadku HTML5 należy rozważyć użycie dedykowanego analizatora składni, takiego jak

html5lib

Implementacje parsera HTML opartego na specyfikacji WHATWG HTML5 w języku Python i PHP w celu zapewnienia maksymalnej kompatybilności z głównymi przeglądarkami na komputery stacjonarne.

Po sfinalizowaniu HTML5 możemy zobaczyć więcej dedykowanych analizatorów składni. Jest też post na blogu autorstwa W3 zatytułowany „ How to To for html 5 parsing”, który warto sprawdzić.


Usługi internetowe

Jeśli nie masz ochoty programować PHP, możesz także korzystać z usług sieciowych. Ogólnie rzecz biorąc, znalazłem dla nich bardzo małą użyteczność, ale to tylko ja i moje przypadki użycia.

ScraperWiki .

Zewnętrzny interfejs ScraperWiki pozwala wyodrębnić dane w formie, którą chcesz wykorzystać w Internecie lub we własnych aplikacjach. Możesz także wyodrębnić informacje o stanie dowolnego skrobaka.


Wyrażenia regularne

Co najmniej zalecane , możesz wyodrębnić dane z HTML za pomocą wyrażeń regularnych . Ogólnie odradza się używanie wyrażeń regularnych w HTML.

Większość fragmentów, które można znaleźć w Internecie w celu dopasowania znaczników, jest krucha. W większości przypadków działają tylko dla bardzo konkretnego fragmentu HTML. Niewielkie zmiany znaczników, takie jak dodanie gdzieś białych znaków lub dodanie lub zmiana atrybutów w tagu, mogą spowodować, że regEx nie powiedzie się, jeśli nie zostanie poprawnie napisany. Przed użyciem RegEx na HTML powinieneś wiedzieć, co robisz.

Parsery HTML znają już składniowe reguły HTML. Wyrażeń regularnych należy uczyć dla każdego nowego RegEx, który napiszesz. RegEx są w niektórych przypadkach w porządku, ale tak naprawdę zależy to od twojego przypadku użycia.

Możesz pisać bardziej niezawodne analizatory składni , ale napisanie kompletnego i niezawodnego niestandardowego analizatora składni z wyrażeniami regularnymi to strata czasu, gdy wspomniane biblioteki już istnieją i wykonują znacznie lepszą robotę.

Zobacz także Parsing Html The Cthulhu Way


Książki

Jeśli chcesz wydać trochę pieniędzy, spójrz na

Nie jestem związany z PHP Architectem ani autorami.

Gordon
źródło
10
@Naveed zależy od twoich potrzeb. Nie potrzebuję zapytań CSS Selector, dlatego używam DOM wyłącznie z XPath. phpQuery ma być portem jQuery. Zend_Dom jest lekki. Naprawdę musisz je sprawdzić, aby zobaczyć, który najbardziej Ci się podoba.
Gordon,
2
@ Ms2ger Głównie, ale nie do końca. Jak już wspomniano powyżej, możesz używać parserów opartych na libxml, ale istnieją specjalne przypadki, w których będą się dusić. Jeśli potrzebujesz maksymalnej kompatybilności, lepiej skorzystać z dedykowanego analizatora składni. Wolę zachować to rozróżnienie.
Gordon,
9
Twój punkt za nieużywanie PHP Simple Parser DOM DOM wydaje się być dyskusyjny.
Petah
3
Na dzień 29 marca 2012 r. DOM nie obsługuje HTML5, XMLReader nie obsługuje HTML, a ostatnie zatwierdzenie na HTML5lib dla PHP jest we wrześniu 2009. Czego używać, aby analizować HTML5, HTML4 i XHTML?
Shiplu Mokaddim
4
@Nasha Celowo wykluczyłem niesławny rant Zalgo z powyższej listy, ponieważ sam w sobie nie jest zbyt pomocny i doprowadził do dość kultowego ładunku od czasu jego napisania. Ludzie zostali spoliczkowani tym linkiem, bez względu na to, jak odpowiednie byłoby wyrażenie regularne jako rozwiązanie. Aby uzyskać bardziej wyważoną opinię, zapoznaj się z linkiem, który zamieściłem, i przejrzyj komentarze na stackoverflow.com/questions/4245008/…
Gordon
322

Wypróbuj prosty parser DOM HTML

  • Parser DOM HTML napisany w PHP 5+, który pozwala manipulować HTML w bardzo łatwy sposób!
  • Wymagaj PHP 5+.
  • Obsługuje nieprawidłowy HTML.
  • Znajdź tagi na stronie HTML za pomocą selektorów takich jak jQuery.
  • Wyodrębnij zawartość z HTML w jednym wierszu.
  • Pobieranie


Przykłady:

Jak zdobyć elementy 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>';


Jak modyfikować elementy 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;


Wyodrębnij zawartość z HTML:

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


Skrobanie Slashdot:

// 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);
Naveed
źródło
8
Cóż, po pierwsze są rzeczy, na które muszę się przygotować, takie jak zły DOM, kod Invlid, a także analiza js pod kątem silnika DNSBL, będzie to również służyć do wyszukiwania złośliwych stron / treści, również gdy zbudowałem swoją witrynę wokół frameworka i zbudowałem, musi być czysty, czytelny i dobrze zorganizowany. SimpleDim jest świetny, ale kod jest nieco niechlujny
RobertPitt
9
@Robert możesz również zajrzeć na stronę htmlpurifier.org, aby uzyskać informacje dotyczące bezpieczeństwa.
Gordon,
3
Ma jeden ważny punkt: simpleHTMLDOM jest trudny do rozszerzenia, chyba że użyjesz wzoru dekoratora, co wydaje mi się niewygodne. Znalazłem sobie dreszcz po prostu dokonywania zmian w podstawowej klasa (-y) sami.
Erik
1
Przed wysłaniem go do SimpleDOM uruchomiłem mój html.
MB34
1
Obecnie używam tego, uruchamiając go jako część projektu do przetworzenia kilkuset adresów URL. Robi się bardzo powoli i utrzymują się regularne limity czasu. Jest to świetny skrypt dla początkujących i intuicyjnie prosty w nauce, ale zbyt prosty dla bardziej zaawansowanych projektów.
luke_mclachlan
236

Wystarczy użyć DOMDocument-> loadHTML () i gotowe. Algorytm parsowania HTML libxml jest dość dobry i szybki, i wbrew powszechnemu przekonaniu, nie dusi się na źle sformułowanym HTML.

Edward Z. Yang
źródło
19
Prawdziwe. Działa z wbudowanymi w PHP klasami XPath i XSLTProcessor, które świetnie nadają się do wyodrębniania zawartości.
Kornel,
8
W przypadku naprawdę zniekształconego HTML zawsze możesz uruchomić go za pomocą htmltidy przed przekazaniem go do DOM. Ilekroć muszę zeskrobywać dane z HTML, zawsze używam DOM lub przynajmniej simplexml.
Frank Farmer
9
Kolejną rzeczą przy ładowaniu źle sformatowanego HTML i jest to, że rozsądne może być wywołanie libxml_use_internal_errors (true), aby uniknąć ostrzeżeń, które przestaną być przetwarzane.
Husky
6
Użyłem DOMDocument do parsowania około 1000 źródeł html (w różnych językach zakodowanych za pomocą różnych zestawów znaków) bez żadnych problemów. Możesz napotkać na to problemy z kodowaniem, ale nie są one nie do pokonania. Musisz wiedzieć 3 rzeczy: 1) loadHTML używa zestawu znaków metatagu do określenia kodowania 2) # 2 może prowadzić do nieprawidłowego wykrywania kodowania, jeśli zawartość HTML nie zawiera tych informacji 3) złe znaki UTF-8 mogą wywołać parser. W takich przypadkach, w celu obejścia tego problemu, użyj kombinacji mb_detect_encoding () i kodowania / konwersji / usuwania nieprawidłowego kodu UTF-8 Parser RSS Parser.
Zero
1
DOM faktycznie obsługuje XPath, spójrz na DOMXPath .
Ryan McCue
147

Dlaczego nie powinieneś i kiedy powinieneś używać wyrażeń regularnych?

Po pierwsze, często mylące: Regexps nie są przeznaczone do parsowania HTML. Regeksy mogą jednak wydobywać dane. Wydobywanie jest do czego są przeznaczone. Główną wadą ekstrakcji wyrażeń regularnych HTML w porównaniu z odpowiednimi zestawami narzędzi SGML lub bazowymi parserami XML jest ich składniowy wysiłek i różna niezawodność.

Weź pod uwagę, że wykonanie wyrażenia regularnego w pewnym stopniu zależnego od ekstrakcji HTML:

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

jest znacznie mniej czytelny niż zwykły phpQuery lub odpowiednik QueryPath:

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

Istnieją jednak konkretne przypadki użycia, w których mogą pomóc.

  • Wiele nakładek DOM przechodzących nie ujawnia komentarzy HTML <!--, które jednak są czasem bardziej przydatnymi kotwicami do ekstrakcji. W szczególności odmiany pseudo-HTML <$var>lub reszty SGML są łatwe do oswojenia za pomocą wyrażeń regularnych.
  • Często wyrażenia regularne mogą zaoszczędzić na przetwarzaniu końcowym. Jednak jednostki HTML często wymagają ręcznego zarządzania.
  • I wreszcie, w przypadku niezwykle prostych zadań, takich jak wyodrębnianie adresów URL <img src =, są one w rzeczywistości prawdopodobnym narzędziem. Przewaga szybkości w porównaniu z parserami SGML / XML w większości przypadków pojawia się w przypadku tych bardzo podstawowych procedur ekstrakcji.

Czasami wskazane jest nawet wstępne wyodrębnienie fragmentu kodu HTML przy użyciu wyrażeń regularnych /<!--CONTENT-->(.+?)<!--END-->/i przetworzenie pozostałej części za pomocą prostszych nakładek parsera HTML.

Uwaga: Mam tę aplikację , w której na przemian używam parsowania XML i wyrażeń regularnych. W zeszłym tygodniu parsowanie PyQuery zepsuło się, a regex nadal działał. Tak dziwne i sam nie potrafię tego wyjaśnić. Ale tak się stało.
Więc proszę, nie głosuj za odrzuceniem rzeczywistych względów, tylko dlatego, że nie pasują one do wyrażenia regularnego = zły mem. Ale nie głosujmy też za bardzo. To tylko sidenote dla tego tematu.

mario
źródło
20
DOMCommentmoże czytać komentarze, więc nie ma powodu, aby używać do tego Regex.
Gordon,
4
Ani zestawy narzędzi SGML, ani parsery XML nie nadają się do analizowania rzeczywistego kodu HTML. W tym celu odpowiedni jest tylko dedykowany parser HTML.
Alohci,
12
@Alohci DOMużywa libxml, a libxml ma osobny moduł analizatora HTML , który będzie używany podczas ładowania HTML, loadHTML()dzięki czemu może bardzo ładować „rzeczywisty” (zepsuty) HTML.
Gordon,
6
Cóż, tylko komentarz na temat twojego „rozważania w świecie rzeczywistym”. Jasne, istnieją pewne przydatne sytuacje dla Regex podczas analizowania HTML. Są też przydatne sytuacje do korzystania z GOTO. I są przydatne sytuacje dla zmiennych-zmiennych. Tak więc żadna konkretna implementacja nie jest definitywnie zgnilizowana przy użyciu kodu. Ale to BARDZO silny znak ostrzegawczy. A przeciętny programista prawdopodobnie nie będzie wystarczająco niuansowany, aby odróżnić. Zasadniczo Regex GOTO i Zmienne-Zmienne są złe. Są zastosowania inne niż złe, ale są to wyjątki (i w tym rzadkie) ... (IMHO)
ircmaxell
11
@mario: W rzeczywistości HTML można „poprawnie” przeanalizować za pomocą wyrażeń regularnych , chociaż zwykle potrzeba kilku z nich, aby wykonać dobrą robotę. W ogólnym przypadku to tylko królewski ból. W szczególnych przypadkach z dobrze zdefiniowanymi danymi wejściowymi graniczy z trywialnością. Są to przypadki, w których ludzie powinni używać wyrażeń regularnych. Wielkie stare, głodne, ciężkie parsery są naprawdę tym, czego potrzebujesz w ogólnych przypadkach, chociaż zwykły użytkownik nie zawsze jest jasny, gdzie narysować tę linię. Którykolwiek kod jest prostszy i łatwiejszy, wygrywa.
tchrist
131

phpQuery i QueryPath są bardzo podobne w replikacji płynnego API jQuery. Dlatego też są to dwa najprostsze podejścia do prawidłowej analizy HTML w PHP.

Przykłady dla QueryPath

Zasadniczo najpierw tworzysz drzewo DOM z zapytaniami na podstawie łańcucha HTML:

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

Powstały obiekt zawiera pełną reprezentację drzewa dokumentu HTML. Można go przechodzić przy użyciu metod DOM. Ale powszechnym podejściem jest używanie selektorów CSS jak w jQuery:

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

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

Najczęściej chcesz używać prostych #idi / .classlub DIVznaczników do ->find(). Ale możesz także użyć instrukcji XPath , które czasem są szybsze. Również typowe metody jQuery, takie jak ->children()i, ->text()szczególnie, ->attr()upraszczają wyodrębnianie właściwych fragmentów HTML. (I już zdekodowały swoje encje SGML).

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

QueryPath pozwala również wstrzykiwać nowe tagi do stream ( ->append), a następnie generować i aktualizować zaktualizowany dokument ( ->writeHTML). Może nie tylko analizować zniekształcony HTML, ale także różne dialekty XML (z przestrzeniami nazw), a nawet wyodrębniać dane z mikroformatów HTML (XFN, vCard).

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

.

phpQuery lub QueryPath?

Ogólnie QueryPath lepiej nadaje się do manipulowania dokumentami. Podczas gdy phpQuery implementuje również niektóre pseudo metody AJAX (tylko żądania HTTP), aby bardziej przypominały jQuery. Mówi się, że phpQuery jest często szybszy niż QueryPath (z powodu mniejszej liczby ogólnych funkcji).

Aby uzyskać więcej informacji na temat różnic zobacz to porównanie na maszynie powrotnej z tagbyte.org . (Zaginęło oryginalne źródło, więc oto link do archiwum internetowego. Tak, nadal możesz znaleźć brakujące strony, ludzie).

A oto kompleksowe wprowadzenie do QueryPath .

Zalety

  • Prostota i niezawodność
  • Proste w użyciu alternatywy ->find("a img, a object, div a")
  • Prawidłowe odwzorowywanie danych (w porównaniu do grepowania wyrażeń regularnych)
Mario
źródło
88

Simple HTML DOM to świetny parser typu open source:

simplehtmldom.sourceforge

Traktuje elementy DOM w sposób zorientowany obiektowo, a nowa iteracja ma duży zasięg dla kodu niezgodnego. Istnieje również kilka świetnych funkcji, które można zobaczyć w JavaScript, takich jak funkcja „znajdź”, która zwróci wszystkie wystąpienia elementów tej nazwy znacznika.

Użyłem tego w wielu narzędziach, testując go na wielu różnych typach stron internetowych i myślę, że działa świetnie.

Robert Elwell
źródło
61

Jednym z ogólnych podejść, o których tu nie wspominałem, jest uruchamianie HTML-a przez Tidy , który można ustawić tak, aby wypluł gwarantowany XHTML. Następnie możesz użyć dowolnej starej biblioteki XML.

Ale na swój konkretny problem powinieneś rzucić okiem na ten projekt: http://fivefilters.org/content-only/ - to zmodyfikowana wersja algorytmu Readability , który został zaprojektowany w celu wyodrębnienia tylko treści tekstowej (nie nagłówków i stopki) ze strony.

Eli
źródło
56

Dla 1a i 2: Głosowałbym na nową klasę DOMCrawler Symfony Componet ( DomCrawler ). Ta klasa pozwala na zapytania podobne do Selektorów CSS. Spójrz na tę prezentację, aby zobaczyć przykłady z prawdziwego świata: news-of-the-symfony2-world .

Komponent jest przeznaczony do samodzielnego działania i może być używany bez Symfony.

Jedyną wadą jest to, że będzie działać tylko z PHP 5.3 lub nowszym.

Timo
źródło
jquery-podobne zapytania css są dobrze powiedziane, ponieważ w dokumentacji w3c brakuje pewnych rzeczy, ale są one obecne jako dodatkowe funkcje w jquery.
Nikola Petkanski
53

Nawiasem mówiąc, jest to powszechnie określane jako zgarnianie ekranu . Biblioteka, której użyłem do tego, to Simple HTML Dom Parser .

Joel Verhagen
źródło
8
Nie do końca prawda ( en.wikipedia.org/wiki/Screen_scraping#Screen_scraping ). Wskazówka znajduje się w „ekranie”; w opisanym przypadku nie jest zaangażowany ekran. Chociaż, co prawda, termin ten spotkał się z okropnym nadużywaniem w ostatnim czasie.
Bobby Jack
4
Nie będę zgarniać ekranu, treść, która zostanie przeanalizowana, zostanie autoryzowana przez dostawcę treści na podstawie mojej umowy.
RobertPitt,
41

Wcześniej stworzyliśmy całkiem sporo robotów dla naszych potrzeb. Na koniec dnia najlepiej sprawdzają się proste wyrażenia regularne. Chociaż biblioteki wymienione powyżej są dobre z tego powodu, że zostały utworzone, jeśli wiesz, czego szukasz, wyrażenia regularne są bezpieczniejszym sposobem, ponieważ możesz obsługiwać również niepoprawne struktury HTML / XHTML , które zawiodłyby, gdyby zostały załadowane przez większość parserów.

jancha
źródło
36

To brzmi jak dobry opis zadania technologii XPath W3C . Łatwo jest wyrazić zapytania takie jak „zwróć wszystkie hrefatrybuty w imgzagnieżdżonych znacznikach <foo><bar><baz> elements”. Nie będąc maniakiem PHP, nie mogę powiedzieć, w jakiej formie XPath może być dostępny. Jeśli możesz wywołać program zewnętrzny w celu przetworzenia pliku HTML, powinieneś być w stanie użyć wersji XPath z wiersza poleceń. Aby uzyskać krótkie wprowadzenie, zobacz http://en.wikipedia.org/wiki/XPath .

Jens
źródło
29

Zewnętrzne alternatywy dla SimpleHtmlDom, które używają DOM zamiast parsowania ciągów: phpQuery , Zend_Dom , QueryPath i FluentDom .

Amal Murali
źródło
3
Jeśli już skopiowałeś moje komentarze, przynajmniej połącz je poprawnie;) Powinno to być: Sugerowane przez osoby trzecie alternatywne dla SimpleHtmlDom, które faktycznie używają DOM zamiast Parsowania ciągów: phpQuery , Zend_Dom , QueryPath i FluentDom .
Gordon
1
Dobre odpowiedzi są doskonałym źródłem. stackoverflow.com/questions/3606792/…
danidacar
24

Tak, w tym celu możesz użyć simple_html_dom. Jednak sporo pracowałem z simple_html_dom, szczególnie w przypadku złomowania stron internetowych i stwierdziłem, że jest zbyt podatny na ataki. Wykonuje podstawową pracę, ale i tak jej nie polecę.

Nigdy nie użyłem curl do tego celu, ale nauczyłem się, że curl może wykonać pracę znacznie wydajniej i jest o wiele bardziej solidny.

Uprzejmie sprawdź ten link: scraping-sites-with-curl

Rafay
źródło
2
curl może pobrać plik, ale nie przeanalizuje dla Ciebie HTML. To trudna część.
cHao
23

QueryPath jest dobry, ale należy uważać na „stan śledzenia”, ponieważ jeśli nie zdajesz sobie sprawy, co to znaczy, może to oznaczać, że tracisz dużo czasu na debugowanie, próbując dowiedzieć się, co się stało i dlaczego kod nie działa.

Oznacza to, że każde wywołanie zestawu wyników modyfikuje zestaw wyników w obiekcie, nie jest on łańcuchowy jak w jquery, gdzie każde łącze jest nowym zestawem, masz jeden zestaw, który jest wynikiem zapytania i każde wywołanie funkcji modyfikuje ten pojedynczy zestaw.

Aby uzyskać zachowanie podobne do jquery, musisz rozgałęzić się przed wykonaniem operacji typu filtruj / zmodyfikuj, co oznacza, że ​​będzie znacznie dokładniej odzwierciedlać to, co dzieje się w jquery.

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

$resultsteraz zawiera zestaw wyników input[name='forename']NIE dla oryginalnego zapytania "div p", co mnie bardzo potknęło. Odkryłem, że QueryPath śledzi filtry i znaleziska oraz wszystko, co modyfikuje wyniki i przechowuje je w obiekcie. musisz to zrobić zamiast tego

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

wtedy $resultsnie zostanie zmodyfikowany i będziesz mógł ponownie używać zestawu wyników, być może ktoś z dużo większą wiedzą może to trochę wyjaśnić, ale w zasadzie tak jest z tego, co znalazłem.

Christopher Thomas
źródło
20

Advanced Html Dom jest prostym zamiennikiem DOM HTML HTML, który oferuje ten sam interfejs, ale jest oparty na DOM, co oznacza, że ​​nie występują żadne powiązane problemy z pamięcią.

Posiada również pełną obsługę CSS, w tym rozszerzenia jQuery .

pguardiario
źródło
Mam dobre wyniki z Advanced Html Dom i myślę, że powinien on znajdować się na liście w zaakceptowanej odpowiedzi. Ważna rzecz, o której należy wiedzieć dla każdego, kto polega na jej „Celem tego projektu jest zastąpienie DOM-a prostą biblioteką domową PHP HTML ... Jeśli używasz pliku / str_get_html, nie musisz zmień wszystko ”. archive.is/QtSuj#selection-933.34-933.100 jest takie, że może być konieczne wprowadzenie zmian w kodzie, aby uwzględnić pewne niezgodności. Zauważyłem cztery znane mi problemy z githubem projektu. github.com/monkeysuffrage/advanced_html_dom/issues
ChrisJJ
Pracował! Dzięki
Faisal Shani
18

W przypadku HTML5 lib html5 jest porzucony od lat. Jedyną biblioteką HTML5, którą mogę znaleźć z ostatnimi rekordami aktualizacji i konserwacji, jest html5-php, który został właśnie wprowadzony do wersji beta nieco ponad tydzień temu.

Reid Johnson
źródło
17

Napisałem parser XML ogólnego przeznaczenia, który może z łatwością obsługiwać pliki GB. Jest oparty na XMLReaderze i jest bardzo łatwy w użyciu:

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

Oto repozytorium github: XmlExtractor

Paul Warelis
źródło
17

Stworzyłem bibliotekę o nazwie PHPPowertools / DOM-Query , która pozwala na indeksowanie dokumentów HTML5 i XML tak samo jak w jQuery.

Pod maską wykorzystuje symfony / DomCrawler do konwersji selektorów CSS na selektory XPath . Zawsze używa tego samego DomDocument, nawet przy przekazywaniu jednego obiektu do drugiego, aby zapewnić przyzwoitą wydajność.


Przykładowe zastosowanie:

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>');

[...]

Obsługiwane metody:


  1. Z oczywistych powodów przemianowano go na „wybierz”
  2. Nazwę „void”, ponieważ „puste” jest słowem zastrzeżonym w PHP

UWAGA :

Biblioteka zawiera również własny autoloader o zerowej konfiguracji dla bibliotek kompatybilnych z PSR-0. Dołączony przykład powinien działać od razu bez dodatkowej konfiguracji. Alternatywnie możesz użyć go z kompozytorem.

John Slegers
źródło
Wygląda na odpowiednie narzędzie do zadania, ale nie ładuje się dla mnie w PHP 5.6.23 w Worpress. Wszelkie dodatkowe wskazówki, jak poprawnie to uwzględnić ?. Zawarte w: zdefiniuj („BASE_PATH”, dirname ( FILE )); zdefiniuj („LIBRARY_PATH”, BASE_PATH. DIRECTORY_SEPARATOR. 'lib / vendor'); wymagają LIBRARY_PATH. DIRECTORY_SEPARATOR. „Loader.php”; Loader :: init (tablica (LIBRARY_PATH, USER_PATH)); in functions.php
lithiumlab 17.10.16
15

Możesz spróbować użyć czegoś takiego jak HTML Tidy, aby wyczyścić dowolny „uszkodzony” HTML i przekonwertować HTML na XHTML, który możesz następnie przeanalizować za pomocą analizatora składni XML.

CesarB
źródło
15

Inną opcją, którą możesz wypróbować, jest QueryPath . Jest inspirowany przez jQuery, ale na serwerze w PHP i używany w Drupal .

Ric
źródło
12

XML_HTMLSaxjest raczej stabilny - nawet jeśli nie jest już utrzymywany. Inną opcją może być przepuszczanie HTML przez HTML Tidy, a następnie parsowanie go za pomocą standardowych narzędzi XML.

troelskn
źródło
11

Struktura Symfony ma pakiety, które mogą analizować HTML, i możesz użyć stylu CSS, aby wybrać DOM, zamiast używać XPath .

Tuong Le
źródło
11

Istnieje wiele sposobów przetwarzania DOM / HTML / XML, o których większość już wspomniano. Dlatego nie podejmę żadnej próby wymieniać je osobiście.

Chcę tylko dodać, że osobiście wolę używać rozszerzenia DOM i dlaczego:

  • iit optymalnie wykorzystuje przewagę wydajności bazowego kodu C.
  • to jest OO PHP (i pozwala mi go podklasować)
  • jest raczej niski poziom (co pozwala mi używać go jako nie nadęty fundament dla bardziej zaawansowanych zachowań)
  • zapewnia dostęp do każdej części DOM (w przeciwieństwie do np. SimpleXml, który ignoruje niektóre mniej znane funkcje XML)
  • ma składnię używaną do indeksowania DOM, która jest podobna do składni używanej w natywnym JavaScript.

I chociaż brakuje mi możliwości użycia selektorów CSS DOMDocument, istnieje dość prosty i wygodny sposób na dodanie tej funkcji: podklasowanie DOMDocumenti dodawanie metod podobnych do JS querySelectorAlli querySelectormetod do podklasy.

Do analizowania selektorów polecam użycie bardzo minimalistycznego komponentu CssSelector z frameworka Symfony . Ten składnik po prostu tłumaczy selektory CSS na selektory XPath, które można następnie wprowadzić do a, DOMXpathaby pobrać odpowiednią listę Nodelist.

Następnie możesz użyć tej (wciąż bardzo niskiego poziomu) podklasy jako podstawy dla klas wyższych poziomów, przeznaczonych np. Do. analizuj bardzo specyficzne typy XML lub dodaj więcej zachowań podobnych do jQuery.

Poniższy kod pochodzi z mojej biblioteki DOM-Query i wykorzystuje opisaną przeze mnie technikę.

Do parsowania 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);
                }
            }
        }
    }

    [...]
}

Zobacz także Analizowanie dokumentów XML za pomocą selektorów CSS przez twórcę Symfony, Fabiena Potenciera, na temat jego decyzji o utworzeniu komponentu CssSelector dla Symfony i sposobu jego użycia.

John Slegers
źródło
9

Dzięki FluidXML możesz wyszukiwać i iterować XML używając XPath i CSS Selector .

$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

Daniele Orlando
źródło
7

JSON i tablica z XML w trzech wierszach:

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

Ta da!

Antonio Max
źródło
7

Istnieje kilka powodów, aby nie analizować HTML za pomocą wyrażeń regularnych. Ale jeśli masz całkowitą kontrolę nad tym, jaki kod HTML zostanie wygenerowany, możesz to zrobić za pomocą prostego wyrażenia regularnego.

Powyżej jest to funkcja, która analizuje HTML przez wyrażenie regularne. Zauważ, że ta funkcja jest bardzo czuła i wymaga, aby HTML przestrzegał pewnych reguł, ale działa bardzo dobrze w wielu scenariuszach. Jeśli potrzebujesz prostego parsera i nie chcesz instalować bibliotek, spróbuj:

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/")));
Daniel Loureiro
źródło
2

Utworzyłem bibliotekę o nazwie HTML5DOMDocument, która jest bezpłatnie dostępna na stronie https://github.com/ivopetkov/html5-dom-document-php

Obsługuje również selektory zapytań, które moim zdaniem będą niezwykle pomocne w twoim przypadku. Oto przykładowy kod:

$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;
Ivo Petkov
źródło
0

Jeśli znasz selektor jQuery, możesz użyć ScarletsQuery dla PHP

<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);

Ta biblioteka zazwyczaj zajmuje mniej niż 1 sekundę na przetwarzanie HTML offline.
Akceptuje również nieprawidłowy kod HTML lub brakujący cytat na atrybutach tagu.

StefansArya
źródło
0

Najlepsza metoda parsowania 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;
}
8031209
źródło