Ovaj tekst sam prvi put napisao 2021, sa primerom na oglasima za posao sa Stack Overflow-a. Taj deo sajta je u međuvremenu ugašen, a promenio se i Selenium, pa stari kod više nije radio. Zato je primer napisan iznova i proveren u oktobru 2026. godine.
Kada je skidanje podataka dozvoljeno?
Skidanje podataka štedi sate prepisivanja. Najčešće se koristi za:
- praćenje cena kod dobavljača ili konkurencije;
- prenos sopstvenih podataka sa starog sajta na novi, kada stari sistem nema izvoz;
- skupljanje javnih podataka za analizu i istraživanje;
- proveru sopstvenog sajta, na primer naslova i linkova na svim stranicama.
To što je nešto javno vidljivo ne znači da sme da se uzme i koristi kako god želite. Pre nego što počnete, proverite:
- robots.txt. Na adresi sajta sa dodatkom
/robots.txtvlasnik navodi koje delove sajta roboti ne bi trebalo da otvaraju. - Uslove korišćenja sajta. Mnogi sajtovi automatsko preuzimanje izričito zabranjuju.
- Autorska prava. Tuđe tekstove, opise i slike ne prenosite na svoj sajt. To nije dozvoljeno, a ne pomaže ni u pretrazi, jer Google duplikate filtrira. Više o tome pročitajte u tekstu o dupliranom sadržaju.
- Lične podatke. Imena, adrese e-pošte i brojevi telefona su lični podaci i za njih važi zakon o zaštiti podataka o ličnosti.
- Opterećenje servera. Pravite pauze između zahteva, kao u primerima ispod. Program koji otvara stotine stranica u sekundi može da obori mali sajt.
- Da li postoji API. Ako sajt nudi API za podatke koji vam trebaju, koristite njega. Brže je, pouzdanije i dozvoljeno.
Priprema
Primer je rađen na Windowsu, a isti kod radi i na Linuksu i macOS-u.
- Instalirajte Python sa python.org. Na prvom ekranu instalacije uključite opciju Add python.exe to PATH, pa nema potrebe da putanju dodajete ručno.
- Kod pišem u programu Visual Studio Code (visualstudio.com), uz dodatak za Python (ms-python.python), koji će vam VS Code sam ponuditi.
- Napravite folder za projekat, otvorite ga u VS Code-u, pa u terminalu instalirajte biblioteke:
pip install requests beautifulsoup4 selenium
Komanda pip preuzima biblioteke koje ne dolaze uz Python, pa ne morate da ih tražite po internetu. Za drugi način treba vam i instaliran Firefox. Ranije je trebalo ručno preuzeti geckodriver.exe i kopirati ga u folder projekta, a od verzije 4.6 Selenium to radi sam.
Za vežbu koristimo sajt quotes.toscrape.com, napravljen baš za učenje skidanja podataka. Na njemu je 100 poznatih citata na 10 stranica, a postoji i verzija čiji sadržaj pravi JavaScript. Cilj je da sve citate i njihove autore prebacimo u jednu tabelu.
Koji način izabrati?
Otvorite stranicu u pregledaču i pritisnite Ctrl+U da vidite njen izvorni kod. Ako se podaci koji vam trebaju vide u izvornom kodu, dovoljan je prvi način. Ako ih nema, stranicu dopunjuje JavaScript posle učitavanja, i tada vam treba drugi način.
| requests i BeautifulSoup | Selenium i Firefox | |
|---|---|---|
| Kako radi | Preuzme HTML stranice i čita ga | Upravlja pravim pregledačem, kao da vi klikćete |
| Brzina | Brz | Sporiji, jer se stranica zaista prikazuje |
| JavaScript stranice | Ne vidi sadržaj koji pravi JavaScript | Vidi sve što vidi i korisnik |
| Prijava, klikovi, formulari | Teže | Lako |
| Kada ga koristiti | Uvek kada može | Kada prvi način ne vidi podatke |
Prvi način: requests i BeautifulSoup
U folderu projekta napravite fajl citati.py sa sledećim kodom:
import csv
import random
import time
from urllib.parse import urljoin
import requests
from bs4 import BeautifulSoup
wait_from = 2
wait_to = 4
url = "https://quotes.toscrape.com/"
headers = {"User-Agent": "Mozilla/5.0 (primer sa programiranje.co.rs)"}
with open("citati.csv", "w", newline="", encoding="utf-8-sig") as csv_file:
writer = csv.writer(csv_file)
writer.writerow(["citat", "autor"])
while url:
response = requests.get(url, headers=headers, timeout=30)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
for quote in soup.select("div.quote"):
text = quote.select_one("span.text").get_text(strip=True)
author = quote.select_one("small.author").get_text(strip=True)
writer.writerow([text, author])
next_link = soup.select_one("li.next > a")
url = urljoin(url, next_link["href"]) if next_link else None
if url:
time.sleep(random.randint(wait_from, wait_to))
print("Gotovo!")
Pokrenite ga komandom python citati.py. Za tridesetak sekundi u folderu će se pojaviti citati.csv sa 100 citata. Evo šta radi koji deo:
wait_fromiwait_toodređuju koliko sekundi program čeka između dve stranice, svaki put nasumično. Ne želimo da otvaramo stranice prebrzo, jer to opterećuje server, a sajt može i da nas blokira.requests.getpreuzima HTML stranice.timeoutsprečava da program zauvek čeka sajt koji ne odgovara, araise_for_status()prekida rad ako sajt vrati grešku, umesto da tiho snimi praznu tabelu.soup.select("div.quote")pronalazi sve elemente po CSS selektoru. Selektor saznate tako što na stranici desnim klikom izaberete Inspect (Pregledaj element) i pogledate u kom elementu i sa kojom klasom je podatak. Ovde je svaki citat udivelementu sa klasomquote, tekst uspan.text, a autor usmall.author.li.next > aje link „Next“ na dnu stranice. Dok on postoji, program prelazi na sledeću stranicu. Kada ga nema, stigli smo do poslednje stranice i petlja se završava. Funkcijaurljoinod relativne adrese linka (/page/2/) pravi punu adresu.
Drugi način: Selenium i Firefox
Verzija sajta na adresi /js/ izgleda isto, ali citate ubacuje JavaScript. U njenom izvornom kodu citata nema, pa prvi način tu vraća praznu tabelu. Selenium otvara pravi Firefox, čeka da se stranica prikaže i klikće na „Next“, isto kao čovek:
import csv
import random
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
wait_from = 2
wait_to = 4
browser = webdriver.Firefox()
browser.get("https://quotes.toscrape.com/js/")
wait = WebDriverWait(browser, 10)
with open("citati-js.csv", "w", newline="", encoding="utf-8-sig") as csv_file:
writer = csv.writer(csv_file)
writer.writerow(["citat", "autor"])
while True:
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "div.quote")))
for quote in browser.find_elements(By.CSS_SELECTOR, "div.quote"):
text = quote.find_element(By.CSS_SELECTOR, "span.text").text
author = quote.find_element(By.CSS_SELECTOR, "small.author").text
writer.writerow([text, author])
next_links = browser.find_elements(By.CSS_SELECTOR, "li.next > a")
if not next_links:
break
time.sleep(random.randint(wait_from, wait_to))
first_quote = browser.find_element(By.CSS_SELECTOR, "div.quote")
next_links[0].click()
wait.until(EC.staleness_of(first_quote))
browser.quit()
print("Gotovo!")
webdriver.Firefox()otvara novi prozor Firefoxa kojim program upravlja. Na kraju gabrowser.quit()zatvara.find_elements(By.CSS_SELECTOR, ...)je današnji način pretrage. U Seleniumu 3 pisalo sefind_elements_by_css_selector(...), i to je bio kod u prvoj verziji ovog teksta. Selenium 4 je te funkcije uklonio, pa stari primeri sa interneta javljaju grešku.WebDriverWaitčeka najviše 10 sekundi da se citati pojave na stranici. To je pouzdanije od fiksnog čekanja, jer ne zavisi od brzine sajta.staleness_of(first_quote)posle klika čeka da stara stranica nestane. Bez toga bi program mogao dva puta da pročita istu stranicu, pre nego što se nova učita.
Ako ne želite da gledate prozor pregledača, Firefox može da radi i nevidljivo. Umesto browser = webdriver.Firefox() napišite:
options = webdriver.FirefoxOptions()
options.add_argument("-headless")
browser = webdriver.Firefox(options=options)
Kako otvoriti rezultat u Excelu?
Oba primera snimaju CSV fajl sa kodiranjem utf-8-sig. Taj dodatak na početku fajla kaže Excelu da je tekst u UTF-8, pa se slova kao što su č, ć i đ prikazuju ispravno. Modul csv sam stavlja navodnike oko teksta koji sadrži zarez, pa citati ostaju u jednoj ćeliji.
Ako vam Excel ceo red stavi u jednu kolonu, to je zbog regionalnih podešavanja: kod nas Excel kao razdelnik očekuje tačku-zarez. Tada otvorite fajl preko Data → From Text/CSV, ili u kodu napišite csv.writer(csv_file, delimiter=";").
Česti problemi
AttributeError: 'WebDriver' object has no attribute 'find_elements_by_css_selector': kod je pisan za Selenium 3. Zamenite ga oblikomfind_elements(By.CSS_SELECTOR, ...)kao u primeru iznad.- Tabela je prazna: stranica sadržaj pravi JavaScriptom, pa koristite Selenium, ili se promenio CSS selektor. Proverite ga ponovo preko Inspect.
- Greška 403 ili 429: sajt vas je blokirao ili traži da usporite. Povećajte pauze i proverite da li sajt uopšte dozvoljava automatsko preuzimanje.
UnicodeEncodeErrorna Windowsu: fajl je otvoren bezencoding. Uvek navediteencoding="utf-8"ili"utf-8-sig".- Program je radio, a sada ne radi: sajt je promenio izgled i selektori više ne odgovaraju. Programe za skidanje podataka treba održavati, jer sajtovi ne pitaju pre nego što se promene.
Da li je lako skinuti podatke sa web stranice?
Sa malo koda jeste, kao što se vidi iz primera. U ovom primeru je korišćen Python, ali isto može da se uradi i u PHP-u, C#-u i drugim programskim jezicima. Teži deo počinje kod pravih sajtova: prijava, zaštita od robota, česte promene izgleda. Takve projekte sam radio za klijente, a primere možete pogledati u portfelju, pod automatizacija pregledača i web scraping.
Nadam se da vam je uputstvo pomoglo. Ako zapne negde, ostavite komentar ispod i pomoći ću.
Treba vam program koji ovo radi umesto vas?
Pravim programe koji sami prikupljaju podatke sa sajtova, popunjavaju formulare i prebacuju podatke u Excel ili bazu, uz poštovanje pravila sajtova sa kojih rade.
Ostavite odgovor