Best of BlackHat SEO (3) - Generování obsahu (Markov)
13. November 2006
Se zjištěním, že google velice příznivě boduje rozsáhlé weby bylo celkém jasné kam blackhat trendy budou směřovat. V dnešní době je celkem běžné generovat weby, které mají v řádu tisíce unikátních stránek. Osobně mám takový pocit že se už od googlu nějaká opatření konala…ale zatím ne tak markantní na to aby se to nevyplatilo dělat. Osobně teď dělám pokus na několika doménách třetího řádu, protože jak zaznělo poměrně jasně od českého “Matta Cuttse” Seznamu, zatím situace okolo domén třetího řádu není dostatečně vyřešená.
Ale zpět k samotnému generování. Existuje spousta metod jak generovat text. Některé generují věty s náhodným obsahem slov, jiné dokonce generují i ta slova. Statistika je ale v tomhle případě neůprosná a dokáže lehce takové texty vyřadit. Netvrdím, že nějaký (český) vyhledávač počítá výskyt písmenek nebo slov, ale vždy je lepší být trošku napřed než pozadu.
Po celkem dlouhém pátrání co by mi asi tak mohlo vyhovovat a daválo nejsmysluplnější výsledky jsem narazil na Markova. Andrey Markov byl poměrně významný vědec devatenáctého a začátku dvacátého století. Jeho teorie se staly jedním ze základů automatického rozpoznávání řeči, písma a kdo ví čeho ještě dalšího. Kdo má rád matematiku a ještě jí ze školy(ehm…) nezapoměl ať se podívá určitě na referát Skryté Markovovy modely (Hidden Markov Models - HMMs).
Metoda kterou my použijeme se jmenuje Markov Chain…je poměrně dobře popsaná v angličtině na wikipedii ackoliv na muj vkus pomerne slozite. Pro tuto metodu je nutné (!) mít nějaký základní text z čeho se bude statistika (Frequency Table) počítat, proto jsou výsledky víceméně smysluplné a vzhledem odpovídají normálnímu textu protože z něho vycházejí. Zjednodušeně to funguje tak, že zjistíte jaké slovo následuje po předchozí frázi a to se zapíše do tabulky. Když generujeme text tak se po každé frázi podíváme jestli v tabulce neni pro dané spojení víc možností, pokud ano vybereme náhodně. Pokud nechápete tak to pochopíte určitě ze zdrojáků…
Prvním krokem by mělo být vytvoření právě Frequency Table ze stávajícího textu. K tomu nejdříve potřebujeme rozdělit text na slova, originální text bude překvapivě uchován v proměné originalText :) (kompletní třídu pro generování uvedu zase nakonci)
function createWordArray($text = false) {
$text = $this->originalText;
$wordArray = preg_split("/[\s]+/", $text);
$this->wordCount = count($wordArray);
return $wordArray;
}
Tak teď máme z textu vyextrahovaná všechna slova. Výstup z této funkce uložíme v mezikroku do $this->textwords a vrhneme se vygenerování tabulky.
function frequencyTable() {
$loopmax = count($this->textwords) - $this->G + 1;
$frequency_table = array ();
for ($j = 0; $j < $loopmax-1; $j ++) {
$key_string = "";
$end = $j + $this->G;
for ($k = $j; $k < $end; $k ++) {
$key_string .= $this->textwords[$k].' ';
}
if(!isset($frequency_table["$key_string"])) $frequency_table["$key_string"] = '';
// pokud uz fraze existuje prida dalsi slovo za mezeru
$frequency_table["$key_string"] .= $this->textwords[$j + $this->G]." ";
}
$this->frequency_table = $frequency_table;
return true;
}
proměnou $this->G se rozumí granularita, tzn. z kolika slov se bude tvořit položka v jednom poli frekvenční tabulky např. pokud budeme mít granularitu 3 tak jedna položka bude vypadat následovně $frequency_table['Před několika týdny '] => ’spustil’, pokud bude granularita 2 tak bude položka vypadat asi takhle $frequency_table['Před několika '] => ‘týdny’ další bude $frequency_table['několika týdny '] => ’spustil’. Z toho už by mělo být poměrně jasné jak tato proměná bude ovlivňovat výstup.
Generovací fci uvedu bez zbytečností, které zpříjemní výstup ale s metodou nesouvisí.
function generate() {
$buffer = "";
$output = "";
$lastwords = array ();
$frequency_table = $this->frequency_table;
$textwords = $this->textwords;
$O = $this->O;
// zacina se prvnima dvema slovama z textu, pokud to s generovanim
// myslite vazne, bylo by dobre vzit nahodna slova z textu
for ($i = 0; $i < $this->G; $i ++) {
$lastwords[] = $textwords[$i]; // ulozi posledni pouzite slovo
$output .= " ".$textwords[$i];
}
// $O omezuje vystupni pocet slov
for ($i = 0; $i < $O; $i ++) {
// vytvori $key_string ktery se pouzije k rozpoznani dalsiho slova
$key_string = "";
for ($j = 0; $j < $this->G; $j ++) {
$key_string .= $lastwords[$j]." ";
}
// pokud nalezneme key_string v $frequency_table vybereme podle jejich
// poctu nahodne dalsi jedno slovo
if (!empty($frequency_table[$key_string])) {
$possible = explode(" ", trim($frequency_table[$key_string]));
mt_srand();
$c = count($possible);
$r = mt_rand(1, $c) - 1;
$nextword = $possible[$r];
$output .= " $nextword";
// odstrani prvni slovo a prida posledni
for ($l = 0; $l < $this->G -1; $l ++) {
$lastwords[$l] = $lastwords[$l +1];
}
$lastwords[$this->G -1] = $nextword;
}
} // skonci pokud sme v koncich :)
return $output;
}
Z uvedeného kódu by měly být jasné dvě věci. Zaprvé je to metoda velice náročná na pamět i procesor, php je k tomuto účelu zcela nevhodné, ale co už… Druhá věc je že granularita úzce souvisí s velikostí dodaného textu, jak už je z algoritmu patrné. V podstatě čím víc bude mít skript na výběr možností po key_stringu, tím víc možností textu dokáže vygenerovat. Velice jednoduché a účiné. Pokud si to chcete vyzkouštet v praxi můžete na http://markov.blackhats.cz.
Zdrojový kód je na http://markov.blackhats.cz/class.markov.phps , neuvádím ho zde kvůli délce. Ale opravdu doporučuju celý zdroják projít ať trošku pochopíte jak ta třída funguje. Přidal jsem tam oproti originálu ještě funkci obohatit() na obohacení textu odkazy a klíčovými slovy. Jednoduché použití pak může vypadat asi takhle
<?php
include("class.markov.php");
$markov = new Markov;
$markov->inputFile('mobil.cz.txt');
$markov->setG(2); // granularita
$markov->setO(1000); // pocet vystupnich slov
$markov->setParagraph( 4, 6, "<p>"); // min. a max. pocet vet v odstavci a oddelovac odstavcu
$obohaceni = array ( // polozky kterymi se obohati text
'<a href="http://www.radekhulan.cz">Hulán je pako</a>',
'<a href="http://www.radekhulan.cz">Drogy jsou špatné ááááno</a>',
'<a href="http://www.seznam.cz">kiss my binary ass</a>',
'pokazde kdyz masturbujes buh zabije kotatko',
);
$markov->obohatit($obohaceni, 3); // pole, a pocet nahodnych polozek kterymi se text obohati
if ($markov->frequencyTable()) { // vytvorime tabulku z textu, staci pouzit jednou,
// generovat pak muzeme jak je libo
echo $markov->generate(); // generace textu
} else
echo "fcuk<br>";
?>
K tomuhle příkladu stačí dopsat jen pár řádek, vygenerovat tím několik souborů a adresářů, přidat htaccess a máte za pár sekund vygenerováno několik vzájemně prolinkovaných stránek na doménách třetího řádu. Třeba http://mobilni-melodie.blackhats.cz/(odkaz je nofollow tak doufám že mě za to nikdo nezbije:)). Docela sranda :)

15 November, 2006 [10:52 pm]
Nofollow je sice pěkný, ale Seznamu ani Jyxu tuším nepomůže a stejně obsah zaindexují. lepší bude soubor robos.txt, který indexaci zakáže. :)
16 November, 2006 [5:29 am]
no to mi pos… tak doufam ze se to dotkne jenom tech domen co jsou tam generovany a ne ostatnich
19 November, 2006 [10:20 pm]
Doufej, pokud tě admin tým seznamáků objeví, tak že se se zákazem omezí jen na ty vygenerované domény. Pro jistotu na ně vždycky můžeš přidat robots.txt :)
15 January, 2007 [12:27 am]
Tak si představ, že jsem tuto tvoji stránku nalezel skutečně podle toho, že obsahuje odkaz na mobilni-melodie . blackhats . cz. Odkazovat na linkfarmy je samozřejmě taky blackhat. Ale potvrzuju, že tam je rel=”nofollow”, takže se bannu neboj a díky za zajímavý článek.
4 February, 2008 [4:12 pm]
Ahoj,
velice pěkný článek, ale externí odkazy (na blackhats.cz) již neexistují.
Chtělo by to aktualizaci článku.
Pokud máš někde původní zdrojové kódy, tak je prosím nabídní ke stažení.
Děkuji
8 May, 2008 [10:30 pm]
Souhlasím s Marcelem.
Chtělo by to aktualizaci …
A celý ZK nám prosím nabídni ke stažení.
Děkuji