Built with anycoder

Teknofest Veri Toplama Otomasyonu

Teknofest yarışmalarından İlkokul/Ortaokul kategorisindeki başarılı projelerin raporlarını otomatik olarak indirin ve proje adlarını çıkarın.

1 Sezonları Tara
2 Ortaokul Kategorisi
3 Yarışmaları Bul
4 Raporları İndir
5 PDF'ten Proje Adı Al
teknofest_scraper.py
"""
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()