Autor Zpráva
Milkys
Profil
Pěkné odpoledne dámy a pánové,
testuji níže uvedený kod. Měl by vypsat url a popis z vyhledávače seznam.cz.

Je funkční jen do té doby, dokud se v řetězci nevyskytuje zbozi.cz ap. To potom sežere i první url s popisem, která následuje po této upoutávce na zbozi.cz a to je pro mně nežádoucí.

Záměrně jsem řetězec $str nevložil, aby to nebylo nepřehledné. Dá se získat ze zdrojáku ve vyhledávači.

Prosím ví někdo kde dělám chybu?
Předem děkuji.

$str = ''; // zde bude řetězec začínající od první (včetně) <h3> až do konce stránky. Bez sklik reklam. 
$reg = '<h3> <a href="(.*?)".*?>(.*?)</a> </h3> <div class="description.*?>(.*?)</div>';
preg_match_all("~$reg~", $str, $matches);

$urlList = $matches[1];
print_r($urlList); //pro kontrolu vypíše pole adres
Tori
Profil
IMHO by stačilo upravit první tři části v závorkách, aby nehledaly jakýkoli znak, ale jakýkoli znak kromě >.
TomasJ
Profil
Milkys:
Přesně jak píše Tori, ale s malou úpravou. Texty v uvozovkách aby hledaly vše kromě uvozovek a text v DIV jak píše Tori. Mohlo by to fungovat. atribut="([^"]*)" <div>([^>]*)</div>
Další věc je <div class="description".*?>(.*?)</div> vyznačená uvozovka chybí.

EDIT: Přeškrtnuté je to proto, že v description se vyskytuje i tag <b> na vyznačení shodných hledaných výrazů. To znamená, že je potřeba nejdřív všemu v description buď odstranit tagy a nebo převést < a > na entity. (&lt; = < | &gt; = >).
Dalo by se také napsat regulár na vynechání <b></b>.
Milkys
Profil
TomasJ, Tori:
Děkuji Vám oběma. Vyzkouším, reguláry neovládám, učím se, pokus - omyl :).


Takže vážení asi to pěkně kopu. Poslední verze včetně pokusu o odstranění tučných tagů je:
$reg = '<h3> <a href="([^"]*)".*?>([^>]*)</a> </h3> <div class="description.*?">([^<(/?)b>]*)</div>';
Tohle vypíše jen první odkaz...
TomasJ
Profil
Milkys:
To, co je uzavřené v [ ] jsou znaky. Nelze do toho uzavřít celé slovo, protože vše je chápáno jako jednotlivé znaky samostatně na sebe nenavazující.

Doporučuji přečíst si pár článků o regulárech.
Třeba rovnou zde www.root.cz/clanky/regularni-vyrazy-1/ a nebo zde http://www.regularnivyrazy.info/regularni-vyrazy-zaklady.html
Tori
Profil
Milkys:
Zkuste to brát postupně, nejdřív najít všechny odkazy + popisy, až potom popisy odtučňovat. :)
Milkys
Profil
TomasJ:
to mám otevřené a z toho jsem čerpal na tu část na odstranění <b> a </b>. Nicméně mi ty tagy v popisu nevadí. A pokud by mi vadily existuje strip_tags.
Malinko jsem postoupil. Zjistil jsem, že toto vypisuje url i za zbozi.cz, ovšem nezískám popis
$reg = '<h3> <a href="([^"]*)".*?>([^>]*)</a>';

a to umí i ten můj původní kod.
$reg = '<h3> <a href="(.*?)".*?>(.*?)</a>';
Takže nepostoupil...
TomasJ
Profil
Milkys:
Z jaké URL adresy čerpáte výsledky? Abych přesně věděl, co vyzkoušet.

Tak mi to nedalo, zkusil jsem taky něco napsat a následně vyhledat. Funguje to v pohodě.
Problém byl v metaznacích nacházejících se v hledaných hodnotách.
Takže ať se netrápíte:
<?php
function array_stripSlashes($array){
  foreach($array as $i => $data){
    if(is_array($data)) $array[$i] = array_stripSlashes($data);
    else $array[$i] = stripslashes($data);
  }
  return $array;
}

$get = file_get_contents("http://search.seznam.cz/?q=regularni+vyrazy");
$get = preg_quote(substr($get,strpos($get, '<h3> <a href="')));
$lt = '\\\<';
$gt = '\\\>';
$eq = '\\\=';
$reg = "{$lt}h3{$gt} {$lt}a href{$eq}\"([^\"]*)\"[^>]*{$gt}(.*?){$lt}/a{$gt} {$lt}/h3{$gt} {$lt}div class{$eq}\"description\"[^>]*{$gt}(.*?){$lt}/div{$gt}";
preg_match_all("~$reg~",$get,$match);
var_dump(array_stripSlashes($match));
?>
Milkys
Profil
TomasJ:
q=bazény

$str =
řetězec začíná: <h3> <a href="1. pozice odkaz" title="Přejít na: 1. pozice odkaz" data-d.....
a končí: ht"> © 1996–2014 Seznam.cz, a.s. </div> <img src="i.imedia.cz/miss?zoneId=seznam.search.hits&amp;collocation=baz%C3%A9ny&amp;referer=search.seznam.cz&amp;count=1&amp;r=cLuyQ2NIwmrapWi4nPC2" class="blind" alt="" height="1" width="1"> </div>
TomasJ
Profil
Milkys:
Nemůžete odesílat diakritiku. Nejdřív ji projeďte přes urlencode
Mně to funguje úplně normálně. Ale myslím, že bude lepší projet to XML parserem. Nachází se tam totiž pár položek, které mají jinou strukturu.
Milkys
Profil
TomasJ:
děkuji funguje. Už jen ze zdrojáku vycucám url zvlášť a popis zvlášť. To jsou 2 věci, které potřebuji. To už bude brnkačka. Ještě jednou děkuji za ochotu vyřešit problém.
TomasJ
Profil
Milkys:
Pokud používáte výše psaný kód, například na dotaz "regularni vyrazy" vám seznam v prohlížeči vypíše 11 výsledku a v kódu jen 9. Chybí tam položka z interval.cz a matematika.cz (tak nějak to bylo).
Milkys
Profil
TomasJ:
nepoužívám. Zjistil jsem, že jsem v podstatě na začátku. V předešlým příspěvku jsem se nechal unést. Asi jsem to na začátku špatně vysvětlil.

Toto mi vyřízne řetězec, který je podobný tomu Vašemu.

$get = file_get_contents("http://search.seznam.cz/?q=bazény");
$pattern = '<div class="text" id="modText.*?(.*)</div>';
if (preg_match("~$pattern~is", $get, $matches)) {
   if (!empty($matches[1])) {
      $str = $matches[1];
   }
}
echo $str;

S řetězcem $str dále pracuji viz. příspěvek #1

$reg = '<h3> <a href="(.*?)".*?>(.*?)</a> </h3> <div class="description".*?>(.*?)</div>';
preg_match_all("~$reg~", $str, $matches);
 
$urlList = $matches[1]; // $matches[3] jsou popisy
print_r($urlList); //pro kontrolu vypíše pole adres

Toto všechno fachčí, jen mi to vždycky sežere i tu url a popis, která následuje po položkách zbozi.cz. Chápeme se?
TomasJ
Profil
Milkys:
A co takhle upravit $pattern = '<div class="text" id="modText.*?(.*?)</div>';?
To je asi blbost, ukončí se to moc brzo. Dál už jinak nevím, řešil bych to xml parserem.
Milkys
Profil
TomasJ:
? nepomohl.
Nepomohla ani změna $reg:
$reg = '<h3> <a href="([^"]*)"[^>]*>(.*?)</a> </h3> <div class="description"[^>]*>(.*?)</div>';



TomasJ:
nic se neděje, nejde o život :). Třeba se objeví Kajman - ten už mi párkrát vytáh trn z paty nebo někdo podobný. Snaha byla děkuji za ochotu. Každopádně pokud to vyřeším dám to sem. Třeba se to někomu také hodí.


TomasJ:
Zrada je až v proměnné $reg. Do toho místa je vše ok.

Ještě mě napadlo:
zbozi má třídu hint:
<div class="modCont hint zbozi">
Ta se jinde ve výsledcích nevyskytuje. Divy, které "nepatří" seznamu jsou ve tvaru:
<div class="modCont result cr"....

Takže kdyby šlo nějak znegovat class hint. Něco jako:
Pokud je tam class hint tak continue na další nejbližší třídu modCont.
Tori
Profil
S uvedeným vyhledáváním mi fungovalo např. tohle:
$get = file_get_contents("http://search.seznam.cz/?q=bazény");
preg_match_all('~<div class="modCont result .+?</div>\s*<script>\s*JAK\.Fulltext\.ResultScreenshotResize~', $get, $matches);
$results = array();
foreach ($matches[0] as $item) {
    if (preg_match('~<h3>\s*<a href="(.+?)" [^>]+? data-dot="title">(.+?)</a>.+?<div class="description" data-dot="description">(.+?)</div>~', $item, $m)) {
        $results[] = array(
            'url' => $m[1], 
            'title' => html_entity_decode(strip_tags($m[2]), ENT_COMPAT, 'UTF-8'),
            'description' => html_entity_decode(strip_tags(trim($m[2])), ENT_COMPAT, 'UTF-8'),
        );
    }
}
var_dump($results);
Vynechává ty odkazy nahoře na meruňkovém pozadí, zboží.cz, a encyklopedii.

Nicméně taky bych hlasovala pro xml parser. edit: Zkusila jsem to a DOM i XMLReader pohořeli na komentářích pro MSIE. Takže přecijen to asi bude jednodušší regulárem.
TomasJ
Profil
Milkys:
Tak regulár se trošku rozšířil, pořádně jsem koukl na strukturu a je to tak, hint má v class jen zboží a wikipedie.

Na závěr jsem přidal funkci assocArray na poskládání adres k popisům.
Je možno zadat $k1(adresa) a $k2(popis) nebo je vynechat a nastaví se jim defaultně 0 a 1.

Takže tady je výsledek, který už je správný:
<?php
function array_stripslashes($array){
  foreach($array as $i => $data){
    if(is_array($data)) $array[$i] = array_stripSlashes($data);
    else $array[$i] = stripslashes($data);
  }
  return $array;
}

function assocArray($a1,$a2,$k1=0,$k2=1){
  $r_array = Array();
  $ca1 = count($a1);
  $ca2 = count($a2);
  $big_arr = $ca1 > $ca2 ? $ca1 : $ca2;
  for($i=0; $i<$big_arr; $i++){
    if(isset($a1[$i])) $r_array[$i][$k1] = $a1[$i];
    if(isset($a2[$i])) $r_array[$i][$k2] = $a2[$i];
  }
  return $r_array;
}

$get = file_get_contents("http://search.seznam.cz/?q=bazeny");
$get = preg_quote($get);
$lt = "\\\<";
$gt = "\\\>";
$eq = "\\\=";
$reg = "{$lt}div class{$eq}\"modCont result[^\"]*\"[^>]*{$gt}.*?{$lt}div class{$eq}\"text\"[^>]*{$gt} ".
       "{$lt}h3{$gt} {$lt}a href{$eq}\"([^\"]*)\"[^>]*{$gt}.*?{$lt}/a{$gt} {$lt}/h3{$gt} ".
       "{$lt}div class{$eq}\"description\"[^>]*{$gt}(.*?){$lt}/div{$gt}";
preg_match_all("~$reg~",$get,$match);

$match = array_stripslashes($match);
$result = assocArray($match[1],$match[2],"url","popis");

var_dump($result);
?>

Regulár poněkud dlouhý, ale musel jsem hodit quote kvůli tečkám a všelijakým metaznakům v popisech a url.
Je třeba ještě ošetřit, pokud to nenajde nic, nebo nenajde adresy / popisy.

Tori mezitím přidala asi lepší funkci, já se nechal asi moc unést :)


Ještě dodám: Pro parsování zdroje XML parserem je v něm moc bordel. I po vhodném escapování všech entit mi parser psal chybu "not well-formed", takže by tam nejspíš musel zasahovat regulární výraz.
Milkys
Profil
Oběma strašně moc děkuji. Velice rád to oplatím pokud budu mít tu možnost.
Prosím příště nevykat :), nepřipadám si, že bych měl věk na vykání (45). Prosím od všech na foru o tykání. Každý je starý tak jak se cítí a já se cítím jak teenager :).
Tori
To tvé funguje přesně jak potřebuji. Jen kosmetická úprava:
na ř. 9 má být prvek pole 3. Jinak 100 bodov.
TomasJ:
netestoval jsem - nebylo už potřeba.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: