Autor | Zpráva | ||
---|---|---|---|
danhill Profil |
Dobrý den,
opět řeším regexy :) Mám dva dotazy. 1. Mám: $htmlcache = file_get_contents("http://coord.info/GC19905"); echo $htmlcache; (to jen taková drobnost) 2.A to je mnohem horší. Potřebuji v html, které dostanu vyhledat kraj. Ten ale znám dopředu a mám ho u sebe v databázi. Takže si ten daný název kraje vyberu SQL dotazem a pak bych potřeboval pomocí foreach projít určitou část externího html a najít tam patřičné hledané slovo. S tím, že return by byl název toho slova,který by se podařilo nalézt. Tedy v uvedeném příkladě bych hledal někde v sekci: <div class="minorCacheDetails Clear"> <div> In Moravskoslezsky kraj, Czech Republic </div> </div> Jakmile by na něj foreach narazil, tak by funkce vrátila jednoduše "Moravskoslezsky" Je akorát potřeba ošetřit to, aby to hledalo právě jen v určitých místech, protože není vyloučeno, že se kdekoli jinde v textu nebude vyskytovat třeba slovo Praha. A další věc je ta, že jsou dva případy,kde se takto může kraj vyskytovat. Buď zde jak jsem uvedl, a nebo v případě např.: $htmlcache = file_get_contents("http://coord.info/GC5CXXJ"); <meta name="description" content="Blanensky most ? (GC5CXXJ) was created by Joska4 on 09/19/2014. It's a Micro size geocache, with difficulty of 2.5, terrain of 2.5. It's located in Jihomoravsky kraj, Czech Republic. <head id="ctl00_Head1"><meta charset="utf-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /><title> GC5CXXJ Blanensky most ? (Unknown Cache) in Jihomoravsky kraj, Czech Republic created by Joska4 </title Samozřejmě by se na to dalo jít i obráceně. že prostě v textu kraj vyhledám a pak jen zkontroluji, zda ho mám v databázi a výsledek by byl stejný. Ale problém je, že ne vždy ve staženém html je to stejné. Některé země totiž kraje nemají a je uveden pouze stát. Jako třeba zde: $htmlcache = file_get_contents("http://coord.info/GC1A0KM"); A těch variant je prostě ještě mnohem více, proto bych byl raději za obecnou php funkci,která by mi prostě v html našla co potřebuji, respektive, která z mnou hledaných možností se v getnutém html nachází. Pokud žádná, funkce frátí prázdnou hodnotu nebo false a já budu upozorněn, že u kodu XYZ nebyl kraj nalezen, s tím už si poradím,ale jak na samotnou funkci,která by tohle dokázala, s tím potřebuji pomoci. Předem moc děkuji. |
||
juriad Profil |
#2 · Zasláno: 16. 6. 2016, 21:06:03
1) Viz Výpis zdrojového kódu » Ošetření HTML řídicích znaků
2) Použij nějakou knihovnu na zpracování HTML, pěkné je simplehtmldom.sourceforge.net/manual.htm $html = str_get_html("http://coord.info/GC19905"); $sekce = (string) $html->find('div[class=minorCacheDetails Clear] div div', -1); Pak v té sekci můžeš hledat pomocí regexů, zkusil bych něco jako: /In (?:([a-z ]*), )?([a-z ]*)/i |
||
Keeehi Profil |
#3 · Zasláno: 17. 6. 2016, 01:39:35
juriad:
Co se té druhé části týče, tak jdeš na to přesně z druhé strany. Nemůžeš přece vyhledávat podle toho co neznáš a ani nevíš, zda to tam bude. Musíš na to jít přesně obráceně. Vyhledávat podle toho, co víš že tam vždy bude. A to jsou ty HTML tagy, jejich struktura je na každé stránce stejná. Tudíž ten regulár v obecnosti může vypadat takto '~<div class="minorCacheDetails Clear"> <div> (.*?) </div> </div>~' Pár vzpomínek z té doby: - Bílé znaky jsou zrádné. Taky záleží na modifikátorech za samotným reguláem a podle toho tečka žere konce řádků. - V pár případech bylo nutné "řezat" ve více kolech, protože to lépe nešlo kvůli nejednoznačnosti. Prvně se vybrala nějaká větší část kódu a v něm se teprve hledalo to zajímavé. |
||
Radek9 Profil |
#4 · Zasláno: 17. 6. 2016, 10:13:52
K tomu parsování HTML pomocí regexu si neodpustím poslat jeden nádherný příspěvek ze Stack Overflow. :-)
|
||
danhill Profil |
#5 · Zasláno: 17. 6. 2016, 10:37:53
Děkuji moc za rady a názory, no to zas bude dílo na týden práce ... jdu se do toho pustit, no uvidíme kam až se dostanu a kdyžtak napíšu doplňující dotazy.
|
||
Keeehi Profil |
#6 · Zasláno: 17. 6. 2016, 10:51:50
Radek9:
Ten příspěvek znám a částečně má pravdu. Kdybych měl nějaký neznámý kód a chtěl v něm najít třeba všechny odkazy, které mají všechno co každý slušný odkaz mám mít, tak na to regulárním výrazem opravdu nepopíšu. Pokud využívám regulární výraz na to, co by zvládlo pár funkcí strpos a substr, pak se to popsat rozhodně dá. Je to však validní poznámka, že existují HTML/XML parsery a dá se využít jich. Já jsem je proto takové účely nikdy nepoužil, jen na tahání nějakých XML feedů. Alespoň pro ten případ vím, že byl velmi striktní, co se týče toho, jak XML má vypadat. Pokud tam byla nějaká chyba, odmítlo to spolupracovat. Proto bych se chtěl zeptat, jak se to staví k nevalinímu HTML kódu? Největším problémem těch stránek titiž je, že část jeho obsahu je tvořena hráči samotnými, kteří mají možnost si tam vložit své HTML. |
||
juriad Profil |
#7 · Zasláno: 17. 6. 2016, 11:06:58
Keeehi:
XML parser je něco úplně jiného než HTML parser. HTML parsery pracují stejně jako prohlížeče, znají pravidla HTML i pravidla opravování nevalidního HTML. Výsledkem obou parserů je DOM reprezentace, která nabízí vysokoúrovňové funkce na procházení dokumentu. Pokud je něco deklarováno jako XML a je v tom sebemenší chybička, tak XML parser musí odmítnout zpracovat takový dokument. Pokud na nějaký takový nevalidní XML feed narazíš, kontaktuj jeho autora. |
||
danhill Profil |
#8 · Zasláno: 17. 6. 2016, 16:20:30
S regexy mi to prostě nechodí správně ... je tam mnoho variant a určitě bych ne všechny dokonale odladil a objeví se další a další a já bych se uifoval k smrti ...
Chtěl bych se v tomto případě vrátit ke své původní myšlence a sice hledá v html známý text. Ze všeho co jsem zkusil mi nejlépe chodí tohle a je to až podezřele jednoduché :) : $htmlcache = file_get_contents("http://coord.info/GC19905"); $select_regions = $mysqli->query("SELECT * FROM `region_type` "); foreach ($select_regions as $select_region){ if(preg_match('['.$select_region["region"].']', $htmlcache)) { $region = $select_region["region"]; } } echo 'Kraj :'.$region; Jen bych tedy potřeboval do toho regexu ['.$select_region["region"].'] |
||
juriad Profil |
#9 · Zasláno: 17. 6. 2016, 16:40:21
danhill:
Vyzobnutí si té části jsem ti ukázal v [#2] pomocí navigace v DOMu; Keeehi ti ukázal, jak to udělat pomocí regexů (osobně tomu nevěřím). Nějakými takovými manipulacemi bys měl dostat jen obsah toho divu, ve kterém je ta lokace uvedená. S tímto textem budeš pracovat dále. Kolik regionů máš v databázi? Pokud jsou jich alespoň desítky, tak na toto zapomeň. Musíš si navrhnout něco, co ten region získá, aniž by to vědělo, jaké regiony existují. Pokud všechny lokace jsou popsatelné: In něco, země nebo In země , tak by ti ten regex v [#2] měl fungovat.
Pokud je víc formátů, tak buď můžeš zesložitit regex, nebo zkusit postupně několik regexů s tím, že jeden z nich se chytne. Ještě poznámky k tomu tvému regexu: Hranaté závorky slouží k něčemu jinému; obsah regexu musíš escapovat pomocí preg_quote. |
||
danhill Profil |
#10 · Zasláno: 17. 6. 2016, 17:31:22
No, ono se to řekne :) použij knihovnu ... Ale nerozchodil jsem to ... nevím proč .. teda vím, protože nechápu definici funkce "find" ...
regionů je konkrétně 707 v db a jsou to všechny na světě. Myslíš, že to může vadit, prohledat si to foreachem? Mě to zatím funguje nejspolehlivěji,co jsem zkoušel. jen vyeliminovat ty místa a nemůže se to splést a nemusím požít více než jeden if/else No já takhle sestavený regex používám celkem běžně - s těmi hranatými závorkami,když potřebuji najít někde konkrétní text. A funguje to bezvadně :) Spíše bych ho potřeboval umět rozšířit, jak jsi právě psal. Tedy do něčeho v tomto stylu: 'div[class=minorCacheDetails Clear] div['.$select_region["region"].']div div' - samozřejmě tohle nechodí, protože nevím jak to zapsat.
nebo jak psal Keeehi: '~<div class="minorCacheDetails Clear"> <div> ['.$select_region["region"].'] </div> </div>~' |
||
juriad Profil |
#11 · Zasláno: 17. 6. 2016, 18:03:29
Ok, ty závorky nevadí; nevěděl jsem.
php.net/manual/en/regexp.reference.delimiters.php Zkusil jsem si to a toto funguje: include 'simple_html_dom.php'; $html = file_get_html("http://coord.info/GC19905"); $sekce = (string) $html->find('div.minorCacheDetails div', -1); echo $sekce; Já bych se v případě 700 regionů bál. Schválně si to změř; vezmi si text, který neobsahuje žádný region v databáze a zkus na to spustit svůj skript. Je možné, že to bude dostatečně svižné, je možné, že ne. |
||
Keeehi Profil |
Pro názornost, velmi jednoduchý regulár 3v4l.org/PGScl
Jelikož se mi nelíbí, že je na několik řádků, tak ho upravím 3v4l.org/JKU8e A teď postup, jak takový regulár zkonstruovat. 1) Zkopírujš část HTML, která tě zajímá. <div class="minorCacheDetails Clear"> <div> In Moravskoslezsky kraj, Czech Republic </div> </div> 2) Část která tě zajímá nahradíš (.*?)
<div class="minorCacheDetails Clear"> <div> (.*?) </div> </div> 3) Bílé znaky kterých se chceš zbavit nahradíš \s*
<div class="minorCacheDetails Clear"> <div> (.*?) </div> </div> -------------------- vvvv ------------------ <div class="minorCacheDetails Clear">\s*<div> (.*?) </div> </div> -------------------- vvvv ------------------ <div class="minorCacheDetails Clear">\s*<div> (.*?) </div> </div> -------------------- vvvv ------------------ <div class="minorCacheDetails Clear">\s*<div>\s*(.*?) </div> </div> -------------------- vvvv ------------------ <div class="minorCacheDetails Clear">\s*<div>\s*(.*?) </div> </div> -------------------- vvvv ------------------ <div class="minorCacheDetails Clear">\s*<div>\s*(.*?)\s*</div> </div> -------------------- vvvv ------------------ <div class="minorCacheDetails Clear">\s*<div>\s*(.*?)\s*</div> </div> -------------------- vvvv ------------------ <div class="minorCacheDetails Clear">\s*<div>\s*(.*?)\s*</div>\s*</div> '~minorCacheDetails Clear">\s*<div>\s*(.*?)\s*</~' |
||
Časová prodleva: 9 let
|
0