Vaje
Pri delu si lahko pomagaš z zapiski, vendar ne uporabljaj enake povezave kot tam: stran z imeni avtorjev, ki se začnejo s črko b, pridobi na naslovu https://ucilnica.fri.uni-lj.si/mod/resource/view.php?id=54610.
- Napiši program, ki izpiše imena vseh avtorjev, naštetih na strani.
Rešitev
from urllib.request import urlopen
from bs4 import BeautifulSoup
url = "https://ucilnica.fri.uni-lj.si/mod/resource/view.php?id=54610"
html = urlopen(url).read()
soup = BeautifulSoup(html, 'html.parser')
for link in soup.find_all("a"):
if "name" in link.attrs:
print(link.text)
- Dopolni program tako, da sestavi slovar, katerega ključi so avtorji del, vrednosti pa pripadajoče oznake, npr.
a556
.
Rešitev
avtorji = {}
for link in soup.find_all("a"):
if "name" in link.attrs:
author = link.text
avtorji[author] = link.attrs["name"]
V datoteko zapiši dokument v obliki Markdown, ki vsebuje seznam (= alineje) z imeni avtorjev. Imena naj delujejo kot povezave v dokument. Babbage, na primer, je zapisan z
- [Babbage, Charles, 1791-1871](https://ucilnica.fri.uni-lj.si/mod/resource/view.php?id=54610#a556)
Ali je oblikovanje pravilno in ali povezave delujejo, lahko preveriš tako, da skopiraš nekaj vrstic v Jupyter (če za programiranje uporabljaš tega), ali pa ga odpreš v PyCharmu (vanj ga preprosto povleci).
Rešitev
with open("avtorji.md", "w") as f:
for a, n in avtorji.items():
f.write(f"- [{a}]({url}#{n})\n")
Spremeni slovar tako, da
- bo ključ vseboval samo ime avtorja, brez letnic rojstva
- pripadajoča vrednost bo trojka z interno oznako (npr.
a556
), letnico rojstva in letnico smrti.
Pri tej nalogi po možnosti uporabi regularne izraze.
Rešitev
import re
avtorji = {}
for link in soup.find_all("a"):
if "name" in link.attrs:
avtor = link.text
r = s = ""
res = re.search(r"(.*), (\d*)\??-(\d*)\??", avtor)
if res is not None:
avtor, r, s = res.groups()
if r:
r = int(r)
if s:
s = int(s)
avtorji[avtor] = (link.attrs["name"], r, s)
Spremeni datoteko z Markdownom tako, da bodo avtorji urejeni po stoletjih, v katerem so se rodili. Stoletja naj bodo mednaslovi, na primer
## 1700 - 1799
Rešitev
min_rojstvo = min(x for _, x, _ in avtorji.values() if x) // 100 * 100
max_rojstvo = max(x for _, x, _ in avtorji.values() if x) // 100 * 100
with open("avtorji1.md", "w") as f:
for st in range(min_rojstvo, max_rojstvo + 100, 100):
f.write(f"## {st} - {st + 99}\n\n")
for a, (n, r, _) in avtorji.items():
if r and st <= r < st + 100:
f.write(f"- [{a}]({url}#{n})\n\n")
Sestavi slovar, katerega ključi so imena avtorjev (brez letnic), pripadajoče vrednosti pa seznami naslovo njihovih del. Imena del naj ne vsebujejo jezikov in opomb "as Author".
Iz seznamov, nabranih v prejšnji točki, izloči tista "dela", ki so pravzaprav le povezave na Wikipedijo. (Oziroma, obratno, obdrži le dela, pri katerih je opomba "as Author").
Vrni se k točki 6: pripadajoča vrednost naj ne bo seznam naslovov, temveč seznam parov (naslov, jezik).
Rešitev
from collections import defaultdict
avtorji = {}
dela = defaultdict(list)
for link in soup.find_all("a"):
if "name" in link.attrs:
avtor = link.text
r = s = ""
res = re.search(r"(.*), (\d*)\??-(\d*)\??", avtor)
if res is not None:
avtor, r, s = res.groups()
if r:
r = int(r)
if s:
s = int(s)
avtorji[avtor] = (link.attrs["name"], r, s)
next = link.find_next("ul")
for delo in next.find_all("li", {"class": "pgdbetext"}):
naslov = delo.a.text
besedilo = delo.text
if "(as Author)" in besedilo:
jezik = re.findall(r"\(.*?\)", besedilo)[-2].strip("()")
dela[avtor].append((naslov, jezik))
Sestavi dokument markdown, v katerem bodo navedena vsa dela vseh avtorjev v takšni obliki:
- glavni naslovi so imena jezikov
- podnaslovi so imena avtorjev, ki so napisali vsaj eno delo v tem jeziku
- znotraj tega podnaslova so našteta vsa dela tega avtorja v tem jeziku.
Rešitev
jeziki_avtorji_dela = defaultdict(lambda: defaultdict(list))
for avtor, dela_ in dela.items():
for naslov, jezik in dela_:
jeziki_avtorji_dela[jezik][avtor].append(naslov)
with open("dela.md", "w") as f:
for jezik, avtor_dela in jeziki_avtorji_dela.items():
f.write(f"# {jezik}\n\n")
for avtor, dela_ in avtor_dela.items():
f.write(f"## {avtor}\n\n")
f.write("\n".join(f"- {d}" for d in dela_) + "\n\n")