Teknofest yarışmalarından İlkokul/Ortaokul kategorisindeki başarılı projelerin raporlarını otomatik olarak indirin ve proje adlarını çıkarın.
"""
Teknofest Yarışma Veri Toplama Otomasyonu
==========================================
Bu script Teknofest web sitesinden İlkokul/Ortaokul kategorisindeki
yarışma raporlarını otomatik olarak indirir ve proje adlarını çıkarır.
Kullanım:
python teknofest_scraper.py
Gerekli Kütüphaneler:
pip install selenium requests pytesseract pdf2image python-docx PyPDF2
"""
import os
import time
import json
import hashlib
import requests
from datetime import datetime
from pathlib import Path
# Selenium imports
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
# PDF ve OCR imports
from PyPDF2 import PdfReader
from pdf2image import convert_from_path
import pytesseract
from docx import Document
# ==================== KONFİGÜRASYON ====================
class Config:
"""Uygulama konfigürasyonu"""
# Chrome Browser Path
CHROME_PATH = r"C:\Program Files\Google\Chrome\Application\chrome.exe"
# Tesseract OCR Path
TESSERACT_PATH = r"C:\Users\mhmtx\AppData\Local\Programs\Tesseract-OCR\tesseract.exe"
# Poppler Path
POPPLER_PATH = r"D:\teknofest\poppler-25.12.0\Library\bin"
# Çıktı Klasörü
OUTPUT_BASE = r"D:\teknofest\output"
# Sezon URL'leri
SEASON_URLS = [
"https://www.teknofest.org/tr/season/2025",
"https://www.teknofest.org/tr/season/2024",
"https://www.teknofest.org/tr/season/2023",
"https://www.teknofest.org/tr/season/2022",
"https://www.teknofest.org/tr/season/2021",
"https://www.teknofest.org/tr/season/2020",
"https://www.teknofest.org/tr/season/2019",
]
# Ortaokul kategori URL'si
CATEGORY_URL = "https://www.teknofest.org/tr/yarismalar/#tabsCategory2"
# Bekleme süreleri (saniye)
PAGE_LOAD_TIMEOUT = 30
IMPLICIT_WAIT = 10
ELEMENT_WAIT = 15
# İndirme ayarları
DOWNLOAD_TIMEOUT = 120
MAX_RETRIES = 3
class TeknofestScraper:
"""Teknofest veri toplama sınıfı"""
def __init__(self):
self.driver = None
self.session = requests.Session()
self.results = []
self.downloaded_files = []
# Klasör yapısı oluştur
self.setup_folders()
# Tesseract path ayarla
if os.path.exists(Config.TESSERACT_PATH):
pytesseract.pytesseract.tesseract_cmd = Config.TESSERACT_PATH
def setup_folders(self):
"""Gerekli klasörleri oluştur"""
Path(Config.OUTPUT_BASE).mkdir(parents=True, exist_ok=True)
def init_driver(self):
"""Chrome driver başlat"""
print("🌐 Chrome driver başlatılıyor...")
chrome_options = Options()
chrome_options.binary_location = Config.CHROME_PATH
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--window-size=1920,1080')
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
chrome_options.add_experimental_option('excludeSwitches', ['enable-automation'])
chrome_options.add_experimental_option('useAutomationExtension', False)
# İndirme ayarları
prefs = {
"download.default_directory": Config.OUTPUT_BASE,
"download.prompt_for_download": False,
"download.directory_upgrade": True,
"safebrowsing.enabled": True
}
chrome_options.add_experimental_option("prefs", prefs)
try:
self.driver = webdriver.Chrome(options=chrome_options)
self.driver.set_page_load_timeout(Config.PAGE_LOAD_TIMEOUT)
self.driver.implicitly_wait(Config.IMPLICIT_WAIT)
print("✅ Chrome driver başarıyla başlatıldı")
return True
except Exception as e:
print(f"❌ Driver başlatma hatası: {e}")
return False
def navigate_to_category(self, season_url):
"""Sezon sayfasına git ve ortaokul kategorisini seç"""
try:
# Ana sayfaya git
self.driver.get(season_url)
time.sleep(3)
# Kategori sayfasına git
self.driver.get(Config.CATEGORY_URL)
time.sleep(3)
# Ortaokul sekmesine tıkla (tabsCategory2)
try:
tab_button = self.driver.find_element(By.ID, "tabsCategory2")
tab_button.click()
time.sleep(2)
print(f" ✅ Ortaokul kategorisi seçildi")
except:
# Alternatif selector dene
tab_button = self.driver.find_element(By.CSS_SELECTOR, '[href*="tabsCategory2"]')
tab_button.click()
time.sleep(2)
return True
except Exception as e:
print(f" ❌ Kategori navigasyon hatası: {e}")
return False
def get_competitions(self):
"""Yarışmaları bul"""
competitions = []
try:
# "yarışması" içeren başlıkları bul
competition_elements = self.driver.find_elements(
By.CSS_SELECTOR,
"a[href*='yarismalar'], div.title:contains('yarışması'), h3:contains('yarışması')"
)
for elem in competition_elements:
try:
title = elem.text.strip()
if "yarışması" in title.lower():
href = elem.get_attribute("href")
competitions.append({
"title": title,
"url": href
})
except:
continue
except Exception as e:
print(f" ❌ Yarışma bulma hatası: {e}")
return competitions
def get_past_reports(self, competition_url, category_name):
"""Geçmiş yıl raporlarını getir"""
reports = []
try:
self.driver.get(competition_url)
time.sleep(3)
# "Geçmiş Yıl Raporları" sekmesini bul
try:
reports_tab = self.driver.find_element(
By.XPATH,
"//a[contains(text(),'Geçmiş Yıl Raporları')]"
)
reports_tab.click()
time.sleep(2)
except:
pass
# İlkokul/Ortaokul filtresi
try:
filter_element = self.driver.find_element(
By.XPATH,
"//option[contains(text(),'İlkokul/Ortaokul')]"
)
filter_element.click()
time.sleep(2)
except:
pass
# Etiket kontrolü (İnsanlık Yararına Teknoloji için)
tags = []
if "İnsanlık Yararına Teknoloji" in category_name:
tag_elements = self.driver.find_elements(By.CSS_SELECTOR, ".tag, .label, .badge")
for tag in tag_elements:
tag_text = tag.text.lower()
if any(t in tag_text for t in ["afet", "inovasyon", "sağlık"]):
tags.append(tag.text)
# Başarılı/Finalist veya Derece kontrolü
status = None
try:
status_elem = self.driver.find_element(
By.XPATH,
"//span[contains(text(),'Başarılı') or contains(text(),'Finalist') or contains(text(),'Derece')]"
)
status = status_elem.text
except:
pass
# Rapor linklerini bul
report_links = self.driver.find_elements(
By.CSS_SELECTOR,
"a[href$='.pdf'], a[href$='.doc'], a[href$='.docx']"
)
for link in report_links:
try:
href = link.get_attribute("href")
if href:
reports.append({
"url": href,
"tags": tags,
"status": status
})
except:
continue
except Exception as e:
print(f" ⚠️ Rapor bulma hatası: {e}")
return reports
def download_file(self, url, folder_path, filename=None):
"""Dosya indir"""
try:
response = self.session.get(url, stream=True, timeout=Config.DOWNLOAD_TIMEOUT)
response.raise_for_status()
# Dosya adını al
if not filename:
filename = url.split('/')[-1].split('?')[0]
filepath = os.path.join(folder_path, filename)
# Dosyayı kaydet
with open(filepath, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print(f" 📥 İndirildi: {filename}")
return filepath
except Exception as e:
print(f" ❌ İndirme hatası: {e}")
return None
def extract_project_name_from_pdf(self, pdf_path):
"""PDF'ten proje adını çıkar"""
project_name = None
try:
# PDF oku
reader = PdfReader(pdf_path)
first_page = reader.pages[0]
text = first_page.extract_text()
# Proje adını bul (heuristic yaklaşım)
lines = text.split('\n')
for i, line in enumerate(lines):
if any(keyword in line.lower() for keyword in ['proje adı', 'proje adi', 'project name']):
if i + 1 < len(lines):
project_name = lines[i + 1].strip()
break
# Alternatif: İlk büyük metin bloğunu al
if not project_name:
for line in lines:
if len(line) > 10 and len(line) < 100:
project_name = line.strip()
break
except Exception as e:
print(f" ⚠️ PDF okuma hatası: {e}")
# OCR dene
try:
images = convert_from_path(pdf_path, poppler_path=Config.POPPLER_PATH)
if images:
text = pytesseract.image_to_string(images[0], lang='tur')
lines = text.split('\n')
for line in lines:
if len(line) > 10 and len(line) < 100:
project_name = line.strip()
break
except Exception as ocr_error:
print(f" ⚠️ OCR hatası: {ocr_error}")
return project_name
def extract_project_name_from_doc(self, doc_path):
"""DOC/DOCX'ten proje adını çıkar"""
try:
doc = Document(doc_path)
for para in doc.paragraphs:
if len(para.text) > 10 and len(para.text) < 100:
return para.text.strip()
except Exception as e:
print(f" ⚠️ DOC okuma hatası: {e}")
return None
def process_competition(self, competition, season_year):
"""Bir yarışmayı işle"""
print(f"\n📋 İşleniyor: {competition['title']}")
# Klasör yapısı oluştur
# Örnek: 2025 -> İnsanlık Yararına Teknoloji -> Afet Yönetimi
category_folder = self.create_folder_structure(competition, season_year)
# Raporları al
reports = self.get_past_reports(competition['url'], competition.get('title', ''))
for report in reports:
# Dosyayı indir
filename = report['url'].split('/')[-1].split('?')[0]
filepath = self.download_file(report['url'], category_folder, filename)
if filepath and os.path.exists(filepath):
# Proje adını çıkar
ext = os.path.splitext(filepath)[1].lower()
if ext == '.pdf':
project_name = self.extract_project_name_from_pdf(filepath)
elif ext in ['.doc', '.docx']:
project_name = self.extract_project_name_from_doc(filepath)
else:
project_name = None
# Dosya adını yeniden adlandır
if project_name:
status_label = ""
if report.get('status'):
if 'derece' in report['status'].lower():
status_label = " - Derece"
elif 'başarılı' in report['status'].lower() or 'finalist' in report['status'].lower():
status_label = " - Başarılı/Finalist"
new_filename = f"{project_name}{status_label}{ext}"
new_filepath = os.path.join(category_folder, new_filename)
try:
os.rename(filepath, new_filepath)
print(f" ✅ Yeniden adlandırıldı: {new_filename}")
self.downloaded_files.append(new_filepath)
except Exception as e:
print(f" ⚠️ Yeniden adlandırma hatası: {e}")
self.downloaded_files.append(filepath)
else:
self.downloaded_files.append(filepath)
def create_folder_structure(self, competition, season_year):
"""Klasör yapısı oluştur"""
# Kategori adını belirle
title = competition.get('title', 'Bilinmeyen Kategori')
# Alt klasör belirle
subfolder = "Genel"
if "İnsanlık Yararına Teknoloji" in title:
if "afet" in title.lower():
subfolder = "Afet Yönetimi"
elif "inovasyon" in title.lower():
subfolder = "İnovasyon"
elif "sağlık" in title.lower() or "health" in title.lower():
subfolder = "Sağlık"
# Klasör yolu
folder_path = os.path.join(Config.OUTPUT_BASE, str(season_year), title, subfolder)
Path(folder_path).mkdir(parents=True, exist_ok=True)
return folder_path
def run(self):
"""Ana çalışma fonksiyonu"""
print("=" * 60)
print("🚀 Teknofest Veri Toplama Otomasyonu Başladı")
print("=" * 60)
# Driver başlat
if not self.init_driver():
print("❌ Driver başlatılamadı. Lütfen Chrome'un kurulu olduğundan emin olun.")
return
try:
for season_url in Config.SEASON_URLS:
# Sezon yılını al
season_year = season_url.split('/')[-1]
print(f"\n{'='*60}")
print(f"📅 Sezon: {season_year}")
print(f"{'='*60}")
# Kategoriye git
if not self.navigate_to_category(season_url):
continue
# Yarışmaları bul
competitions = self.get_competitions()
print(f" 📊 {len(competitions)} yarışma bulundu")
# Her yarışmayı işle
for competition in competitions:
self.process_competition(competition, season_year)
except KeyboardInterrupt:
print("\n⚠️ İşlem kullanıcı tarafından durduruldu")
except Exception as e:
print(f"\n❌ Beklenmeyen hata: {e}")
finally:
# Driver kapat
if self.driver:
self.driver.quit()
# Özet
print(f"\n{'='*60}")
print(f"📊 Özet")
print(f"{'='*60}")
print(f"Toplam indirilen: {len(self.downloaded_files)}")
print(f"Çıktı klasörü: {Config.OUTPUT_BASE}")
print("✅ İşlem tamamlandı!")
if __name__ == "__main__":
scraper = TeknofestScraper()
scraper.run()