anycoder-3fba633c / index.html
mhmtx's picture
Upload folder using huggingface_hub
96480d6 verified
Raw History Blame Contribute Delete
39.4 kB
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Teknofest Veri Toplama Otomasyonu</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary: #2563eb;
--primary-dark: #1d4ed8;
--secondary: #7c3aed;
--success: #10b981;
--warning: #f59e0b;
--danger: #ef4444;
--dark: #1e293b;
--light: #f8fafc;
--gray: #64748b;
--card-bg: #ffffff;
--gradient: linear-gradient(135deg, #2563eb 0%, #7c3aed 100%);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Inter', sans-serif;
}
body {
background: linear-gradient(180deg, #0f172a 0%, #1e293b 100%);
min-height: 100vh;
color: #e2e8f0;
}
/* Header */
.header {
background: rgba(15, 23, 42, 0.95);
backdrop-filter: blur(20px);
padding: 1rem 2rem;
position: sticky;
top: 0;
z-index: 100;
border-bottom: 1px solid rgba(255,255,255,0.1);
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
display: flex;
align-items: center;
gap: 0.75rem;
font-weight: 700;
font-size: 1.25rem;
}
.logo-icon {
width: 40px;
height: 40px;
background: var(--gradient);
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.25rem;
}
.header-actions {
display: flex;
gap: 1rem;
align-items: center;
}
.btn {
padding: 0.625rem 1.25rem;
border-radius: 8px;
font-weight: 500;
font-size: 0.875rem;
cursor: pointer;
transition: all 0.2s ease;
border: none;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.btn-primary {
background: var(--gradient);
color: white;
box-shadow: 0 4px 15px rgba(37, 99, 235, 0.3);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(37, 99, 235, 0.4);
}
.btn-outline {
background: transparent;
border: 1px solid rgba(255,255,255,0.2);
color: #e2e8f0;
}
.btn-outline:hover {
background: rgba(255,255,255,0.1);
}
/* Main Container */
.container {
max-width: 1400px;
margin: 0 auto;
padding: 2rem;
}
/* Hero Section */
.hero {
text-align: center;
padding: 3rem 0;
}
.hero h1 {
font-size: 2.5rem;
font-weight: 800;
margin-bottom: 1rem;
background: linear-gradient(135deg, #60a5fa 0%, #a78bfa 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero p {
color: #94a3b8;
font-size: 1.125rem;
max-width: 600px;
margin: 0 auto;
}
/* Process Flow */
.process-flow {
display: flex;
justify-content: center;
gap: 1rem;
margin: 2rem 0;
flex-wrap: wrap;
}
.process-step {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 1rem 1.5rem;
background: rgba(255,255,255,0.05);
border-radius: 12px;
border: 1px solid rgba(255,255,255,0.1);
transition: all 0.3s ease;
}
.process-step:hover {
background: rgba(255,255,0.1);
border-color: rgba(37, 99, 235, 0.5);
transform: translateY(-2px);
}
.step-number {
width: 32px;
height: 32px;
background: var(--gradient);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 0.875rem;
}
.step-arrow {
color: var(--gray);
font-size: 1.25rem;
}
/* Tabs */
.tabs {
display: flex;
gap: 0.5rem;
margin-bottom: 2rem;
background: rgba(255,255,255,0.05);
padding: 0.5rem;
border-radius: 12px;
width: fit-content;
}
.tab {
padding: 0.75rem 1.5rem;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease;
font-weight: 500;
color: #94a3b8;
border: none;
background: transparent;
}
.tab.active {
background: var(--gradient);
color: white;
}
.tab:hover:not(.active) {
background: rgba(255,255,255,0.1);
color: #e2e8f0;
}
/* Code Section */
.code-section {
background: #0d1117;
border-radius: 16px;
overflow: hidden;
border: 1px solid rgba(255,255,255,0.1);
}
.code-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 1.5rem;
background: rgba(255,255,255,0.03);
border-bottom: 1px solid rgba(255,255,255,0.1);
}
.code-title {
display: flex;
align-items: center;
gap: 0.75rem;
font-weight: 600;
}
.code-title i {
color: #f59e0b;
}
.code-content {
padding: 1.5rem;
overflow-x: auto;
}
pre {
font-family: 'Fira Code', 'Consolas', monospace;
font-size: 0.8rem;
line-height: 1.6;
color: #c9d1d9;
white-space: pre-wrap;
word-wrap: break-word;
}
.keyword { color: #ff7b72; }
.string { color: #a5d6ff; }
.function { color: #d2a8ff; }
.comment { color: #8b949e; }
.number { color: #79c0ff; }
.decorator { color: #d2a8ff; }
/* Configuration Panel */
.config-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}
.config-card {
background: rgba(255,255,255,0.05);
border-radius: 12px;
padding: 1.5rem;
border: 1px solid rgba(255,255,255,0.1);
}
.config-card h3 {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1rem;
font-size: 1rem;
color: #e2e8f0;
}
.config-card h3 i {
color: var(--primary);
}
.config-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.75rem 0;
border-bottom: 1px solid rgba(255,255,255,0.05);
}
.config-item:last-child {
border-bottom: none;
}
.config-label {
color: #94a3b8;
font-size: 0.875rem;
}
.config-value {
font-weight: 500;
color: #e2e8f0;
font-family: monospace;
font-size: 0.8rem;
background: rgba(0,0,0,0.3);
padding: 0.25rem 0.5rem;
border-radius: 4px;
}
/* Status Panel */
.status-panel {
background: rgba(255,255,255,0.05);
border-radius: 12px;
padding: 1.5rem;
margin-top: 2rem;
border: 1px solid rgba(255,255,255,0.1);
}
.status-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.status-title {
font-weight: 600;
display: flex;
align-items: center;
gap: 0.5rem;
}
.status-badge {
padding: 0.25rem 0.75rem;
border-radius: 20px;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
}
.status-badge.ready {
background: rgba(16, 185, 129, 0.2);
color: #10b981;
}
.status-badge.running {
background: rgba(245, 158, 11, 0.2);
color: #f59e0b;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.log-container {
background: #0d1117;
border-radius: 8px;
padding: 1rem;
max-height: 300px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 0.75rem;
}
.log-entry {
padding: 0.25rem 0;
display: flex;
gap: 0.75rem;
}
.log-time {
color: #64748b;
}
.log-info { color: #60a5fa; }
.log-success { color: #10b981; }
.log-warning { color: #f59e0b; }
.log-error { color: #ef4444; }
/* Input Fields */
.input-group {
margin-bottom: 1rem;
}
.input-group label {
display: block;
margin-bottom: 0.5rem;
font-size: 0.875rem;
color: #94a3b8;
}
.input-field {
width: 100%;
padding: 0.75rem 1rem;
background: rgba(0,0,0,0.3);
border: 1px solid rgba(255,255,255,0.1);
border-radius: 8px;
color: #e2e8f0;
font-size: 0.875rem;
transition: all 0.2s ease;
}
.input-field:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2);
}
/* Footer */
.footer {
text-align: center;
padding: 2rem;
color: #64748b;
font-size: 0.875rem;
border-top: 1px solid rgba(255,255,255,0.1);
margin-top: 3rem;
}
.footer a {
color: var(--primary);
text-decoration: none;
}
.footer a:hover {
text-decoration: underline;
}
/* Responsive */
@media (max-width: 768px) {
.header {
padding: 1rem;
}
.container {
padding: 1rem;
}
.hero h1 {
font-size: 1.75rem;
}
.process-flow {
flex-direction: column;
}
.step-arrow {
display: none;
}
.tabs {
width: 100%;
overflow-x: auto;
}
}
/* Copy Button */
.copy-btn {
position: absolute;
right: 1rem;
top: 50%;
transform: translateY(-50%);
padding: 0.5rem 1rem;
background: var(--primary);
border: none;
border-radius: 6px;
color: white;
cursor: pointer;
font-size: 0.75rem;
display: flex;
align-items: center;
gap: 0.5rem;
transition: all 0.2s ease;
}
.copy-btn:hover {
background: var(--primary-dark);
}
.code-wrapper {
position: relative;
}
/* Scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: rgba(0,0,0,0.2);
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: rgba(255,255,255,0.2);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255,255,255,0.3);
}
</style>
</head>
<body>
<header class="header">
<div class="logo">
<div class="logo-icon">
<i class="fas fa-rocket"></i>
</div>
<span>Teknofest Otomasyon</span>
</div>
<div class="header-actions">
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="color: #94a3b8; text-decoration: none; font-size: 0.875rem;">
Built with anycoder
</a>
</div>
</header>
<div class="container">
<div class="hero">
<h1>Teknofest Veri Toplama Otomasyonu</h1>
<p>Teknofest yarışmalarından İlkokul/Ortaokul kategorisindeki başarılı projelerin raporlarını otomatik olarak indirin ve proje adlarını çıkarın.</p>
</div>
<!-- Process Flow -->
<div class="process-flow">
<div class="process-step">
<span class="step-number">1</span>
<span>Sezonları Tara</span>
</div>
<i class="fas fa-chevron-right step-arrow"></i>
<div class="process-step">
<span class="step-number">2</span>
<span>Ortaokul Kategorisi</span>
</div>
<i class="fas fa-chevron-right step-arrow"></i>
<div class="process-step">
<span class="step-number">3</span>
<span>Yarışmaları Bul</span>
</div>
<i class="fas fa-chevron-right step-arrow"></i>
<div class="process-step">
<span class="step-number">4</span>
<span>Raporları İndir</span>
</div>
<i class="fas fa-chevron-right step-arrow"></i>
<div class="process-step">
<span class="step-number">5</span>
<span>PDF'ten Proje Adı Al</span>
</div>
</div>
<!-- Tabs -->
<div class="tabs">
<button class="tab active" onclick="showTab('script')">
<i class="fas fa-code"></i> Python Script
</button>
<button class="tab" onclick="showTab('config')">
<i class="fas fa-cog"></i> Yapılandırma
</button>
<button class="tab" onclick="showTab('guide')">
<i class="fas fa-book"></i> Kullanım Kılavuzu
</button>
</div>
<!-- Script Tab -->
<div id="script" class="tab-content">
<div class="code-section">
<div class="code-header">
<div class="code-title">
<i class="fab fa-python"></i>
teknofest_scraper.py
</div>
<button class="btn btn-primary" onclick="copyScript()">
<i class="fas fa-copy"></i> Kopyala
</button>
</div>
<div class="code-content">
<div class="code-wrapper">
<pre id="python-script">"""
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()</pre>
</div>
</div>
</div>
</div>
<!-- Config Tab -->
<div id="config" class="tab-content" style="display: none;">
<div class="config-grid">
<div class="config-card">
<h3><i class="fas fa-folder"></i> Chrome Ayarları</h3>
<div class="config-item">
<span class="config-label">Chrome Path</span>
<span class="config-value">C:\Program Files\Google\Chrome\Application\chrome.exe</span>
</div>
<div class="config-item">
<span class="config-label">Driver Mode</span>
<span class="config-value">Headless</span>
</div>
<div class="config-item">
<span class="config-label">Download Prompt</span>
<span class="config-value">Disabled</span>
</div>
</div>
<div class="config-card">
<h3><i class="fas fa-eye"></i> OCR Ayarları</h3>
<div class="config-item">
<span class="config-label">Tesseract Path</span>
<span class="config-value">C:\Users\mhmtx\AppData\Local\Programs\Tesseract-OCR</span>
</div>
<div class="config-item">
<span class="config-label">OCR Language</span>
<span class="config-value">Turkish (tur)</span>
</div>
<div class="config-item">
<span class="config-label">Poppler Path</span>
<span class="config-value">D:\teknofest\poppler-25.12.0\Library\bin</span>
</div>
</div>
<div class="config-card">
<h3><i class="fas fa-download"></i> İndirme Ayarları</h3>
<div class="config-item">
<span class="config-label">Output Base</span>
<span class="config-value">D:\teknofest\output</span>
</div>
<div class="config-item">
<span class="config-label">Timeout</span>
<span class="config-value">120 seconds</span>
</div>
<div class="config-item">
<span class="config-label">Max Retries</span>
<span class="config-value">3</span>
</div>
</div>
<div class="config-card">
<h3><i class="fas fa-globe"></i> Sezon URL'leri</h3>
<div class="config-item">
<span class="config-label">2025</span>
<span class="config-value">Active</span>
</div>
<div class="config-item">
<span class="config-label">2024</span>
<span class="config-value">Active</span>
</div>
<div class="config-item">
<span class="config-label">2023-2019</span>
<span class="config-value">Active</span>
</div>
</div>
</div>
<div class="config-card">
<h3><i class="fas fa-folder-tree"></i> Klasör Yapısı Örneği</h3>
<pre style="margin-top: 1rem; color: #94a3b8; font-size: 0.85rem;">D:\teknofest\output\
├── 2025\
│ ├── İnsanlık Yararına Teknoloji\
│ │ ├── Afet Yönetimi\
│ │ │ ├── Deprem Erken Uyarı Sistemi - Derece.pdf
│ │ │ └── Acil Kurtarma Drone - Başarılı.pdf
│ │ ├── İnovasyon\
│ │ │ └── Akıllı Tarım Sistemi - Derece.pdf
│ │ └── Sağlık\
│ │ └── Sağlık Takip App - Finalist.pdf
│ └── ...
├── 2024\
│ └── ...
└── ...</pre>
</div>
</div>
<!-- Guide Tab -->
<div id="guide" class="tab-content" style="display: none;">
<div class="config-grid">
<div class="config-card">
<h3><i class="fas fa-step-forward"></i> Adım 1: Kurulum</h3>
<p style="color: #94a3b8; font-size: 0.9rem; line-height: 1.6;">
Python kütüphanelerini yükleyin:<br><br>
<code style="background: rgba(0,0,0,0.3); padding: 0.25rem 0.5rem; border-radius: 4px;">pip install selenium requests pytesseract pdf2image python-docx PyPDF2</code>
</p>
</div>
<div class="config-card">
<h3><i class="fas fa-folder"></i> Adım 2: ChromeDriver</h3>
<p style="color: #94a3b8; font-size: 0.9rem; line-height: 1.6;">
ChromeDriver'ı <a href="https://chromedriver.chromium.org/" target="_blank" style="color: var(--primary);">chromedriver.chromium.org</a> adresinden indirin ve path'e ekleyin.
</p>
</div>
<div class="config-card">
<h3><i class="fas fa-cog"></i> Adım 3: Tesseract OCR</h3>
<p style="color: #94a3b8; font-size: 0.9rem; line-height: 1.6;">
Tesseract OCR'ı <a href="https://github.com/UB-Mannheim/tesseract/wiki" target="_blank" style="color: var(--primary);">buradan</a> indirin ve Turkish language pack ekleyin.
</p>
</div>
<div class="config-card">
<h3><i class="fas fa-play"></i> Adım 4: Çalıştırma</h3>
<p style="color: #94a3b8; font-size: 0.9rem; line-height: 1.6;">
Scripti çalıştırın:<br><br>
<code style="background: rgba(0,0,0,0.3); padding: 0.25rem 0.5rem; border-radius: 4px;">python teknofest_scraper.py</code>
</p>
</div>
</div>
<div class="config-card">
<h3><i class="fas fa-info-circle"></