HTML parseren en schermschrapen met de eenvoudige HTML DOM-bibliotheek

Als u HTML wilt parseren, zijn reguliere expressies niet de juiste keuze. In deze zelfstudie leert u hoe u een open source, gemakkelijk te leren parser gebruikt om HTML van externe bronnen te lezen, aan te passen en terug te spugen. Met behulp van nettuts als een voorbeeld, leert u hoe u een lijst krijgt met alle artikelen die op de site zijn gepubliceerd en deze weer te geven.

Overigens vindt u ook parsers op Envato Market, zoals HTML5 Parser.

HTML5 Parser op Envato Market

Stap 1. Voorbereiding

Het eerste wat u moet doen, is een kopie downloaden van de simpleHTMLdom-bibliotheek, vrij verkrijgbaar via sourceforge.

Er zijn verschillende bestanden in de download, maar de enige die u nodig hebt, is het bestand simple_html_dom.php; de rest zijn voorbeelden en documentatie.


Stap 2. Basisbeginselen van parseren

Deze bibliotheek is heel gemakkelijk te gebruiken, maar er zijn enkele basisprincipes die u moet beoordelen voordat u deze in gebruik neemt.

HTML laden

$ html = nieuw simple_html_dom (); // Laad van een string $ html-> load ('

Hallo Wereld!

Waren hier

'); // Laad een bestand $ html-> load_file ('http://net.tutsplus.com/');

U kunt uw oorspronkelijke object maken door HTML te laden uit een tekenreeks of uit een bestand. Het laden van een bestand kan via een URL of via uw lokale bestandssysteem.

Een waarschuwing: de methode load_file () delegeert de taak naar PHP's file_get_contents. Als allow_url_fopen niet is ingesteld op true in uw php.ini-bestand, kunt u een extern bestand op deze manier mogelijk niet openen. U kunt altijd terugvallen op de CURL-bibliotheek om externe pagina's te laden in dit geval en ze vervolgens in te lezen met de methode load ().

Toegang tot informatie

Zodra u uw DOM-object hebt, kunt u ermee aan de slag gaan door find () te gebruiken en collecties te maken. Een verzameling is een groep objecten die via een selector wordt gevonden - de syntaxis lijkt veel op jQuery.

  

Hallo Wereld!

Waren hier.

In dit voorbeeld HTML gaan we kijken hoe we toegang krijgen tot de informatie in de tweede alinea, deze wijzigen en vervolgens de resultaten weergeven.

# create en laad de HTML include ('simple_html_dom.php'); $ html = nieuw simple_html_dom (); $ HTML-> load ("

Hallo Wereld!

Waren hier

"); # krijg een element dat de tweede paragraaf vertegenwoordigt $ element = $ html-> find (" p "); # wijzig het $ element [1] -> innertext. =" en we zijn hier om te blijven. "; # output it! echo $ html-> save ();

Als u de methode find () gebruikt, wordt altijd een verzameling (array) met tags geretourneerd, tenzij u opgeeft dat u alleen het n-de kind wilt, als een tweede parameter.

Lijnen 2-4: Laad de HTML van een string, zoals eerder uitgelegd.

Regel 7: Deze regel vindt alles

tags in de HTML en retourneert ze als een array. De eerste alinea heeft een index van 0, en volgende alinea's worden dienovereenkomstig geïndexeerd.

regel 10: Hiermee wordt het 2e item in onze verzameling alinea's (index 1) geopend en wordt een aanvulling gemaakt op het kenmerk innertext. Innertext representeert de inhoud tussen de tags, terwijl outertext de inhoud inclusief de tag vertegenwoordigt. We zouden de tag volledig kunnen vervangen door outertext te gebruiken.

We voegen nog een regel toe en passen de klasse van onze tweede alinea-tag aan.

$ element [1] -> class = "class_name"; echo $ html-> save ();

De resulterende HTML van de opdracht opslaan zou zijn:

  

Hallo Wereld!

We zijn hier en we zijn hier om te blijven.

Andere kiezers

Hier zijn enkele andere voorbeelden van selectors. Als je jQuery hebt gebruikt, zullen deze heel vertrouwd lijken.

# krijg de eerste instantie van $ single = $ html-> find ('# foo', 0); # krijg alle elementen met $ collection = $ html-> find ('. foo'); # alle anker-tags op een pagina ophalen $ collection = $ html-> find ('a'); # alle ankertags binnen H1-tags ophalen $ collection = $ html-> find ('h1 a'); # krijg alle img-tags met een titel van 'himom' $ collection = $ html-> find ('img [title = himom]');

Het eerste voorbeeld is niet geheel intuïtief - alle query's bevatten standaard retourreeksen, zelfs een ID-query, die slechts één resultaat zou moeten retourneren. Door de tweede parameter op te geven, zeggen we echter: "retourneer alleen het eerste item van deze verzameling".

Dit betekent dat $ single een enkel element is, in plaats van een array van elementen met één item.

De rest van de voorbeelden spreken voor zichzelf.

Documentatie

Volledige documentatie over de bibliotheek is te vinden op de projectdocumentatiepagina.


Stap 3. Voorbeeld van echte wereld

Om deze bibliotheek in actie te zetten, gaan we een snel script schrijven om de inhoud van de Nettuts-website te schrapen en een lijst met artikelen op de site produceren op titel en beschrijving ... alleen als een voorbeeld. Schrapen is een lastig deel van het web en mag niet zonder toestemming worden uitgevoerd.

omvatten (simple_html_dom.php); $ articles = array (); getArticles (http://net.tutsplus.com/page/76/);

We beginnen met het opnemen van de bibliotheek en het aanroepen van de functie getArticles met de pagina die we willen gaan parsen. In dit geval beginnen we aan het einde en zijn we aardig voor de server van Nettuts.

We verklaren ook een globale array om het eenvoudig te maken alle artikelinformatie op één plek te verzamelen. Voordat we beginnen met het ontleden, laten we kijken hoe een artikeloverzicht wordt beschreven op Nettuts+.

Dit is een standaard post-formaat op de site, inclusief opmerkingen over broncodes. Waarom zijn de opmerkingen belangrijk? Ze tellen als knooppunten voor de parser.


Stap 4. De parserfunctie starten

function getArticles ($ page) global $ articles; $ html = nieuw simple_html_dom (); $ HTML-> load_file ($ pagina); //… meer… 

We beginnen heel eenvoudig met het claimen van onze globale, het maken van een nieuw object simple_html_dom en het laden van de pagina die we willen parseren. Deze functie zal zichzelf later gaan noemen, dus we stellen het in om de URL als een parameter te accepteren.


Stap 5. De gewenste informatie vinden

$ items = $ html-> find ('div [class = preview]'); foreach ($ items als $ post) # onthoud commentaar tellen als knooppunten $ artikelen [] = array ($ post-> kinderen (3) -> outertext, $ post-> children (6) -> first_child () -> outertext ); 

Dit is het vlees van de functie getArticles. Het gaat van dichterbij kijken om echt te begrijpen wat er gebeurt.

Lijn 1: Creëert een array van elementen - div's met de klasse van de preview. We hebben nu een verzameling artikelen opgeslagen in $ items.

Regel 5: $ post verwijst nu naar een enkele div van klassevoorbeeld. Als we de oorspronkelijke HTML bekijken, kunnen we zien dat het derde kind de H1 is die de titel van het artikel bevat. We nemen dat en wijzen het toe aan $ artikelen [index] [0].

Vergeet niet om te beginnen bij 0 en om reacties te tellen bij het bepalen van de juiste index van een onderliggende knoop.

Regel 6: Het zesde kind van $ post is

. We willen de beschrijvende tekst van binnenuit, dus we pakken de buitenste tekst van het eerste kind - dit bevat de alinea-tag. Een enkel record in artikelen ziet er nu als volgt uit:

$ articles [0] [0] = "Mijn artikelnaam hier"; $ articles [0] [1] = "Dit is mijn artikelbeschrijving"

Stap 6, paginering

Het eerste dat we doen, is bepalen hoe we onze volgende pagina kunnen vinden. Op Nettuts + zijn de URL's gemakkelijk te achterhalen, maar we gaan doen alsof ze dat niet zijn en krijgen de volgende link via parsing.

Als we naar de HTML kijken, zien we het volgende:

"

Als er een volgende pagina is (en dat zal niet altijd zo zijn), vinden we een anker met de klasse van 'nextpostslink'. Nu kan die informatie worden gebruikt.

if ($ next = $ html-> find ('a [class = nextpostslink]', 0)) $ URL = $ next-> href; $ HTML-> clear (); unset ($ html); getArticles ($ URL); 

Op de eerste regel zien we of we een anker kunnen vinden met de klasse nextpostslink. Let vooral op de tweede parameter voor find (). Dit geeft aan dat we alleen het eerste element (index 0) van de gevonden verzameling willen retourneren. $ next zal slechts één element bevatten, in plaats van een groep elementen.

Vervolgens wijzen we de HREF van de link toe aan de variabele $ URL. Dit is belangrijk omdat we het HTML-object gaan vernietigen. Vanwege een php5 circulaire referenties geheugenlek moet het huidige object simple_html_dom worden gewist en uitgeschakeld voordat een ander object wordt gemaakt. Als u dit niet doet, kunt u al uw beschikbare geheugen opeten.

Ten slotte noemen we getArticles met de URL van de volgende pagina. Deze recursie eindigt wanneer er geen pagina's meer zijn om te parseren.


Stap 7 Resultaten uitvoeren

Eerst gaan we enkele basistypen instellen. Dit is volkomen willekeurig - u kunt uw uitvoer laten lijken zoals u dat wilt.

#main margin: 80px auto; width: 500px;  h1 font: bold 40px / 38px helvetica, verdana, sans-serif; margin: 0;  h1 a color: # 600; text-decoration: none;  p background: #ECECEC; lettertype: 10px / 14px verdana, schreefloos; marge: 8px 0 15px; rand: 1px #CCC vast; opvulling: 15px;  .item opvulling: 10px; 

Vervolgens gaan we een klein beetje PHP in de pagina plaatsen om de eerder opgeslagen informatie uit te voeren.

"; echo $ item [0]; echo $ item [1]; echo"
";?>

Het uiteindelijke resultaat is een enkele HTML-pagina met alle artikelen, beginnend op de pagina die wordt aangegeven door de eerste oproep getArticles ().


Stap 8 Conclusie

Als u veel pagina's parseert (bijvoorbeeld de hele site), kan het langer duren dan de maximale uitvoeringstijd die door uw server is toegestaan. Als u bijvoorbeeld vanaf mijn lokale computer werkt, duurt het ongeveer één seconde per pagina (inclusief tijd om op te halen).

Op een site als Nettuts, met een huidige 78 pagina's met tutorials, zou dit meer dan een minuut duren.

Deze tutorial zou je moeten starten met HTML-parsing. Er zijn andere methoden om met de DOM te werken, inclusief ingebouwde PHP's, waarmee je met krachtige xpath selectors kunt werken om elementen te vinden. Voor gemakkelijk gebruik en snelle start vind ik deze bibliotheek een van de beste. Houd er als sluitbriefje altijd rekening mee voordat u een site scrapt; dit is belangrijk. Bedankt voor het lezen!