Toon posts:

[PHP] Preg_match_all van een html pagina

Pagina: 1
Acties:

Onderwerpen


  • Bender
  • Registratie: augustus 2000
  • Laatst online: 21:35
Het is iets waar ik al lang mee zit en niet voor elkaar krijg, het zit ongetwijfeld eenvoudig in elkaar maar ik zie denk ik iets over het hoofd.

Ik wil heel eenvoudig info uit een pagina halen, even als voorbeeld van content waarmee ik het niet werkend krijg.

PHP:
1
$response = file_get_contents("http://www.linkedin.com/pub/dir/?first=mark&last=rutte");


Geeft bijvoorbeeld terug:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
                  <h2> 
                    <strong> 
                    <a href="http://www.linkedin.com/pub/mark-h-de-rutte/18/113/37b" title="Mark H de Rutte"> 
                      <span class="given-name">Mark H</span> 
                      <span class="family-name">de Rutte</span></a> 
                    </strong> 
                  </h2> 
                  
                  <dl class="vcard-basic"> 
                      <dt>Title</dt> 
                      <dd class="title">Owner, de Rutte Builders</dd> 
          
                    <dt>Demographic info</dt> 
                    <dd> 
                        <span class="location"> 
                          San Francisco Bay Area
                        </span> 
                        <span class="split"> | </span> 
                        <span class="industry"> 
                          Construction
                        </span> 
                    </dd> 
                  </dl>


Laten we eenvoudig beginnen, ik wil link en naam;
code:
1
2
<strong> 
                    <a href="http://www.linkedin.com/pub/mark-h-de-rutte/18/113/37b" title="Mark H de Rutte">

(dus met spaties en enters)


Dus wat ik heb;
PHP:
1
preg_match_all('/<strong><a href="(.*)" title="(.*)">/msU', $response, $match);

Waarbij ik (.*) gebruik om het nog makkelijker te maken, zal uiteindelijk iets van ([^\"]) worden bij wijze van.


Maar de response is in dit geval 3x een lege array, maw het werkt niet.


Dit werkt dan weer wel
PHP:
1
2
3
4
5
6
7
$test = '
<select name="foo">
   <option value="1">asdfa</option>
 <option>asd</option>
</select>';

preg_match('/<select name="foo">(.*)<\/select>/msU',$test,$matches);


Wat zie ik nou over het hoofd, ik loop hier echt al lang tegenaan maar zie het echt niet.

  • Nvidiot
  • Registratie: mei 2003
  • Laatst online: 23-09 17:03

Nvidiot

notepad!

Gebruik een html parsing library, geen regexp om html te parsen: http://stackoverflow.com/...xhtml-self-contained-tags

What a caterpillar calls the end, the rest of the world calls a butterfly. (Lao-Tze)


  • RaZ
  • Registratie: november 2000
  • Niet online
Ik herken gewoon een vCard in Microformat: klik

  • CodeCaster
  • Registratie: juni 2003
  • Niet online

CodeCaster

👌👀 good shit ✔💯

Je weet dat LinkedIn een API heeft?

As always, we are nailed to a cross of our own construction.


  • FragFrog
  • Registratie: september 2001
  • Laatst online: 18-09 14:19
:Y

Regexen zijn niet alleen ongeschikt, ze zijn ook nog eens een stuk lastiger en onleesbaarder. Hoe je dit bijvoorbeeld in PHP kan doen (uitgaande van je $response string):
PHP:
1
2
3
4
5
6
$document =   new DOMDocument();
$document ->  loadHTML($response);
$header   =   $document -> getElementsByTagName('h2') -> item(0);
$link     =   $header   -> getElementsByTagName('a')  -> item(0);
$target   =   $link     -> getAttribute("href");
$title    =   $link     -> getAttribute("title");

Voila, $target en $title bevatten nu wat je zoekt :)

On a sidenote, RaZ haalt een goed punt aan: als je de gegevens ook een parsebaar formaat kan binnenhalen heeft dat absoluut de voorkeur. HTML wil nog wel eens veranderen, en hoewel een DOMDocument bijvoorbeeld best flexibel is ga je geheid tegen problemen aanlopen zodra linkedin hun layout aanpast. De enige webapp waar ik daadwerkelijk HTML heb lopen parsen met een DOMDocument haalt z'n gegevens van Google Scholar, waarvan ik de API maar niet kan vinden :/

[Voor 6% gewijzigd door FragFrog op 10-11-2010 21:28]

[ Site ] [ twitch ]


  • Bender
  • Registratie: augustus 2000
  • Laatst online: 21:35
Ja, maar is voor nu niet heel handig. Daarnaast is het een langer bestaand probleem niet enkel voorbehouden aan dit, het was meer een voorbeeld.
Ik zoek dus de manier hoe ik het in de toekomst ook op kan lossen :o
RaZ schreef op woensdag 10 november 2010 @ 21:18:
Ik herken gewoon een vCard in Microformat: klik
Ik niet, dat formaat staat toch los van hoe html in elkaar steekt?
FragFrog schreef op woensdag 10 november 2010 @ 21:26:
[...]

:Y

Regexen zijn niet alleen ongeschikt, ze zijn ook nog eens een stuk lastiger en onleesbaarder. Hoe je dit bijvoorbeeld in PHP kan doen (uitgaande van je $response string):
PHP:
1
2
3
4
5
6
$document =   new DOMDocument();
$document ->  loadHTML($response);
$header   =   $document -> getElementsByTagName('h2') -> item(0);
$link     =   $header   -> getElementsByTagName('a')  -> item(0);
$target   =   $link     -> getAttribute("href");
$title    =   $link     -> getAttribute("title");

Voila, $target en $title bevatten nu wat je zoekt :)

On a sidenote, RaZ haalt een goed punt aan: als je de gegevens ook een parsebaar formaat kan binnenhalen heeft dat absoluut de voorkeur. HTML wil nog wel eens veranderen, en hoewel een DOMDocument bijvoorbeeld best flexibel is ga je geheid tegen problemen aanlopen zodra linkedin hun layout aanpast. De enige webapp waar ik daadwerkelijk HTML heb lopen parsen met een DOMDocument haalt z'n gegevens van Google Scholar, waarvan ik de API maar niet kan vinden :/
Ziet er ook wel veelbelovend uit maar ik krijg een foutmelding;
htmlParseEntityRef: expecting ';' in Entity, line: 56

Nu haal ik zelf geen ; uit lijn 56 in de html dus weet ik al niet meer waar het op vast loopt helaas.
(krijg ook meer errors, Tag lintest invalid en Unexpected end tag)

[Voor 69% gewijzigd door Bender op 10-11-2010 21:32]


  • FragFrog
  • Registratie: september 2001
  • Laatst online: 18-09 14:19
Bender schreef op woensdag 10 november 2010 @ 21:26:
Ziet er ook wel veelbelovend uit maar ik krijg een foutmelding;
htmlParseEntityRef: expecting ';' in Entity, line: 56

Nu haal ik zelf geen ; uit lijn 56 in de html dus weet ik al niet meer waar het op vast loopt helaas.
(krijg ook meer errors, Tag lintest invalid en Unexpected end tag)
Tja, het is gebaseerd op de voorbeeld HTML die je post, maar als je brakke HTML probeert te parsen ga je ook geheid tegen problemen aanlopen. Je kan met met de recover parameter aangeven dat je ook brakke HTML wilt parsen, maar ook dat heeft beperkingen. Als er een API of bijvoorbeeld vCard beschikbaar is kun je dan ook beter die gebruiken. HTML scrapen hoort een last-resort noodoplossing te zijn :)

[ Site ] [ twitch ]


  • Bender
  • Registratie: augustus 2000
  • Laatst online: 21:35
FragFrog schreef op woensdag 10 november 2010 @ 21:40:
[...]

Tja, het is gebaseerd op de voorbeeld HTML die je post, maar als je brakke HTML probeert te parsen ga je ook geheid tegen problemen aanlopen. Je kan met met de recover parameter aangeven dat je ook brakke HTML wilt parsen, maar ook dat heeft beperkingen. Als er een API of bijvoorbeeld vCard beschikbaar is kun je dan ook beter die gebruiken. HTML scrapen hoort een last-resort noodoplossing te zijn :)
Als er andere oplossingen zijn zoals API's is het zeker beter.
Maar die zijn er niet altijd, linkedin is waar ik nu toevallig tegenaan loop maar het gebeurt vaker dat ik met een dergelijk issue zit waar geen API's beschikbaar zijn.

  • NMe
  • Registratie: februari 2004
  • Laatst online: 22:02

NMe

Quia Ego Sic Dico.

Bender schreef op woensdag 10 november 2010 @ 21:47:
[...]

Als er andere oplossingen zijn zoals API's is het zeker beter.
Maar die zijn er niet altijd, linkedin is waar ik nu toevallig tegenaan loop maar het gebeurt vaker dat ik met een dergelijk issue zit waar geen API's beschikbaar zijn.
Dan nog zou je moeten kiezen voor het parsen van de HTML middels de classes die PHP daarvoor biedt, niet voor regular expressions. :)

En waarom je regexp niet werkt? Je matcht de whitespace na <strong> niet. Er staat nergens <strong><a.... in de code die je post, wel <strong><enter><tab><tab><tab><tab><a... ;)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • Bender
  • Registratie: augustus 2000
  • Laatst online: 21:35
Maar die whitespace zou dus genegeert moeten worden, dat werkt in het 2e voorbeeld overigens wel goed maar in het eerste niet :(

  • kluyze
  • Registratie: augustus 2004
  • Niet online
Bender schreef op woensdag 10 november 2010 @ 21:26:
[...]

Ziet er ook wel veelbelovend uit maar ik krijg een foutmelding;
htmlParseEntityRef: expecting ';' in Entity, line: 56

Nu haal ik zelf geen ; uit lijn 56 in de html dus weet ik al niet meer waar het op vast loopt helaas.
(krijg ook meer errors, Tag lintest invalid en Unexpected end tag)
Hij verwacht een ';' op die regel, staat er toevallig geen '&' ergens?

  • NMe
  • Registratie: februari 2004
  • Laatst online: 22:02

NMe

Quia Ego Sic Dico.

Bender schreef op woensdag 10 november 2010 @ 22:50:
Maar die whitespace zou dus genegeert moeten worden, dat werkt in het 2e voorbeeld overigens wel goed maar in het eerste niet :(
Waar in jouw regexp staat dat whitespace genegeerd moet worden? Juist. ;)

Maar goed, je bent beter af als je die andere suggestie van hierboven werkend krijgt, dat zou mijn eerste optie zijn.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • ReenL
  • Registratie: augustus 2010
  • Laatst online: 22-03-2015
http://php.net/manual/en/...cre.pattern.modifiers.php
m => Multiline
s => dot all => ook newlines vallen onder de . wildcard
U => Ungreedy => Matched niet meer zoveel mogelijk

Ofwel met je modifiers heb je alleen gezorgt dat je een newline kan matchen met een "punt" en die punt staat niet tussen je strong en je a.

In je teweede voorbeeld zul je zien dat de spaties/tabs/newlines gewoon in je matches array zitten.

  • NMe
  • Registratie: februari 2004
  • Laatst online: 22:02

NMe

Quia Ego Sic Dico.

ReenL schreef op vrijdag 12 november 2010 @ 14:01:
Ofwel met je modifiers heb je alleen gezorgt dat je een newline kan matchen met een "punt" en die punt staat niet tussen je strong en je a.
Punt ster zelfs, anders werkt het nog niet. :P

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • Voutloos
  • Registratie: januari 2002
  • Niet online
Kap nou met eerst de slechtste aanpak uit te werken.

{signature}


  • NMe
  • Registratie: februari 2004
  • Laatst online: 22:02

NMe

Quia Ego Sic Dico.

Voutloos schreef op vrijdag 12 november 2010 @ 14:08:
Kap nou met eerst de slechtste aanpak uit te werken.
In dit topic is eerst de goeie aanpak uitgewerkt, pas toen die op tafel lag heb ik gezegd wat hij fout doet in de slechte aanpak. Als hij alsnog voor de regexp-oplossing kiest is dat zijn eigen probleem. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • Bender
  • Registratie: augustus 2000
  • Laatst online: 21:35
NMe schreef op vrijdag 12 november 2010 @ 14:19:
[...]

In dit topic is eerst de goeie aanpak uitgewerkt, pas toen die op tafel lag heb ik gezegd wat hij fout doet in de slechte aanpak. Als hij alsnog voor de regexp-oplossing kiest is dat zijn eigen probleem. :)
DOMDocument geeft 9 van de 10x problemen in de website, dus dat lijkt me dan ook zeker niet de goede aanpak.
Wat is volgens jou dan de goede aanpak?

  • NMe
  • Registratie: februari 2004
  • Laatst online: 22:02

NMe

Quia Ego Sic Dico.

Had je met die class niet de mogelijkheid om aan te geven dat je met malformed HTML werkt?

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • beetle71
  • Registratie: februari 2003
  • Laatst online: 07-05-2019
Kijk eens of je wellicht gebruik kunt maken van YQL. Dat is echt super voor dit soort dingen. Je kunt via YQL een pagina laden en dan met een soort 'SQL' (duh.. 8) ) data uit die pagina trekken! 't werkt echt belachelijk goed...

Voorbeeldje (te testen via: http://developer.yahoo.com/yql/console/ )
code:
1
2
3
select * from html 
where url="http://www.linkedin.com/pub/dir/?first=mark&last=rutte" 
and xpath='/html/body/div[2]/div/div/div/ol/li/h2/strong/a'


Je kunt evt. de xpath verkorten naar zoiets als dit: '//ol/li/h2/strong/a' of een ander patroon waaraan je de elementen die je wilt hebben kunt herkennen.

Dan krijg je dit als resultaat
XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng"
    yahoo:count="2" yahoo:created="2010-11-24T19:06:35Z" yahoo:lang="en-US">
    <results>
        <a href="http://www.linkedin.com/pub/mark-h-de-rutte/18/113/37b" title="Mark H de Rutte">
            <span class="given-name">Mark H</span>
            <span class="family-name">de Rutte</span>
        </a>
        <a href="http://nl.linkedin.com/pub/mark-rutte/22/105/a65" title="Mark Rutte">
            <span class="given-name">Mark</span>
            <span class="family-name">Rutte</span>
        </a>
    </results>
</query>


Die Xpath expression kun je er simpel uit een pagina halen met bijv. Firebug

[Voor 94% gewijzigd door beetle71 op 24-11-2010 20:18. Reden: Voorbeeldje toegevoegd]

http://www.dreamsolution.nl


  • NMe
  • Registratie: februari 2004
  • Laatst online: 22:02

NMe

Quia Ego Sic Dico.

...waarme je vervolgens alsnog middels een DOM/XML-klasse je results moet lopen uitlezen. Het enige verschil met de beginsituatie is dat je weet dat je geen malformed zooi krijgt, maar of dat het gebruiken (en afhankelijk zijn) van een externe class rechtvaardigt waag ik te betwijfelen. ;)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • pieturp
  • Registratie: april 2004
  • Laatst online: 21-09 21:38

pieturp

gaffa!

NMe schreef op woensdag 24 november 2010 @ 20:35:
...waarme je vervolgens alsnog middels een DOM/XML-klasse je results moet lopen uitlezen. Het enige verschil met de beginsituatie is dat je weet dat je geen malformed zooi krijgt, maar of dat het gebruiken (en afhankelijk zijn) van een externe class rechtvaardigt waag ik te betwijfelen. ;)
YQL kan ook JSON uitspugen, da's dan alweer wat makkelijker ;)

... en etcetera en zo


  • NMe
  • Registratie: februari 2004
  • Laatst online: 22:02

NMe

Quia Ego Sic Dico.

True, maar dan zit je alsnog twee keer te parsen. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • pieturp
  • Registratie: april 2004
  • Laatst online: 21-09 21:38

pieturp

gaffa!

En dan dus?

Een simpele json_decode() is toch geen probleem? 't Is hier geen rocketscience o.i.d. dat het super performant moet zijn, lijkt me.

Oftewel, als het zelf parsen van een DOM (omdat die te ver vernaggeld is) niet lukt, dan laat je het door Yahoo of wie dan ook doen :)

Dat dat dan JSON oplevert is een mooi bijkomend voordeel, niet waar?

... en etcetera en zo


  • FragFrog
  • Registratie: september 2001
  • Laatst online: 18-09 14:19
pieturp schreef op woensdag 24 november 2010 @ 23:43:
Oftewel, als het zelf parsen van een DOM (omdat die te ver vernaggeld is) niet lukt, dan laat je het door Yahoo of wie dan ook doen :)
Dat kan ook gewoon met PHP zelf door de parser op fault-tolerant te zetten. Scheelt je weer een roundtrip naar een externe server, zal de snelheid van je applicatie aardig ten goede komen. Dat je het resultaat dan als JSON of XML terugkrijgt maakt het alleen maar een langere omweg: zou je lokaal een DOMXpath gebruiken krijg je gewoon een DOMNodeList terug waar je direct mee kan werken zonder eerst weer een string te moeten parsen.

Een externe server gebruiken om iets te parsen wat je vervolgens zelf ook nog moet parsen is gewoon een hint dat je niet optimaal bezig bent - ook als die tweede parse relatief simpel is :)

[Voor 15% gewijzigd door FragFrog op 25-11-2010 00:07]

[ Site ] [ twitch ]


  • pieturp
  • Registratie: april 2004
  • Laatst online: 21-09 21:38

pieturp

gaffa!

Mee eens!

... en etcetera en zo


  • RobIII
  • Registratie: december 2001
  • Laatst online: 02:31

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

FragFrog schreef op donderdag 25 november 2010 @ 00:05:
Een externe server gebruiken om iets te parsen wat je vervolgens zelf ook nog moet parsen is gewoon een hint dat je niet optimaal bezig bent - ook als die tweede parse relatief simpel is :)
Laat ik even voorop stellen dat ik 't met je eens ben. Ik wil alleen even aankaarten dat het parsen van JSON/XML is echt totally en utterly te verwaarlozen op een call naar Yihaa!

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Roses are red Violets are blue, Unexpected ‘{‘ on line 32.

Over mij


  • NMe
  • Registratie: februari 2004
  • Laatst online: 22:02

NMe

Quia Ego Sic Dico.

pieturp schreef op woensdag 24 november 2010 @ 23:43:
Dat dat dan JSON oplevert is een mooi bijkomend voordeel, niet waar?
Hoe is iets dat je toch niet echt nodig hebt een voordeel? Daarnaast, over DOM-parsers:
NMe schreef op woensdag 24 november 2010 @ 19:41:
Had je met die class niet de mogelijkheid om aan te geven dat je met malformed HTML werkt?
Dat zei ik vóór die hele JSON-mogelijkheid aangekaart werd, en dat levert een éénmalige parse op in plaats van een dubbele met JSON als nutteloze omweg. ;)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • gitkua
  • Registratie: februari 2005
  • Laatst online: 13-01-2013
Ik liep laatst ook voor een projectje met een vergelijkbaar iets te stoeien. Heb toen uiteindelijk "PHP Simple HTML DOM Parser" gebruikt. Werkt vooral lekker omdat het jQuery-achtige selectors ondersteund (a la ".class #id a"). Vond het handig werken!

http://simplehtmldom.sourceforge.net/

  • FragFrog
  • Registratie: september 2001
  • Laatst online: 18-09 14:19
RobIII schreef op donderdag 25 november 2010 @ 01:25:
Laat ik even voorop stellen dat ik 't met je eens ben. Ik wil alleen even aankaarten dat het parsen van JSON/XML is echt totally en utterly te verwaarlozen op een call naar Yihaa!
Ja, dat was op zich volgens mij ook wel redelijk duidelijk toch? :+ Ik bedoelde maar te zeggen dat als je bijvoorbeeld er eerst een DOMDocument van parsed, daar XML uitpoept en vervolgens een SimpleXMLParser zou gebruiken om de node te vinden die je wilt hebben je evengoed niet optimaal bezig bent :) Zodra je data gaat parsen en als je klaar bent nog een parser nodig hebt zou ik me achter de oren gaan lopen krabben of dat niet handiger kan.

[Voor 10% gewijzigd door FragFrog op 25-11-2010 20:52]

[ Site ] [ twitch ]


  • Clock
  • Registratie: maart 2005
  • Laatst online: 13-09 07:50
gitkua schreef op donderdag 25 november 2010 @ 19:26:
Ik liep laatst ook voor een projectje met een vergelijkbaar iets te stoeien. Heb toen uiteindelijk "PHP Simple HTML DOM Parser" gebruikt. Werkt vooral lekker omdat het jQuery-achtige selectors ondersteund (a la ".class #id a"). Vond het handig werken!

http://simplehtmldom.sourceforge.net/
Gebruik hier ook PHP Simple HTML DOM Parser voor het schrapen van wat lokale web-apps zonder API. Het is goed gedocumenteerd en makkelijk in gebruik. Deed het daarvoor met hele nasty loops door de regels en dan een search en een substring. Werkte an-sich wel, maar naast dat het een ontzettend lelijke oplossing was werkte het na de eerste de beste update van de software al niet meer.

Met een DOM parser is het toch 'iets' robuuster, maar mocht de site/applicatie echt op de kop gaan moet je je code aanpassen natuurlijk.
Pagina: 1


Nintendo Switch (OLED model) Apple iPhone 13 LG G1 Google Pixel 6 Call of Duty: Vanguard Samsung Galaxy S21 5G Apple iPad Pro (2021) 11" Wi-Fi, 8GB ram Nintendo Switch Lite

Tweakers vormt samen met Hardware Info, AutoTrack, Gaspedaal.nl, Nationale Vacaturebank, Intermediair en Independer DPG Online Services B.V.
Alle rechten voorbehouden © 1998 - 2021 Hosting door True

Tweakers maakt gebruik van cookies

Bij het bezoeken van het forum plaatst Tweakers alleen functionele en analytische cookies voor optimalisatie en analyse om de website-ervaring te verbeteren. Op het forum worden geen trackingcookies geplaatst. Voor het bekijken van video's en grafieken van derden vragen we je toestemming, we gebruiken daarvoor externe tooling die mogelijk cookies kunnen plaatsen.

Meer informatie vind je in ons cookiebeleid.

Sluiten

Forum cookie-instellingen

Bekijk de onderstaande instellingen en maak je keuze. Meer informatie vind je in ons cookiebeleid.

Functionele en analytische cookies

Deze cookies helpen de website zijn functies uit te voeren en zijn verplicht. Meer details

janee

    Cookies van derden

    Deze cookies kunnen geplaatst worden door derde partijen via ingesloten content en om de gebruikerservaring van de website te verbeteren. Meer details

    janee