Php parser za html stranice. PHP parser je jednostavan. Dobivanje bloka po ID-u

Odlučili smo ažurirati članak. Ranije na ovoj stranici predstavljen je univerzalni parser za HTML stranice u PHP-u. Ali prošlo je više od 4 godine, stekao sam više iskustva u razvoju parsera. I odlučio da objavim novu PHP primjer parser sa detaljnom analizom algoritma.

Parser prethodne verzije nosio je ponosnu titulu univerzalnog, ali je bio vrlo simbol. Skripta je imala mnoga ograničenja, za njenu punu upotrebu bilo je potrebno znanje u regularnim izrazima u PHP-u i JS-u.

Ponekad je potrebno pročitati korisničke podatke, kao što su izrazi formule, jednostavne oznake ili čak formatiranje stringova. Ovaj korisnički unos mora se raščlaniti i pretvoriti u obrazac koji možete obraditi. Možda želite da izgradite hijerarhiju objekata ili želite da kreirate formatirani izlazni niz koji odražava ono što je korisnik otkucao.

Takođe, želite da vaš parser kaže korisniku kada postoji problem sa unosom, kao što je sintaksička greška, i kreira značajnu poruku o grešci. Proces raščlanjivanja korisničkog unosa sadrži nekoliko koraka. Marker može biti jedan znak ili niz znakova.

Razmišljao sam, razmišljao i odlučio da bi univerzalnije rješenje bilo pokazati primjer parsera u PHP-u i reći kako on radi. Tako će programeri koji prethodno nisu pisali parsere moći riješiti svoje probleme. I kupci će moći da razumeju mogućnosti PHP-a u oblasti parsiranja sajtova i šta se zaista može zahtevati od programera.

Parser je program koji analizira ulazne tekstualne podatke, izdvaja potrebne informacije i na osnovu primljenih podataka proizvodi rezultat u datom formatu.

Gramatika definira skup pravila koja specificiraju koji se tip unosa očekuje. Gramatika radi na nivou markera. jednostavno pravilo raščlaniti zbir dvije varijable može biti. Stvaranje gramatike je pomalo apstraktan proces i obično se radi na komadu papira. Postoje različiti algoritmi za generiranje koda parsera. Ovisno o složenosti gramatike, ovaj zadatak se često izvodi pomoću generatora parsera. Generirani kod će tada procijeniti tokene i odlučiti o primjenjivim gramatičkim pravilima.

Opći algoritam PHP za raščlanjivanje pretpostavlja da vaša skripta šalje zahtjev na datu adresu, prima odgovor od servera u obliku HTML stranice ili u nekom drugom tekstualnom formatu, kao što je CSV, JSON, XML. Nadalje, primljene informacije se analiziraju, iz njih se izvlače (raščlanjuju) potrebni podaci, na osnovu kojih se formira rezultat. Primljeni podaci mogu biti prikazani na ekranu, ili upisani u datoteku ili bazu podataka.

U ovoj seriji ćemo pokriti samo jednostavnu gramatiku. Za jednostavne gramatike, parser se može ručno kodirati pomoću algoritma rekurzivnog spuštanja. Ovi koraci su neophodni da bi se ulazni niz pretvorio u strukturu podataka koju program može kasnije koristiti. Radnje mogu uključivati ​​izgradnju strukture stabla objekata ili pisanje fragmenta formatiranog niza u tok.

Pisanje parsera, ovisno o jeziku, umjereno je težak zadatak. U suštini, on mora transformirati dio koda u "apstraktno sintaksno stablo". Na primjer, za sljedeći programski tekst. Glavna poteškoća u pisanju parsera je nemogućnost pravilnog organizovanja koda. Parser bi trebao raditi za više visoki nivo nego čitanje znakova iz niza. Nekoliko savjeta o tome kako zadržati složenost pod kontrolom.

Primjer jednostavnog PHP analizatora html sadržaja

Pretpostavimo da trebamo analizirati cijenu proizvoda na gearbest.com. Skripta čita datu stranicu, zatim pomoću regularni izrazi analizira njegov sadržaj i izdvaja dijelove HTML koda koji su nam potrebni. Rezultat se zatim prikazuje na ekranu.

/Us"; $buffer = array(); preg_match($regexp, $page, $buffer); $res_arr["price_list"]["currency"] = $buffer; $res_arr["error"] = ""; ) else ( $res_arr["price"] = 0; $res_arr["currency"] = "nodata"; $res_arr["error"] = "Greška pri učitavanju stranice"; ) return $res_arr; ) /* --- 1.4 --- Izlaz u HTML */ /* --- 1.4.1 --- Izlaz primljenih cijena */ funkcija price_list_html($price_list) ( echo "

Cijena: " . $price_list["price"] . " " . $price_list["currency"] ."

Dobijanje elemenata po klasama

  • Napišite puno funkcija i zadržite ih malo.
  • U svakoj funkciji uradite jednu stvar i to dobro.
  • Ne pokušavajte koristiti regularne izraze za raščlanjivanje.
Pošto je ovo modul treće strane, morat ćete ga sami instalirati. Ova biblioteka je vrlo jednostavna za korištenje, ali postoje neke osnove koje biste trebali razmotriti prije nego što je stavite u akciju.

Prvi paragraf će imati indeks 0, a naredni paragrafi će biti indeksirani u skladu sa tim. Unutrašnji tekst predstavlja sadržaj između oznaka, dok vanjski tekst predstavlja sadržaj uključujući i oznaku. Možemo u potpunosti zamijeniti oznaku koristeći vanjski tekst. Dodaćemo još jedan red i promeniti klasu naše oznake drugog paragrafa.

"; ) /* --- 1.4.2 --- Izlaz greške */ funkcija error_list_html($error) ( if (!empty($error)) ( echo "

Došlo je do sljedećih grešaka prilikom obrade zahtjeva:

\n"; eho "
    \n"; foreach($error kao $error_row) ( echo "
  • " . $error_row ."
  • \n"; ) echo "
\n"; eho "

Status: FAIL

\n"; ) else ( echo "

Status: uredu

\n"; ) ) /* --- 1.4.3 --- Ispis greške pri učitavanju stranice */ funkcija error_page_list_html($error_page) ( if (!empty($error_page)) ( echo "
    \n"; foreach($error_page kao $error_row) ( echo "
  • [" . $error_row . "] " . $error_row . " - " . $error_row ."
  • \n"; ) echo "
\n"; ) ) /* --- 1.4.4 --- Izlaz skripte */ funkcija run_time_html($time_start) ( if(!empty($time_start)) echo "\n"; ) /* --- 2 --- Uzmi sadržaj iz Gearbest kataloga */ if($action) ( // ako nema grešaka i podaci obrasca za pretragu se primaju if(!empty($gearbest_url)) ( $gearbest_url = trim($gearbest_url); $din_url = $gearbest_url; $res_arr = get_gearbest_price($din_url); $price_list = $res_arr["price_list"]; $error_page = $res_arr[]error_page" = $error_page res_arr[" error"]; ) else ( $error = "Adresa stranice proizvoda nije postavljena"; ) ) /* --- 3 --- Prikaži rezultate analize */ ?>

Parser cijena proizvoda na Gearbest.com

!}

Mi smo tu i tu smo da ostanemo. Evo nekoliko primjera selektora. Međutim, specificiranjem drugog parametra, kažemo "vrati samo prvi element ove kolekcije". Ostali primjeri su sami po sebi razumljivi. Kompletnu dokumentaciju za biblioteku možete pronaći na.

Pronalaženje informacija koje želimo

Scraping je lukav dio interneta i ne bi se trebao raditi bez dozvole. Također deklariramo globalni niz kako bismo olakšali prikupljanje svih informacija o članku na jednom mjestu. Oni se smatraju čvorovima parsera. Prići će bliže da shvati šta se dešava. Želimo tekst opisa iznutra, tako da zgrabimo vanjski tekst prvog djeteta - ovo će uključivati ​​oznaku pasusa. Jedan unos u člancima sada izgleda ovako.

index.php— glavni PHP fajl skripte parsera. Kod parsera je aktuelan u vrijeme objavljivanja. Vremenom se HTML kod izvorne stranice može promijeniti i regularni izrazi mu više neće odgovarati.

Postoje različiti načini za instaliranje skripte. Radio sam s njim ispod XAMPP-a. Ali možete pokrenuti parser direktno iz . Samo prenesite fajl index.php na svoju stranicu u bilo kojoj mapi i pristupite joj preko adresne trake pretraživača. Pretpostavimo da ste stavili skriptu u folder my -parser u korijenskom direktoriju vašeg hostinga. Zatim u adresnu traku trebate upisati URL: http://yourdomain.ru/my-parser/.

Prva stvar koju radimo je da odredimo kako pronaći našu sljedeću stranicu. Sada se ove informacije mogu koristiti. Ako to ne učinite, možete pojesti svu memoriju koju imate. Ova rekurzija se završava kada više nije potrebno analizirati stranice.

Dobijanje i raščlanjivanje stranice

Prvo ćemo kreirati neke osnovne stilove. Ovo je potpuno proizvoljno - možete napraviti svoj izlaz kako god želite. Ako analizirate veliki broj stranica, ovo može potrajati duže od maksimalnog vremena izvršenja koje dozvoljava vaš server. Na primjer, pokretanje sa mog lokalnog stroja traje oko jedne sekunde po stranici.

Snimak ekrana glavne stranice analizatora cijena sa gearbest.com:

1. Na glavnoj stranici parsera moramo unijeti adresu stranice proizvoda. Nakon klika na dugme "Start", stranica se ponovo učitava, podaci obrasca se šalju na server, a PHP skripta šalje zahtev na navedenu adresu koristeći cURL biblioteku.

Funkcija je odgovorna za ovu radnju. curl_get_contents(), što je analogno standardnoj PHP funkciji file_get_contents(), ali sa proširenom funkcionalnošću zasnovanom na cURL-u.
cURL je PHP ekstenzija koja pruža podršku za biblioteku funkcija libcurl. Ovaj skup funkcija vam omogućava generiranje POST i PUT zahtjeva, preuzimanje datoteka. Podržani su različiti protokoli http, https, ftp, itd. Mogu se koristiti proxy serveri, kolačići i autentikacija korisnika. Općenito, odličan alat za simulaciju radnji korisnika u pretraživaču.

Kao završnu napomenu, uvijek ne zaboravite da dobijete dozvolu prije nego što krenete na web lokaciju; važno je. Prilikom odabira imena bez hash prefiksa, imajte na umu da predložak stranice koji ima isto ime kao funkcija iza kojeg slijedi dvotočka više ne može biti vezan. Posebno izbjegavajte imena funkcija koja su jednaka imenu prostora imena.

Evo kopije dokumentacije. Povratna vrijednost: stara funkcija povratnog poziva za ovo ime, ako postoji. Funkcija povratnog poziva trebala bi biti sljedećeg oblika. Funkcija povratnog poziva može vratiti ili tekstualni rezultat funkcije, ili niz koji sadrži tekst na elementu 0 i neke zastavice na drugim elementima. Imena zastavica navedena su u ključevima.

cURL je vrlo korisna stvar za razvoj HTML parsera, a u jednom od njih ću detaljnije govoriti o tome kako raditi s njim u svrhu raščlanjivanja.


Imajte na umu da skripta vidi stranicu u tekstualnom formatu i da se analizira njen HTML kod.

Pronađeno Vraćeni tekst je važeći, zaustavlja uzorak. Korisnici su često navikli da koriste vertikalne poteze za razdvajanje parametara, tako da mogu biti korisni iu kontekstu funkcije parsera kako bi to omogućili. Evo jednostavnog primjera kako se to može postići. Ovome se dodaje kod koji se koristi za prikaz teksta, na primjer, paragraf ili naslov. Postoje određeni znakovi iz normalnog skupa znakova za izlaz teksta.

Sadržaj između je "opseg" dotičnog elementa. Oznake su označene šiljatim zagradama. Primjer pokazuje zaglavlje. Uvodna oznaka signalizira da je naslov u redu. Zadnji dan označava kraj kursa. Poslednji dan počinje početnom vitičastom zagradom i kosom crtom.

Nedavno radim u jednoj kompaniji OOO Radio City Sahalin u timu programera i novinara infotainment portala Sitisah. Posebno za ljubitelje fudbala, portal održava Sportsku rubriku sa novostima iz svijeta fudbala, tabelama i spiskom igrača tima FK Sahalin.

Postoje i neki elementi sa "samostalnim oznakama", tj. elementi koji ne sadrže sadržaj i stoga se sastoje od samo jedne oznake umjesto početne i završne oznake. Prazni "samostalni" elementi i oznake Potoci i potoci bez leda Kroz osvježavajući, osnažujući izgled.

Na kraju prvog reda, to znači da se mora umetnuti ručni prijelom reda. Alternativno, također možete napisati element sa početnom i završnom oznakom, ali bez sadržaja. Elementi mogu biti ugniježđeni jedan u drugom. Ovo stvara hijerarhijsku strukturu. Stoga stručnjaci govore i o strukturiranom označavanju.

Sada je portal u redizajniranju, pa sam dobio instrukciju da vodim brigu o rubrici "Sport". Moja glavna funkcija u timu je izrada novih dizajna. Ponekad moramo rješavati sporedne zadatke kako bismo olakšali ionako težak posao našeg glavnog programera. Danas ću govoriti o Microparseru.

Prethodno su na portalu fudbalsku tabelu popunjavali ručno menadžeri sadržaja. Postoje slučajevi kada su se rezultati utakmica pojavljivali na stranici Championship.com brže nego na našem portalu. Sada smo konačno odlučili da ažuriranje tabela učinimo automatskim. Budući da Championship.com ne pruža API (barem ne otvoreni) za dobijanje turnirskih tabela koje prikazuje, jedini izlaz je raščlanjivanje.

Dobijanje href linkova

Tekst između i dobija drugačiji prikaz, često kurziv, u većini pretraživača. Pred-oznake i samostalne oznake mogu sadržavati dodatne informacije. Atributi s unaprijed definiranim vrijednostima, na primjer, polje za unos za običan tekst - ovdje su dozvoljene samo određene vrijednosti. Atributi koji se slobodno mogu dodijeliti, međutim, očekuju da određeni tip podataka ili konvencija, na primjer, definira raspon za stilske listove. Ili - polje za unos u koje korisnik može unijeti do 10 znakova - ovdje se očekuje numerička specifikacija. pojedinačni atributi. . Ovo smanjuje mogućnost grešaka prilikom stavljanja svih vrijednosti koje dodjeljujete atributima u jednostruke "ili dvostruke" navodnike.

Kako koristiti "Microparser"

"Mikroparser" se sastoji od samo jedne funkcije - parse_site(array $sites, array $defaults = array()) . Prvi argument je niz lokacija (ili stranica na istoj lokaciji) koje treba raščlaniti, a drugi argument je niz zadanih postavki.

Niz $sites ima sljedeći format:

Array("zona_vostok" => array("url" => "http://www.championat.com/football/_russia2d/589/table/all.html", "xpath" => "some/x/path" , //opciono "xsl" => "absolute/path/to/xsl", //opciono), "stackoverflow" => array("url" => "http://stackoverflow.com", "xpath" = > "some/x/path", "transform" => false //opciono));

Možete miješati ove dvije vrste u datoteci kako god želite, sve dok se isti atribut mora koristiti na početku i na kraju istog znaka. Koji znak odaberete u osnovi nije preferencija. Dodjela vrijednosti atributima može biti osjetljiva na velika i mala slova ili ne ovisi o tipu vrijednosti.

Primjer: generički identifikator atributa. Odjeljak "Univerzalni atributi". Validacija može biti korisna i sa pravne tačke gledišta. U slučaju pravnih sporova u vezi sa web ponudom, sudovi obično razmatraju da li se poštuju "najsavremeniji" ili "priznati tehnički standardi i propisi". Ako su web stranice nevažeće, ovi standardi i propisi se ne poštuju. Tako, na primjer, ako zahtjevi za informacijama za web ponude koje zahtijeva njemački zakon o telemedicini ili Ugovor o radiodifuziji nisu "lako prepoznatljivi" i web ponuda nije važeća, to bi moglo utjecati na rezultat.

Svi ključevi osim url-a su opcioni. Ako XPath izraz nedostaje, stranica navedena u vrijednosti url ključa bit će obrađena u cijelosti. Također možete uključiti XSL stilski list samo ako trebate obraditi "sirovi" kod.

Obratite pažnju na "transform" => lažni ključ. Koristi se kada niz $defaults sadrži zadani XSL stilski list, ali transformacija nije potrebna za ovu stranicu.

Pristup informacijama

Najbolje je da konvertujete podatke na server. Na internetu ili mrežnim aplikacijama. Ako dođe do greške, pojavljuje se odgovarajuća poruka. Ako je sve ispravno, ništa se ne pojavljuje. Postupak koji se ovdje koristi je osnova za sve ostale primjere u ovom članku.

Prvi red definiše ime datoteke koju treba provjeriti. Čim funkcija naiđe na brisanje datoteke, prestaje raditi. Parser je orijentiran na događaje. Na programeru je da osmisli ovu akciju. Ove akcije se sastoje od funkcija. Funkcija prima kao parametar ime deskriptora parsera, ime oznake i niz mogućih atributa. Funkcija ispisuje samo naziv oznake. U ovom primjeru, radnja je ograničena na izdavanje datuma zatvaranja s prethodnom kosom crtom. Ova funkcija uzima ručku parsera kao prvi parametar i specificira imena funkcija kao nizove.

Niz $defaults izbjegava kopiranje postavki u nizu $sites. Može sadržavati samo dva ključa: xpath i xsl. Ostali ključevi se jednostavno zanemaruju.

Sažetak

Parser koji sam napisao sastoji se od jedne funkcije sa dva parametra (za privatne i opće postavke), omogućava vam da učitate cijelu stranicu ili njen zasebni fragment i, ako želite, obradite rezultat pomoću XSL stilskog lista.

Prvi unos nakon deskriptora identificira funkciju za ulaznu oznaku, drugi funkciju za krajnju oznaku. Opremljen ovim rukovaocem, parser se vratio na posao. Jedna od njih je za početnu, a druga za krajnju oznaku. Uključite u listu iz posljednjeg odjeljka ovih redova.

Polja tabele pomažu u otkrivanju grešaka. Da bi nizovi pokazali efekat, napišite funkcije za početne i krajnje oznake. Uvezite potrebne nizove širom svijeta u funkcije. Ako nije, pojavljuje se sama oznaka, praćena tri znaka pitanja.

U početku, da zaobiđem čvorove, htio sam koristiti biblioteku poput phpQuery ili Ganon, ali onda sam razmislio o tome i shvatio da ne bih trebao povlačiti dodatne ovisnosti - možete koristiti već postojeći, ugrađeni alat.

Radni primjer

Pogledajmo na tabeli ruskog fudbalskog prvenstva u drugoj ligi, zoni Istok.

Problem ugniježđenih blokova

Da bi stvarno prikazao podatke između oznaka, programu je potrebna dodatna funkcija. Jedini zadatak u ovoj funkciji je da ispiše podatke o znakovima koji su joj proslijeđeni. Poziva ga drugi rukovalac. Omogućava vam obradu i obradu podataka. Instrukcija za prolazak u strukturu podataka je jednostavna - vrijednosti se tamo ponovo pojavljuju, zahtijeva malo više okolnosti. Sljedeći program pokazuje kako ovo funkcionira.

Foreasp. Prvi niz sadrži vrijednosti iz niza, drugi je indeks iz kojeg pristupate vrijednostima. Na taj način barem nestaju poruke o grešci. Što se tiče dokumenta, postoji niz karakteristika i metoda. Svojstva čvora uključuju ime i tip, te sadržaj oznake. Na primjer, metode izlaze prekrivene oznake ili osnovna "djeca".

S obzirom na to da moramo „povući“ turnirsku tabelu direktno sa stranice, XPath izraz će biti: //div[@id="section-statistics"]/table

Izvorna tabela sadrži mnogo smeća: atribute, klase, inline stilove. Stoga ćemo ga transformirati u ljepši izgled pomoću XSL stilske tablice sa sljedećim sadržajem:

Tim Igre pobjede Neriješeno Gubici lopte Naočare
čak odd

Sada napišimo kod za prikaz gotove turnirske tabele.

$results = parse_site(array("zona_vostok" => array("url" => "http://www.championat.com/football/_russia2d/589/table/all.html", "xpath" => "xpath" " => "//div[@id="section-statistics"]/table", "xsl" => __DIR__."/football.xsl")); print $results["zona_vostok"];

A izlaz je sljedeći HTML kod:

...
Tim Igre pobjede Neriješeno Gubici lopte Naočare
1 Beam-Energy 20 12 6 2 30-17 42
2 Chita 20 12 5 3 28-14 41

Preuzmite "Microparser"

Evo nekoliko načina da dobijete Microparser:

  1. Fork na Githubu: git klon https://github.com/franzose/microparser.git
  2. Preuzmite arhivu: