Jak říká XKCD #903, pokud na Wikipedii budete klikat na první odkaz v textu článku, který není v závorkách nebo kurzívou, dříve nebo později se dostanete na článek o filosofii.
Dneska si to ověříme v praxi. Během tohoto ověřování se naučíme používat knihovnu BeautifulSoup a procvičíme si requests.
Předpokládáme základní znalost Pythonu. Měli byste mít počítač s nainstalovaným interpretem jazyka Python ve verzi aspoň 3.6. Pro začátek si také vytvořte nové virtuální prostředí (na kurzu s lektorem můžete použít prostředí z minulé lekce.
Webové stránky jsou super, pokud je čtete v prohlížečí, jako je třeba Firefox nebo Chrome. Občas ale potřebuje vytáhnout nějaké informace, a potom s nimi dále pracovat. Ruční kopírování je moc náročné.
Některé webové služby poskytují API, přes které je možné se k datům dostat v nějakém civilizovaném formátu. Toto bohužel není až tak časté, a obvykle je potřeba data vytáhnout ze samotné stránky, tak jak je určená pro prohlížeče.
Webové stránky jsou napsané v jazyku HTML. Je to značkovací jazyk, kde se míchá text určený pro lidi se značkami (tagy) určenými pro prohlížeč. Tyto tagy definují, jak se má text zobrazovat.
(venv) $ python -m pip install beautifulsoup4 requests
Knihovna beautifulsoup
existuje v několika verzích. My chceme tu poslední,
verzi 4. Protože hodně existujících programů pořád používá starší verzi 3, jsou
pro instalaci stále dostupné obě.
Hodně zjednodušený pohled na knihovnu beautifulsoup
vypadá takto: z textu
reprezentujícího HTML kód můžete vytvořit strukturu, ve které je potom možné
hledat požadované značky a pracovat s nimi.
>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup("<html><body><h1>Ahoj</h1></body></html>")
>>> soup
<html><body><h1>Ahoj</h1></body></html>
>>> soup.name
'[document]'
>>> soup.html.body.h1.text
'Ahoj'
>>>
Vyzkoušíme si nejdřív prohledávání malého dokumentu:
>>> html_doc = """
... <html><head><title>O třech prasátkách</title></head>
... <body>
... <p class="title"><b>O třech prasátkách</b></p>
... <p class="story">Byla nebyla tři prasátka. Postavila si domky ze
... <a href="http://example.com/slama" class="material">slámy</a>,
... <a href="http://example.com/drevo" class="material">dřeva</a> a
... <a href="http://example.com/cihly" class="material">cihel</a>.
... </p>
... <p class="story">...</p>
... </body>
... </html>
... """
>>>
Nejdříve ho zpracujeme. Druhý argument upřesňuje, že se jedná o HTML.
>>> soup = BeautifulSoup(html_doc, "html.parser")
>>>
Přístup přes název tagu už jsme viděli. Dostaneme tak první tag s daným jménem. Můžeme se ale zeptat na všechny.
>>> soup.a
<a class="material" href="http://example.com/slama">slámy</a>
>>> soup.find_all("a")
[<a class="material" href="http://example.com/slama">slámy</a>, <a class="material" href="http://example.com/drevo">dřeva</a>, <a class="material" href="http://example.com/cihly">cihel</a>]
>>>
Můžeme taky zkoumat obsah tagů:
>>> hlavicka = soup.head
>>> hlavicka
<head><title>O třech prasátkách</title></head>
>>> hlavicka.contents
[<title>O třech prasátkách</title>]
>>> titulek = hlavicka.contents[0]
>>> titulek
<title>O třech prasátkách</title>
>>> titulek.contents
['O třech prasátkách']
>>>
Pokud chceme iterovat v cyklu přes všechny věci uvnitř nějakého tagu, je lepší
použít children
než contents
. Ušetříme si tak vytváření seznamu.
Pokud element obsahuje jenom text, můžeme se k němu dostat přes atribut string
:
>>> titulek.string
'O třech prasátkách'
>>>
Ve stromu značek se můžeme pohybovat nejenom dolů, ale i nahoru a do stran.
parent
– nadřazený elementparents
– iterátor, přes který můžeme vylézt až ke kořenovému elementunext_sibling
, previous_sibling
– skok na další nebo předchozí element,
který má stejného rodiče (v reálném dokumentu soused většiny elementů bude
pravděpodobně text plný mezer)Už jsme zmínili metodu find_all
. Podle čeho všecho můžeme vyhledávat? Zatím
jsme viděli vyhledávání podle názvu elementu. Můžeme ale hledat i podle seznamu
elementů, případně podle regulárního výrazu.
Můžeme taky udělat find_all(True)
. Tím dostaneme všechny elementy, ale ne
text.
Taky můžeme hledat podle funkce. Tato funkce dostane jako argument jeden
element, a pokud vrátí True
, element bude považovaný za nalezený.
Jakýkoli pojmenovaný argument bude fungovat jako filtr na atributy elementu.
Často se hodí vyhledávat podle atributu class
, který ale nejde použít pro
argument funkce v Pythonu. Naštěstí class_
se dá použít jako náhrada.
Na tomto místě je asi fajn zmínit, že na scraping neexistuje univerzální návod. Typický vývoj programu vypadá tak, že ho ladíme na datech, dokud se nechová rozumně. První aktualizace stránek ho typicky rozbije a můžeme začít ladit znovu. Je to možná ale jednodušší než se snažit vymyslet něco dokonalého.
Jak to bude celé fungovat: budeme postupně stahovat stránky z Wikipedie. Začneme náhodnou stránkou. Na každé stránce najdeme první vhodný odkaz a budeme na něj pokračovat. Program skončí, až se znovu dostane na stránku, kde už byl, nebo pokud nenajde žádný pěkný odkaz.
Není ale úplně dobrý nápad napsat velký program na první pokus. Budeme postupně přidávat malé kousky funkcionality, abychom mohli pořád opakovaně testovat, že všechno dělá to, co má.
Začneme jednoduchou kostrou, kde si v komentářích vyznačíme, co se bude dít.
URL = "https://en.wikipedia.org"
START = "/wiki/Special:Random"
def stahuj(stranka):
while True:
# 1. Stáhni stránku
# 2. Napiš titulek
# 3. Vytáhni další odkaz
break
if __name__ == "__main__":
stahuj(START)
První úkol: nahraďte první komentář kódem, který stáhne stránku, zkontroluje
připadné chyby a vypíše text odpovědi od serveru. Adresu stránky ke stažení
dostanete spojením proměnných URL
a stranka
.
Očekávané chování po tomto kroku: program vypíše dlouhý kus HTML kódu a skončí. Při každém běhu bude výstup jiný (pracujeme s náhodnou stránkou).
Úkol: doplňte tělo funkce najdi_titulek()
a upravte funkci stahuj()
tak,
aby místo celé stránky vypsala jenom titulek stránky.
def najdi_titulek(html):
"""Najde titulek v HTML kódu. Titulek je v elementu s identifikátorem
`firstHeading`. Budeme předpokládat, že tento element vždycky existuje.
Funkce vrátí titulek jako řetězec.
"""
Očekávané chování: program vypíše titulek náhodné stránky a skončí.
V dalším kroku konečně budeme hledat odkaz na další stránku. K tomu vytvoříme
ještě jednu funkci: najdi_odkaz()
. Ta bude velmi podobná funkci
najdi_titulek()
.
Volání BeautifulSoup()
je pomerně náročný výpočet, a asi ho nechceme dělat
dvakrát.
Úkoly:
stahuj()
, a do najdi_titulek()
se předala jako argument.najdi_odkaz()
. Bude mít stejný argument jako
najdi_titulek()
. Prozatím bude vždycky vracet None
.najdi_odkaz()
do stahuj()
. Vrácený odkaz uložte do
proměnné stranka
.break
jenom tehdy, když stranka
je None
while
cyklu přidejte volání time.sleep(1)
. Nezapomeňte
naimportovat modul time
.time.sleep(1)
náš program zastaví na 1 sekundu po zpracování každé stránky.
Chceme si totiž procvičit programování, ne zbytečně vytěžovat cizí servery.
Očekávané chování: žádná změna oproti předchozímu kroku.
class
s hodnotou
mw-parser-output
. To je box s hlavním textem článku.p
) v tomto elementu.a
) v tomto odstavci:href
a vrátíme ji. Tady se bude
hodit metoda get()
.Očekávané chování: program vytiskne titulek náhodné stránky, první odstavec na ní, potom první odkaz v tomto odstavci. Pak vytiskne další nadpis, odstavec, odkaz a tak dále. Nikdy neskončí. Ukončit ho bude třeba ručně klávesovou zkratkou Ctrl-C.
Úkol: zajistíme, aby program někdy skončil. Pokud se dostaneme na stránku, kde už jsme byli, můžeme skončit.
stahuj()
si vytvořte proměnnou navstivene
. Začne
jako prázdná množina (set()
).while
cyklu zkontrolujte, jestli stranka
je v
navštívených. Pokud ano, ukončete cyklus.Očekávané chování: program bude vypisovat spoustu textu jako předtím, ale časem by měl skončit. Pořád začíná na náhodné stránce, takže to někdy může chvilku trvat.
Úkol: teď odstraníme text v závorkách. Začneme pomocnou funkci
odstran_zavorky()
, která by se měla chovat podle přiloženého dokumentačního
komentáře.
Zavolejte tuto funkci v najdi_odkaz()
. Jako argument jí dáte odstavec
převedený na řetězec (pomocí str(odstavec)
). Vrácený výsledek vypíšete hned
potom, co se vypisuje odstavec.
Očekávané chování: stejné jako dřív, akorát odstavec bude vypsaný vždy dvakrát. Poprvé tak, jak se nachází na stránce. Podruhé bez ozávorkovaných částí.
Vzhledem k tomu, že v tomto kroku akorát pracujeme s řetězci, můžete ho přeskočit a rovnou se podívat na řešení. Ale je to relativně zajímavý problém.
def odstran_zavorky(text):
"""Odstraní uzávorkované výrazy z textu. HTML elementy mimo závorky budou
zachované. Funkce předpokládá, že každá otevírací závorka má i uzavírací
závorku, a že závorky a HTML elementy se nekříží.
>>> odstran_zavorky("Ahoj (nazdar)!")
'Ahoj !'
>>> odstran_zavorky("<b>Ahoj</b>")
'<b>Ahoj</b>'
>>> odstran_zavorky("A (<i>písmeno</i>) B")
'A B'
>>> odstran_zavorky("a (b (c) d) e")
'a e'
"""
Úkol: Místo vypisování odstavce bez závorek ho znovu převeďte na značkovou polévku. Odkazy hledejte v ní. Teď už je na čase odstranit vypisování odstavce i odkazu.
Očekávané chování: program bude vypisovat titulky stránek a následovat odkazy na nich. Až dojde na stránku, kde už byl (nebo kde není žádný odkaz), tak skončí.
Úkol: Někdy první odkaz nevede na jinou stránku (typicky odkazy na zdroje
uvedené na konci stránky). Upravte funkci najdi_odkaz()
tak, aby vracela
adresu stránky jenom tehdy, pokud ta vracená hodnota začíná řetězecem /wiki/
.
Očekávané chování: program se bude chovat stejně jako dřív, ale bude trochu chytřejší v hledání správného odkazu.
Na anglické wikipedii by tento program měl poměrně spolehlivě dojít na stránku Philosophy. Pokud to zkusíte s českou verzí, až tak slavné to není. Ale i tam jsou výsledky relativně zajímavé.
{ "data": { "sessionMaterial": { "id": "session-material:2019/brno-jaro-knihovny:scraping:0", "title": "Web Scraping", "html": "\n \n \n\n <h1>Web Scraping</h1>\n<h2>Co je cílem tohoto cvičení?</h2>\n<p>Jak říká <a href=\"https://xkcd.com/903/\">XKCD #903</a>, pokud na Wikipedii budete klikat\nna první odkaz v textu článku, který není v závorkách nebo kurzívou, dříve nebo\npozději se dostanete na článek o filosofii.</p>\n<p>Dneska si to ověříme v praxi. Během tohoto ověřování se naučíme používat\nknihovnu <a href=\"https://www.crummy.com/software/BeautifulSoup/\">BeautifulSoup</a> a\nprocvičíme si <a href=\"http://docs.python-requests.org/en/master/\">requests</a>.</p>\n<h2>Předpoklady</h2>\n<p>Předpokládáme základní znalost Pythonu. Měli byste mít počítač s nainstalovaným\ninterpretem jazyka Python ve verzi aspoň 3.6. Pro začátek si také vytvořte nové\nvirtuální prostředí (na kurzu s lektorem můžete použít prostředí z <a href=\"/2019/brno-jaro-knihovny/beginners/kurzovni-listek/\">minulé\nlekce</a>.</p>\n<h2>Teorie do začátku</h2>\n<p>Webové stránky jsou super, pokud je čtete v prohlížečí, jako je třeba Firefox\nnebo Chrome. Občas ale potřebuje vytáhnout nějaké informace, a potom s nimi\ndále pracovat. Ruční kopírování je moc náročné.</p>\n<p>Některé webové služby poskytují API, přes které je možné se k datům dostat v\nnějakém civilizovaném formátu. Toto bohužel není až tak časté, a obvykle je\npotřeba data vytáhnout ze samotné stránky, tak jak je určená pro prohlížeče.</p>\n<p>Webové stránky jsou napsané v jazyku HTML. Je to značkovací jazyk, kde se míchá\ntext určený pro lidi se značkami (<em>tagy</em>) určenými pro prohlížeč. Tyto <em>tagy</em>\ndefinují, jak se má text zobrazovat.</p>\n<h2>Instalace</h2>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">(venv) $ </span>python -m pip install beautifulsoup4 requests\n</pre></div><p>Knihovna <code>beautifulsoup</code> existuje v několika verzích. My chceme tu poslední,\nverzi 4. Protože hodně existujících programů pořád používá starší verzi 3, jsou\npro instalaci stále dostupné obě.</p>\n<h2>Použití</h2>\n<p>Hodně zjednodušený pohled na knihovnu <code>beautifulsoup</code> vypadá takto: z textu\nreprezentujícího HTML kód můžete vytvořit strukturu, ve které je potom možné\nhledat požadované značky a pracovat s nimi.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"kn\">from</span> <span class=\"nn\">bs4</span> <span class=\"kn\">import</span> <span class=\"n\">BeautifulSoup</span>\n<span class=\"gp\">>>> </span><span class=\"n\">soup</span> <span class=\"o\">=</span> <span class=\"n\">BeautifulSoup</span><span class=\"p\">(</span><span class=\"s2\">"<html><body><h1>Ahoj</h1></body></html>"</span><span class=\"p\">)</span>\n<span class=\"gp\">>>> </span><span class=\"n\">soup</span>\n<span class=\"go\"><html><body><h1>Ahoj</h1></body></html></span>\n<span class=\"gp\">>>> </span><span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">name</span>\n<span class=\"go\">'[document]'</span>\n<span class=\"gp\">>>> </span><span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">html</span><span class=\"o\">.</span><span class=\"n\">body</span><span class=\"o\">.</span><span class=\"n\">h1</span><span class=\"o\">.</span><span class=\"n\">text</span>\n<span class=\"go\">'Ahoj'</span>\n<span class=\"go\">>>></span>\n</pre></div><p>Vyzkoušíme si nejdřív prohledávání malého dokumentu:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">html_doc</span> <span class=\"o\">=</span> <span class=\"s2\">"""</span>\n<span class=\"gp\">... </span><span class=\"s2\"><html><head><title>O třech prasátkách</title></head></span>\n<span class=\"gp\">... </span><span class=\"s2\"><body></span>\n<span class=\"gp\">... </span><span class=\"s2\"><p class="title"><b>O třech prasátkách</b></p></span>\n<span class=\"gp\">... </span><span class=\"s2\"><p class="story">Byla nebyla tři prasátka. Postavila si domky ze</span>\n<span class=\"gp\">... </span><span class=\"s2\"><a href="http://example.com/slama" class="material">slámy</a>,</span>\n<span class=\"gp\">... </span><span class=\"s2\"><a href="http://example.com/drevo" class="material">dřeva</a> a</span>\n<span class=\"gp\">... </span><span class=\"s2\"><a href="http://example.com/cihly" class="material">cihel</a>.</span>\n<span class=\"gp\">... </span><span class=\"s2\"></p></span>\n<span class=\"gp\">... </span><span class=\"s2\"><p class="story">...</p></span>\n<span class=\"gp\">... </span><span class=\"s2\"></body></span>\n<span class=\"gp\">... </span><span class=\"s2\"></html></span>\n<span class=\"gp\">... </span><span class=\"s2\">"""</span>\n<span class=\"go\">>>></span>\n</pre></div><p>Nejdříve ho zpracujeme. Druhý argument upřesňuje, že se jedná o HTML.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">soup</span> <span class=\"o\">=</span> <span class=\"n\">BeautifulSoup</span><span class=\"p\">(</span><span class=\"n\">html_doc</span><span class=\"p\">,</span> <span class=\"s2\">"html.parser"</span><span class=\"p\">)</span>\n<span class=\"go\">>>></span>\n</pre></div><p>Přístup přes název tagu už jsme viděli. Dostaneme tak první tag s daným jménem.\nMůžeme se ale zeptat na všechny.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">a</span>\n<span class=\"go\"><a class="material" href="http://example.com/slama">slámy</a></span>\n<span class=\"gp\">>>> </span><span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find_all</span><span class=\"p\">(</span><span class=\"s2\">"a"</span><span class=\"p\">)</span>\n<span class=\"go\">[<a class="material" href="http://example.com/slama">slámy</a>, <a class="material" href="http://example.com/drevo">dřeva</a>, <a class="material" href="http://example.com/cihly">cihel</a>]</span>\n<span class=\"go\">>>></span>\n</pre></div><p>Můžeme taky zkoumat obsah tagů:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">hlavicka</span> <span class=\"o\">=</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">head</span>\n<span class=\"gp\">>>> </span><span class=\"n\">hlavicka</span>\n<span class=\"go\"><head><title>O třech prasátkách</title></head></span>\n<span class=\"gp\">>>> </span><span class=\"n\">hlavicka</span><span class=\"o\">.</span><span class=\"n\">contents</span>\n<span class=\"go\">[<title>O třech prasátkách</title>]</span>\n<span class=\"gp\">>>> </span><span class=\"n\">titulek</span> <span class=\"o\">=</span> <span class=\"n\">hlavicka</span><span class=\"o\">.</span><span class=\"n\">contents</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n<span class=\"gp\">>>> </span><span class=\"n\">titulek</span>\n<span class=\"go\"><title>O třech prasátkách</title></span>\n<span class=\"gp\">>>> </span><span class=\"n\">titulek</span><span class=\"o\">.</span><span class=\"n\">contents</span>\n<span class=\"go\">['O třech prasátkách']</span>\n<span class=\"go\">>>></span>\n</pre></div><p>Pokud chceme iterovat v cyklu přes všechny věci uvnitř nějakého tagu, je lepší\npoužít <code>children</code> než <code>contents</code>. Ušetříme si tak vytváření seznamu.</p>\n<p>Pokud element obsahuje jenom text, můžeme se k němu dostat přes atribut <code>string</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </span><span class=\"n\">titulek</span><span class=\"o\">.</span><span class=\"n\">string</span>\n<span class=\"go\">'O třech prasátkách'</span>\n<span class=\"go\">>>></span>\n</pre></div><p>Ve stromu značek se můžeme pohybovat nejenom dolů, ale i nahoru a do stran.</p>\n<ul>\n<li><code>parent</code> – nadřazený element</li>\n<li><code>parents</code> – iterátor, přes který můžeme vylézt až ke kořenovému elementu</li>\n<li><code>next_sibling</code>, <code>previous_sibling</code> – skok na další nebo předchozí element,\nkterý má stejného rodiče (v reálném dokumentu soused většiny elementů bude\npravděpodobně text plný mezer)</li>\n</ul>\n<h3>Vyhledávání</h3>\n<p>Už jsme zmínili metodu <code>find_all</code>. Podle čeho všecho můžeme vyhledávat? Zatím\njsme viděli vyhledávání podle názvu elementu. Můžeme ale hledat i podle seznamu\nelementů, případně podle regulárního výrazu.</p>\n<p>Můžeme taky udělat <code>find_all(True)</code>. Tím dostaneme všechny elementy, ale ne\ntext.</p>\n<p>Taky můžeme hledat podle funkce. Tato funkce dostane jako argument jeden\nelement, a pokud vrátí <code>True</code>, element bude považovaný za nalezený.</p>\n<p>Jakýkoli pojmenovaný argument bude fungovat jako filtr na atributy elementu.\nČasto se hodí vyhledávat podle atributu <code>class</code>, který ale nejde použít pro\nargument funkce v Pythonu. Naštěstí <code>class_</code> se dá použít jako náhrada.</p>\n<h2>Nepraktický příklad z neživota</h2>\n<div class=\"admonition note\"><p>Na tomto místě je asi fajn zmínit, že na <em>scraping</em> neexistuje univerzální\nnávod. Typický vývoj programu vypadá tak, že ho ladíme na datech, dokud se\nnechová rozumně. První aktualizace stránek ho typicky rozbije a můžeme začít\nladit znovu. Je to možná ale jednodušší než se snažit vymyslet něco\ndokonalého.</p>\n</div><p>Jak to bude celé fungovat: budeme postupně stahovat stránky z Wikipedie.\nZačneme náhodnou stránkou. Na každé stránce najdeme první vhodný odkaz a\nbudeme na něj pokračovat. Program skončí, až se znovu dostane na stránku, kde\nuž byl, nebo pokud nenajde žádný pěkný odkaz.</p>\n<p>Není ale úplně dobrý nápad napsat velký program na první pokus. Budeme postupně\npřidávat malé kousky funkcionality, abychom mohli pořád opakovaně testovat, že\nvšechno dělá to, co má.</p>\n<h3>Krok 1 – kostra programu</h3>\n<p>Začneme jednoduchou kostrou, kde si v komentářích vyznačíme, co se bude dít.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"s2\">"https://en.wikipedia.org"</span>\n<span class=\"n\">START</span> <span class=\"o\">=</span> <span class=\"s2\">"/wiki/Special:Random"</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">stahuj</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">):</span>\n <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n <span class=\"c1\"># 1. Stáhni stránku</span>\n <span class=\"c1\"># 2. Napiš titulek</span>\n <span class=\"c1\"># 3. Vytáhni další odkaz</span>\n <span class=\"k\">break</span>\n\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s2\">"__main__"</span><span class=\"p\">:</span>\n <span class=\"n\">stahuj</span><span class=\"p\">(</span><span class=\"n\">START</span><span class=\"p\">)</span>\n</pre></div><h3>Krok 2 – stažení stránky</h3>\n<p>První úkol: nahraďte první komentář kódem, který stáhne stránku, zkontroluje\npřipadné chyby a vypíše text odpovědi od serveru. Adresu stránky ke stažení\ndostanete spojením proměnných <code>URL</code> a <code>stranka</code>.</p>\n<p>Očekávané chování po tomto kroku: program vypíše dlouhý kus HTML kódu a skončí.\nPři každém běhu bude výstup jiný (pracujeme s náhodnou stránkou).</p>\n<div class=\"solution\" id=\"solution-0\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/brno-jaro-knihovny/beginners/scraping/index/solutions/0/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n\n\n<span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"s2\">"https://en.wikipedia.org"</span>\n<span class=\"n\">START</span> <span class=\"o\">=</span> <span class=\"s2\">"/wiki/Special:Random"</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">stahuj</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">):</span>\n <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n <span class=\"n\">odpoved</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">URL</span> <span class=\"o\">+</span> <span class=\"n\">stranka</span><span class=\"p\">)</span>\n <span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">raise_for_status</span><span class=\"p\">()</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">)</span>\n <span class=\"c1\"># 2. Napiš titulek</span>\n <span class=\"c1\"># 3. Vytáhni další odkaz</span>\n <span class=\"k\">break</span>\n\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s2\">"__main__"</span><span class=\"p\">:</span>\n <span class=\"n\">stahuj</span><span class=\"p\">(</span><span class=\"n\">START</span><span class=\"p\">)</span>\n</pre></div>\n </div>\n</div><h3>Krok 3 – hledání titulku</h3>\n<p>Úkol: doplňte tělo funkce <code>najdi_titulek()</code> a upravte funkci <code>stahuj()</code> tak,\naby místo celé stránky vypsala jenom titulek stránky.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">html</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Najde titulek v HTML kódu. Titulek je v elementu s identifikátorem</span>\n<span class=\"sd\"> `firstHeading`. Budeme předpokládat, že tento element vždycky existuje.</span>\n\n<span class=\"sd\"> Funkce vrátí titulek jako řetězec.</span>\n<span class=\"sd\"> """</span>\n</pre></div><p>Očekávané chování: program vypíše titulek náhodné stránky a skončí.</p>\n<div class=\"solution\" id=\"solution-1\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/brno-jaro-knihovny/beginners/scraping/index/solutions/1/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">from</span> <span class=\"nn\">bs4</span> <span class=\"kn\">import</span> <span class=\"n\">BeautifulSoup</span>\n\n\n<span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"s2\">"https://en.wikipedia.org"</span>\n<span class=\"n\">START</span> <span class=\"o\">=</span> <span class=\"s2\">"/wiki/Special:Random"</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">html</span><span class=\"p\">):</span>\n <span class=\"n\">soup</span> <span class=\"o\">=</span> <span class=\"n\">BeautifulSoup</span><span class=\"p\">(</span><span class=\"n\">html</span><span class=\"p\">,</span> <span class=\"s2\">"html.parser"</span><span class=\"p\">)</span>\n <span class=\"k\">return</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"nb\">id</span><span class=\"o\">=</span><span class=\"s2\">"firstHeading"</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">text</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">stahuj</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">):</span>\n <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n <span class=\"n\">odpoved</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">URL</span> <span class=\"o\">+</span> <span class=\"n\">stranka</span><span class=\"p\">)</span>\n <span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">raise_for_status</span><span class=\"p\">()</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">))</span>\n <span class=\"c1\"># 3. Vytáhni další odkaz</span>\n <span class=\"k\">break</span>\n\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s2\">"__main__"</span><span class=\"p\">:</span>\n <span class=\"n\">stahuj</span><span class=\"p\">(</span><span class=\"n\">START</span><span class=\"p\">)</span>\n</pre></div>\n </div>\n</div><h3>Krok 4 – úklid před další funkcionalitou</h3>\n<p>V dalším kroku konečně budeme hledat odkaz na další stránku. K tomu vytvoříme\nještě jednu funkci: <code>najdi_odkaz()</code>. Ta bude velmi podobná funkci\n<code>najdi_titulek()</code>.</p>\n<p>Volání <code>BeautifulSoup()</code> je pomerně náročný výpočet, a asi ho nechceme dělat\ndvakrát.</p>\n<p>Úkoly:</p>\n<ol>\n<li>Upravte program tak, aby se polévka elementů vytvořila už ve funkci\n<code>stahuj()</code>, a do <code>najdi_titulek()</code> se předala jako argument.</li>\n<li>Vytvořte funkci <code>najdi_odkaz()</code>. Bude mít stejný argument jako\n<code>najdi_titulek()</code>. Prozatím bude vždycky vracet <code>None</code>.</li>\n<li>Přidejte volání <code>najdi_odkaz()</code> do <code>stahuj()</code>. Vrácený odkaz uložte do\n proměnné <code>stranka</code>.</li>\n<li>Zavolejte <code>break</code> jenom tehdy, když <code>stranka</code> je <code>None</code></li>\n<li>Na konec <code>while</code> cyklu přidejte volání <code>time.sleep(1)</code>. Nezapomeňte\n naimportovat modul <code>time</code>.</li>\n</ol>\n<div class=\"admonition note\"><p><code>time.sleep(1)</code> náš program zastaví na 1 sekundu po zpracování každé stránky.\nChceme si totiž procvičit programování, ne zbytečně vytěžovat cizí servery.</p>\n</div><p>Očekávané chování: žádná změna oproti předchozímu kroku.</p>\n<div class=\"solution\" id=\"solution-2\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/brno-jaro-knihovny/beginners/scraping/index/solutions/2/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">time</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">from</span> <span class=\"nn\">bs4</span> <span class=\"kn\">import</span> <span class=\"n\">BeautifulSoup</span>\n\n\n<span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"s2\">"https://en.wikipedia.org"</span>\n<span class=\"n\">START</span> <span class=\"o\">=</span> <span class=\"s2\">"/wiki/Special:Random"</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">):</span>\n <span class=\"k\">return</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"nb\">id</span><span class=\"o\">=</span><span class=\"s2\">"firstHeading"</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">text</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_odkaz</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">):</span>\n <span class=\"k\">pass</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">stahuj</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">):</span>\n <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n <span class=\"n\">odpoved</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">URL</span> <span class=\"o\">+</span> <span class=\"n\">stranka</span><span class=\"p\">)</span>\n <span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">raise_for_status</span><span class=\"p\">()</span>\n\n <span class=\"n\">soup</span> <span class=\"o\">=</span> <span class=\"n\">BeautifulSoup</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"s2\">"html.parser"</span><span class=\"p\">)</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">))</span>\n\n <span class=\"n\">stranka</span> <span class=\"o\">=</span> <span class=\"n\">najdi_odkaz</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">)</span>\n <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">stranka</span><span class=\"p\">:</span>\n <span class=\"k\">break</span>\n\n <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s2\">"__main__"</span><span class=\"p\">:</span>\n <span class=\"n\">stahuj</span><span class=\"p\">(</span><span class=\"n\">START</span><span class=\"p\">)</span>\n</pre></div>\n </div>\n</div><h3>Krok 5 – hledání odkazů</h3>\n<ol>\n<li>Nejdříve na stránce najdeme element s atributem <code>class</code> s hodnotou\n<code>mw-parser-output</code>. To je box s hlavním textem článku.</li>\n<li>V cyklu projdeme přes každý odstavec (<code>p</code>) v tomto elementu.</li>\n<li>Vytiskneme odstavec.</li>\n<li>Pro každý odkaz (<code>a</code>) v tomto odstavci:</li>\n<li>vytiskneme tento odkaz,</li>\n<li>a vytáhneme z odkazu hodnotu atributu <code>href</code> a vrátíme ji. Tady se bude\nhodit metoda <code>get()</code>.</li>\n</ol>\n<p>Očekávané chování: program vytiskne titulek náhodné stránky, první odstavec na\nní, potom první odkaz v tomto odstavci. Pak vytiskne další nadpis, odstavec,\nodkaz a tak dále. Nikdy neskončí. Ukončit ho bude třeba ručně klávesovou\nzkratkou Ctrl-C.</p>\n<div class=\"solution\" id=\"solution-3\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/brno-jaro-knihovny/beginners/scraping/index/solutions/3/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">time</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">from</span> <span class=\"nn\">bs4</span> <span class=\"kn\">import</span> <span class=\"n\">BeautifulSoup</span>\n\n\n<span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"s2\">"https://en.wikipedia.org"</span>\n<span class=\"n\">START</span> <span class=\"o\">=</span> <span class=\"s2\">"/wiki/Special:Random"</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">):</span>\n <span class=\"k\">return</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"nb\">id</span><span class=\"o\">=</span><span class=\"s2\">"firstHeading"</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">text</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_odkaz</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">):</span>\n <span class=\"n\">hlavni_text</span> <span class=\"o\">=</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"n\">class_</span><span class=\"o\">=</span><span class=\"s2\">"mw-parser-output"</span><span class=\"p\">)</span>\n <span class=\"k\">for</span> <span class=\"n\">odstavec</span> <span class=\"ow\">in</span> <span class=\"n\">hlavni_text</span><span class=\"o\">.</span><span class=\"n\">find_all</span><span class=\"p\">(</span><span class=\"s2\">"p"</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">odstavec</span><span class=\"p\">)</span>\n <span class=\"k\">for</span> <span class=\"n\">odkaz</span> <span class=\"ow\">in</span> <span class=\"n\">odstavec</span><span class=\"o\">.</span><span class=\"n\">find_all</span><span class=\"p\">(</span><span class=\"s2\">"a"</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">odkaz</span><span class=\"p\">)</span>\n <span class=\"k\">return</span> <span class=\"n\">odkaz</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">"href"</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">stahuj</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">):</span>\n <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n <span class=\"n\">odpoved</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">URL</span> <span class=\"o\">+</span> <span class=\"n\">stranka</span><span class=\"p\">)</span>\n <span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">raise_for_status</span><span class=\"p\">()</span>\n\n <span class=\"n\">soup</span> <span class=\"o\">=</span> <span class=\"n\">BeautifulSoup</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"s2\">"html.parser"</span><span class=\"p\">)</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">))</span>\n\n <span class=\"n\">stranka</span> <span class=\"o\">=</span> <span class=\"n\">najdi_odkaz</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">)</span>\n <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">stranka</span><span class=\"p\">:</span>\n <span class=\"k\">break</span>\n\n <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s2\">"__main__"</span><span class=\"p\">:</span>\n <span class=\"n\">stahuj</span><span class=\"p\">(</span><span class=\"n\">START</span><span class=\"p\">)</span>\n</pre></div>\n </div>\n</div><h3>Krok 6 – ukončení programu</h3>\n<p>Úkol: zajistíme, aby program někdy skončil. Pokud se dostaneme na stránku, kde\nuž jsme byli, můžeme skončit.</p>\n<ol>\n<li>Na začátku funkce <code>stahuj()</code> si vytvořte proměnnou <code>navstivene</code>. Začne\njako prázdná množina (<code>set()</code>).</li>\n<li>Jako první věc uvnitř <code>while</code> cyklu zkontrolujte, jestli <code>stranka</code> je v\nnavštívených. Pokud ano, ukončete cyklus.</li>\n<li>Přidejte stránku mezi navštívené.</li>\n</ol>\n<p>Očekávané chování: program bude vypisovat spoustu textu jako předtím, ale\nčasem by měl skončit. Pořád začíná na náhodné stránce, takže to někdy může\nchvilku trvat.</p>\n<div class=\"solution\" id=\"solution-4\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/brno-jaro-knihovny/beginners/scraping/index/solutions/4/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">time</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">from</span> <span class=\"nn\">bs4</span> <span class=\"kn\">import</span> <span class=\"n\">BeautifulSoup</span>\n\n\n<span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"s2\">"https://en.wikipedia.org"</span>\n<span class=\"n\">START</span> <span class=\"o\">=</span> <span class=\"s2\">"/wiki/Special:Random"</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">):</span>\n <span class=\"k\">return</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"nb\">id</span><span class=\"o\">=</span><span class=\"s2\">"firstHeading"</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">text</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_odkaz</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">):</span>\n <span class=\"n\">hlavni_text</span> <span class=\"o\">=</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"n\">class_</span><span class=\"o\">=</span><span class=\"s2\">"mw-parser-output"</span><span class=\"p\">)</span>\n <span class=\"k\">for</span> <span class=\"n\">odstavec</span> <span class=\"ow\">in</span> <span class=\"n\">hlavni_text</span><span class=\"o\">.</span><span class=\"n\">find_all</span><span class=\"p\">(</span><span class=\"s2\">"p"</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">odstavec</span><span class=\"p\">)</span>\n <span class=\"k\">for</span> <span class=\"n\">odkaz</span> <span class=\"ow\">in</span> <span class=\"n\">odstavec</span><span class=\"o\">.</span><span class=\"n\">find_all</span><span class=\"p\">(</span><span class=\"s2\">"a"</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">odkaz</span><span class=\"p\">)</span>\n <span class=\"k\">return</span> <span class=\"n\">odkaz</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">"href"</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">stahuj</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">):</span>\n <span class=\"n\">navstivene</span> <span class=\"o\">=</span> <span class=\"nb\">set</span><span class=\"p\">()</span>\n <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n <span class=\"k\">if</span> <span class=\"n\">stranka</span> <span class=\"ow\">in</span> <span class=\"n\">navstivene</span><span class=\"p\">:</span>\n <span class=\"k\">break</span>\n <span class=\"n\">navstivene</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">)</span>\n\n <span class=\"n\">odpoved</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">URL</span> <span class=\"o\">+</span> <span class=\"n\">stranka</span><span class=\"p\">)</span>\n <span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">raise_for_status</span><span class=\"p\">()</span>\n\n <span class=\"n\">soup</span> <span class=\"o\">=</span> <span class=\"n\">BeautifulSoup</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"s2\">"html.parser"</span><span class=\"p\">)</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">))</span>\n\n <span class=\"n\">stranka</span> <span class=\"o\">=</span> <span class=\"n\">najdi_odkaz</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">)</span>\n <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">stranka</span><span class=\"p\">:</span>\n <span class=\"k\">break</span>\n\n <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s2\">"__main__"</span><span class=\"p\">:</span>\n <span class=\"n\">stahuj</span><span class=\"p\">(</span><span class=\"n\">START</span><span class=\"p\">)</span>\n</pre></div>\n </div>\n</div><h3>Krok 7 – odstranění textu v závorkách</h3>\n<p>Úkol: teď odstraníme text v závorkách. Začneme pomocnou funkci\n<code>odstran_zavorky()</code>, která by se měla chovat podle přiloženého dokumentačního\nkomentáře.</p>\n<p>Zavolejte tuto funkci v <code>najdi_odkaz()</code>. Jako argument jí dáte odstavec\npřevedený na řetězec (pomocí <code>str(odstavec)</code>). Vrácený výsledek vypíšete hned\npotom, co se vypisuje odstavec.</p>\n<p>Očekávané chování: stejné jako dřív, akorát odstavec bude vypsaný vždy dvakrát.\nPoprvé tak, jak se nachází na stránce. Podruhé bez ozávorkovaných částí.</p>\n<div class=\"admonition note\"><p>Vzhledem k tomu, že v tomto kroku akorát pracujeme s řetězci, můžete ho\npřeskočit a rovnou se podívat na řešení. Ale je to relativně zajímavý\nproblém.</p>\n</div><div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">odstran_zavorky</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">):</span>\n <span class=\"sd\">"""Odstraní uzávorkované výrazy z textu. HTML elementy mimo závorky budou</span>\n<span class=\"sd\"> zachované. Funkce předpokládá, že každá otevírací závorka má i uzavírací</span>\n<span class=\"sd\"> závorku, a že závorky a HTML elementy se nekříží.</span>\n\n<span class=\"sd\"> >>> odstran_zavorky("Ahoj (nazdar)!")</span>\n<span class=\"sd\"> 'Ahoj !'</span>\n<span class=\"sd\"> >>> odstran_zavorky("<b>Ahoj</b>")</span>\n<span class=\"sd\"> '<b>Ahoj</b>'</span>\n<span class=\"sd\"> >>> odstran_zavorky("A (<i>písmeno</i>) B")</span>\n<span class=\"sd\"> 'A B'</span>\n<span class=\"sd\"> >>> odstran_zavorky("a (b (c) d) e")</span>\n<span class=\"sd\"> 'a e'</span>\n<span class=\"sd\"> """</span>\n</pre></div><div class=\"solution\" id=\"solution-5\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/brno-jaro-knihovny/beginners/scraping/index/solutions/5/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">time</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">from</span> <span class=\"nn\">bs4</span> <span class=\"kn\">import</span> <span class=\"n\">BeautifulSoup</span>\n\n\n<span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"s2\">"https://en.wikipedia.org"</span>\n<span class=\"n\">START</span> <span class=\"o\">=</span> <span class=\"s2\">"/wiki/Special:Random"</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">odstran_zavorky</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">):</span>\n <span class=\"c1\"># V kolika závorkách jsme vnoření. 0 = mimo závorky</span>\n <span class=\"n\">hloubka</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n <span class=\"c1\"># Jsme zrovna uvnitř nějakého HTML elementu?</span>\n <span class=\"n\">v_tagu</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n <span class=\"n\">vysledek</span> <span class=\"o\">=</span> <span class=\"s2\">""</span>\n <span class=\"k\">for</span> <span class=\"n\">znak</span> <span class=\"ow\">in</span> <span class=\"n\">text</span><span class=\"p\">:</span>\n <span class=\"c1\"># Pokud jsme v nějakém elementu…</span>\n <span class=\"k\">if</span> <span class=\"n\">v_tagu</span><span class=\"p\">:</span>\n <span class=\"c1\"># …chceme zachovat veškerý text.</span>\n <span class=\"n\">vysledek</span> <span class=\"o\">+=</span> <span class=\"n\">znak</span>\n <span class=\"c1\"># Končí tady značka?</span>\n <span class=\"k\">if</span> <span class=\"n\">znak</span> <span class=\"o\">==</span> <span class=\"s2\">">"</span><span class=\"p\">:</span>\n <span class=\"n\">v_tagu</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n <span class=\"k\">else</span><span class=\"p\">:</span>\n <span class=\"k\">if</span> <span class=\"n\">znak</span> <span class=\"o\">==</span> <span class=\"s2\">"("</span><span class=\"p\">:</span>\n <span class=\"c1\"># Pokud vstupujeme do uzávorkovaného výrazu, jsme o jednu</span>\n <span class=\"c1\"># úroveň hlouběji.</span>\n <span class=\"n\">hloubka</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n <span class=\"k\">elif</span> <span class=\"n\">znak</span> <span class=\"o\">==</span> <span class=\"s2\">")"</span><span class=\"p\">:</span>\n <span class=\"c1\"># Pokud vystupujeme, úroveň o jedna zmenšíme.</span>\n <span class=\"n\">hloubka</span> <span class=\"o\">-=</span> <span class=\"mi\">1</span>\n <span class=\"k\">elif</span> <span class=\"n\">hloubka</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n <span class=\"c1\"># Jsme mimo závorky, chceme si znak nechat.</span>\n <span class=\"n\">vysledek</span> <span class=\"o\">+=</span> <span class=\"n\">znak</span>\n <span class=\"c1\"># Ale musíme zkontrolovat, jestli nevstupujeme do nějakého HTML</span>\n <span class=\"c1\"># elementu.</span>\n <span class=\"k\">if</span> <span class=\"n\">znak</span> <span class=\"o\">==</span> <span class=\"s2\">"<"</span><span class=\"p\">:</span>\n <span class=\"n\">v_tagu</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n\n <span class=\"k\">return</span> <span class=\"n\">vysledek</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">):</span>\n <span class=\"k\">return</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"nb\">id</span><span class=\"o\">=</span><span class=\"s2\">"firstHeading"</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">text</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_odkaz</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">):</span>\n <span class=\"n\">hlavni_text</span> <span class=\"o\">=</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"n\">class_</span><span class=\"o\">=</span><span class=\"s2\">"mw-parser-output"</span><span class=\"p\">)</span>\n <span class=\"k\">for</span> <span class=\"n\">odstavec</span> <span class=\"ow\">in</span> <span class=\"n\">hlavni_text</span><span class=\"o\">.</span><span class=\"n\">find_all</span><span class=\"p\">(</span><span class=\"s2\">"p"</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">odstavec</span><span class=\"p\">)</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">odstran_zavorky</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">odstavec</span><span class=\"p\">)))</span>\n <span class=\"k\">for</span> <span class=\"n\">odkaz</span> <span class=\"ow\">in</span> <span class=\"n\">odstavec</span><span class=\"o\">.</span><span class=\"n\">find_all</span><span class=\"p\">(</span><span class=\"s2\">"a"</span><span class=\"p\">):</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">odkaz</span><span class=\"p\">)</span>\n <span class=\"k\">return</span> <span class=\"n\">odkaz</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">"href"</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">stahuj</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">):</span>\n <span class=\"n\">navstivene</span> <span class=\"o\">=</span> <span class=\"nb\">set</span><span class=\"p\">()</span>\n <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n <span class=\"k\">if</span> <span class=\"n\">stranka</span> <span class=\"ow\">in</span> <span class=\"n\">navstivene</span><span class=\"p\">:</span>\n <span class=\"k\">break</span>\n <span class=\"n\">navstivene</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">)</span>\n\n <span class=\"n\">odpoved</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">URL</span> <span class=\"o\">+</span> <span class=\"n\">stranka</span><span class=\"p\">)</span>\n <span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">raise_for_status</span><span class=\"p\">()</span>\n\n <span class=\"n\">soup</span> <span class=\"o\">=</span> <span class=\"n\">BeautifulSoup</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"s2\">"html.parser"</span><span class=\"p\">)</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">))</span>\n\n <span class=\"n\">stranka</span> <span class=\"o\">=</span> <span class=\"n\">najdi_odkaz</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">)</span>\n <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">stranka</span><span class=\"p\">:</span>\n <span class=\"k\">break</span>\n\n <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s2\">"__main__"</span><span class=\"p\">:</span>\n <span class=\"n\">stahuj</span><span class=\"p\">(</span><span class=\"n\">START</span><span class=\"p\">)</span>\n</pre></div>\n </div>\n</div><h3>Krok 8 – použití nové funkce</h3>\n<p>Úkol: Místo vypisování odstavce bez závorek ho znovu převeďte na značkovou\npolévku. Odkazy hledejte v ní. Teď už je na čase odstranit vypisování odstavce\ni odkazu.</p>\n<p>Očekávané chování: program bude vypisovat titulky stránek a následovat odkazy\nna nich. Až dojde na stránku, kde už byl (nebo kde není žádný odkaz), tak\nskončí.</p>\n<div class=\"solution\" id=\"solution-6\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/brno-jaro-knihovny/beginners/scraping/index/solutions/6/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">time</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">from</span> <span class=\"nn\">bs4</span> <span class=\"kn\">import</span> <span class=\"n\">BeautifulSoup</span>\n\n\n<span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"s2\">"https://en.wikipedia.org"</span>\n<span class=\"n\">START</span> <span class=\"o\">=</span> <span class=\"s2\">"/wiki/Special:Random"</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">odstran_zavorky</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">):</span>\n <span class=\"n\">hloubka</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n <span class=\"n\">v_tagu</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n <span class=\"n\">vysledek</span> <span class=\"o\">=</span> <span class=\"s2\">""</span>\n <span class=\"k\">for</span> <span class=\"n\">znak</span> <span class=\"ow\">in</span> <span class=\"n\">text</span><span class=\"p\">:</span>\n <span class=\"k\">if</span> <span class=\"n\">v_tagu</span><span class=\"p\">:</span>\n <span class=\"n\">vysledek</span> <span class=\"o\">+=</span> <span class=\"n\">znak</span>\n <span class=\"k\">if</span> <span class=\"n\">znak</span> <span class=\"o\">==</span> <span class=\"s2\">">"</span><span class=\"p\">:</span>\n <span class=\"n\">v_tagu</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n <span class=\"k\">else</span><span class=\"p\">:</span>\n <span class=\"k\">if</span> <span class=\"n\">znak</span> <span class=\"o\">==</span> <span class=\"s2\">"("</span><span class=\"p\">:</span>\n <span class=\"n\">hloubka</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n <span class=\"k\">elif</span> <span class=\"n\">znak</span> <span class=\"o\">==</span> <span class=\"s2\">")"</span><span class=\"p\">:</span>\n <span class=\"n\">hloubka</span> <span class=\"o\">-=</span> <span class=\"mi\">1</span>\n <span class=\"k\">elif</span> <span class=\"n\">hloubka</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n <span class=\"n\">vysledek</span> <span class=\"o\">+=</span> <span class=\"n\">znak</span>\n <span class=\"k\">if</span> <span class=\"n\">znak</span> <span class=\"o\">==</span> <span class=\"s2\">"<"</span><span class=\"p\">:</span>\n <span class=\"n\">v_tagu</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n\n <span class=\"k\">return</span> <span class=\"n\">vysledek</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">):</span>\n <span class=\"k\">return</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"nb\">id</span><span class=\"o\">=</span><span class=\"s2\">"firstHeading"</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">text</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_odkaz</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">):</span>\n <span class=\"n\">hlavni_text</span> <span class=\"o\">=</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"n\">class_</span><span class=\"o\">=</span><span class=\"s2\">"mw-parser-output"</span><span class=\"p\">)</span>\n <span class=\"k\">for</span> <span class=\"n\">odstavec</span> <span class=\"ow\">in</span> <span class=\"n\">hlavni_text</span><span class=\"o\">.</span><span class=\"n\">find_all</span><span class=\"p\">(</span><span class=\"s2\">"p"</span><span class=\"p\">):</span>\n <span class=\"n\">html</span> <span class=\"o\">=</span> <span class=\"n\">odstran_zavorky</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">odstavec</span><span class=\"p\">))</span>\n <span class=\"n\">odstavec</span> <span class=\"o\">=</span> <span class=\"n\">BeautifulSoup</span><span class=\"p\">(</span><span class=\"n\">html</span><span class=\"p\">,</span> <span class=\"s2\">"html.parser"</span><span class=\"p\">)</span>\n <span class=\"k\">for</span> <span class=\"n\">odkaz</span> <span class=\"ow\">in</span> <span class=\"n\">odstavec</span><span class=\"o\">.</span><span class=\"n\">find_all</span><span class=\"p\">(</span><span class=\"s2\">"a"</span><span class=\"p\">):</span>\n <span class=\"k\">return</span> <span class=\"n\">odkaz</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">"href"</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">stahuj</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">):</span>\n <span class=\"n\">navstivene</span> <span class=\"o\">=</span> <span class=\"nb\">set</span><span class=\"p\">()</span>\n <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n <span class=\"k\">if</span> <span class=\"n\">stranka</span> <span class=\"ow\">in</span> <span class=\"n\">navstivene</span><span class=\"p\">:</span>\n <span class=\"k\">break</span>\n <span class=\"n\">navstivene</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">)</span>\n\n <span class=\"n\">odpoved</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">URL</span> <span class=\"o\">+</span> <span class=\"n\">stranka</span><span class=\"p\">)</span>\n <span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">raise_for_status</span><span class=\"p\">()</span>\n\n <span class=\"n\">soup</span> <span class=\"o\">=</span> <span class=\"n\">BeautifulSoup</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"s2\">"html.parser"</span><span class=\"p\">)</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">))</span>\n\n <span class=\"n\">stranka</span> <span class=\"o\">=</span> <span class=\"n\">najdi_odkaz</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">)</span>\n <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">stranka</span><span class=\"p\">:</span>\n <span class=\"k\">break</span>\n\n <span class=\"n\">time</span><span class=\"o\">.</span><span class=\"n\">sleep</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">if</span> <span class=\"vm\">__name__</span> <span class=\"o\">==</span> <span class=\"s2\">"__main__"</span><span class=\"p\">:</span>\n <span class=\"n\">stahuj</span><span class=\"p\">(</span><span class=\"n\">START</span><span class=\"p\">)</span>\n</pre></div>\n </div>\n</div><h3>Krok 9 – filtrování pouze pěkných odkazů</h3>\n<p>Úkol: Někdy první odkaz nevede na jinou stránku (typicky odkazy na zdroje\nuvedené na konci stránky). Upravte funkci <code>najdi_odkaz()</code> tak, aby vracela\nadresu stránky jenom tehdy, pokud ta vracená hodnota začíná řetězecem <code>/wiki/</code>.</p>\n<p>Očekávané chování: program se bude chovat stejně jako dřív, ale bude trochu\nchytřejší v hledání správného odkazu.</p>\n<h3>Finální řešení</h3>\n<p>Na anglické wikipedii by tento program měl poměrně spolehlivě dojít na stránku\n<em>Philosophy</em>. Pokud to zkusíte s českou verzí, až tak slavné to není. Ale i tam\njsou výsledky relativně zajímavé.</p>\n<div class=\"solution\" id=\"solution-7\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/brno-jaro-knihovny/beginners/scraping/index/solutions/7/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">time</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">requests</span>\n<span class=\"kn\">from</span> <span class=\"nn\">bs4</span> <span class=\"kn\">import</span> <span class=\"n\">BeautifulSoup</span>\n\n\n<span class=\"n\">URL</span> <span class=\"o\">=</span> <span class=\"s2\">"https://en.wikipedia.org"</span>\n<span class=\"n\">START</span> <span class=\"o\">=</span> <span class=\"s2\">"/wiki/Special:Random"</span>\n<span class=\"c1\"># Česká wikipedie:</span>\n<span class=\"c1\"># URL = "https://cs.wikipedia.org"</span>\n<span class=\"c1\"># START = "/wiki/Speciální:Náhodná_stránka"</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">odstran_zavorky</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">):</span>\n <span class=\"n\">hloubka</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n <span class=\"n\">v_tagu</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n <span class=\"n\">vysledek</span> <span class=\"o\">=</span> <span class=\"s2\">""</span>\n <span class=\"k\">for</span> <span class=\"n\">znak</span> <span class=\"ow\">in</span> <span class=\"n\">text</span><span class=\"p\">:</span>\n <span class=\"k\">if</span> <span class=\"n\">v_tagu</span><span class=\"p\">:</span>\n <span class=\"n\">vysledek</span> <span class=\"o\">+=</span> <span class=\"n\">znak</span>\n <span class=\"k\">if</span> <span class=\"n\">znak</span> <span class=\"o\">==</span> <span class=\"s2\">">"</span><span class=\"p\">:</span>\n <span class=\"n\">v_tagu</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n <span class=\"k\">else</span><span class=\"p\">:</span>\n <span class=\"k\">if</span> <span class=\"n\">znak</span> <span class=\"o\">==</span> <span class=\"s2\">"("</span><span class=\"p\">:</span>\n <span class=\"n\">hloubka</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n <span class=\"k\">elif</span> <span class=\"n\">znak</span> <span class=\"o\">==</span> <span class=\"s2\">")"</span><span class=\"p\">:</span>\n <span class=\"n\">hloubka</span> <span class=\"o\">-=</span> <span class=\"mi\">1</span>\n <span class=\"k\">elif</span> <span class=\"n\">hloubka</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n <span class=\"n\">vysledek</span> <span class=\"o\">+=</span> <span class=\"n\">znak</span>\n <span class=\"k\">if</span> <span class=\"n\">znak</span> <span class=\"o\">==</span> <span class=\"s2\">"<"</span><span class=\"p\">:</span>\n <span class=\"n\">v_tagu</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n\n <span class=\"k\">return</span> <span class=\"n\">vysledek</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">):</span>\n <span class=\"k\">return</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"nb\">id</span><span class=\"o\">=</span><span class=\"s2\">"firstHeading"</span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">text</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">najdi_odkaz</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">):</span>\n <span class=\"n\">hlavni_text</span> <span class=\"o\">=</span> <span class=\"n\">soup</span><span class=\"o\">.</span><span class=\"n\">find</span><span class=\"p\">(</span><span class=\"n\">class_</span><span class=\"o\">=</span><span class=\"s2\">"mw-parser-output"</span><span class=\"p\">)</span>\n <span class=\"k\">for</span> <span class=\"n\">odstavec</span> <span class=\"ow\">in</span> <span class=\"n\">hlavni_text</span><span class=\"o\">.</span><span class=\"n\">find_all</span><span class=\"p\">(</span><span class=\"s2\">"p"</span><span class=\"p\">):</span>\n <span class=\"n\">html</span> <span class=\"o\">=</span> <span class=\"n\">odstran_zavorky</span><span class=\"p\">(</span><span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">odstavec</span><span class=\"p\">))</span>\n <span class=\"n\">odstavec</span> <span class=\"o\">=</span> <span class=\"n\">BeautifulSoup</span><span class=\"p\">(</span><span class=\"n\">html</span><span class=\"p\">,</span> <span class=\"s2\">"html.parser"</span><span class=\"p\">)</span>\n <span class=\"k\">for</span> <span class=\"n\">odkaz</span> <span class=\"ow\">in</span> <span class=\"n\">odstavec</span><span class=\"o\">.</span><span class=\"n\">find_all</span><span class=\"p\">(</span><span class=\"s2\">"a"</span><span class=\"p\">):</span>\n <span class=\"n\">href</span> <span class=\"o\">=</span> <span class=\"n\">odkaz</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s2\">"href"</span><span class=\"p\">)</span>\n <span class=\"k\">if</span> <span class=\"n\">href</span><span class=\"o\">.</span><span class=\"n\">startswith</span><span class=\"p\">(</span><span class=\"s2\">"/wiki/"</span><span class=\"p\">):</span>\n <span class=\"k\">return</span> <span class=\"n\">href</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">stahuj</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">):</span>\n <span class=\"n\">navstivene</span> <span class=\"o\">=</span> <span class=\"nb\">set</span><span class=\"p\">()</span>\n <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n <span class=\"k\">if</span> <span class=\"n\">stranka</span> <span class=\"ow\">in</span> <span class=\"n\">navstivene</span><span class=\"p\">:</span>\n <span class=\"k\">break</span>\n <span class=\"n\">navstivene</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">stranka</span><span class=\"p\">)</span>\n\n <span class=\"n\">odpoved</span> <span class=\"o\">=</span> <span class=\"n\">requests</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"s2\">"{URL}{stranka}"</span><span class=\"p\">)</span>\n <span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">raise_for_status</span><span class=\"p\">()</span>\n\n <span class=\"n\">soup</span> <span class=\"o\">=</span> <span class=\"n\">BeautifulSoup</span><span class=\"p\">(</span><span class=\"n\">odpoved</span><span class=\"o\">.</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"s2\">"html.parser"</span><span class=\"p\">)</span>\n <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">najdi_titulek</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">))</span>\n\n <span class=\"n\">stranka</span> <span class=\"o\">=</span> <span class=\"n\">najdi_odkaz</span><span class=\"p\">(</span><span class=\"n\">soup</span><span class=\"p\">)</span>\n <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"n\">stranka</span><span class=\"p\">:</span>\n <span class=\"k\">break</span>\n</pre></div>\n </div>\n</div>\n\n\n " } } }