Untitled

mail@pastecode.io avatar
unknown
python
a month ago
10 kB
3
Indexable
Never
from elems import Elems
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException
import time
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.firefox.options import Options
from selenium import webdriver
from selenium.webdriver.firefox.service import Service as FirefoxService
from webdriver_manager.firefox import GeckoDriverManager
from typing import Optional, Any
from exceptions import ERRORS
from utilities import get_date_from_days, read_csv
import os
import csv
import pandas as pd
from PyQt5.QtWidgets import (QApplication, QWidget, QVBoxLayout, QLabel, QFileDialog,
                             QLineEdit, QCalendarWidget, QPushButton, QCheckBox, QTabWidget, QMessageBox)
from datetime import datetime


class BookingBot(Elems):
    FIELD_NAMES = ["NAME", "PRICE", 'START_DATE', 'END_DATE']

    def __init__(self, driver: webdriver.Firefox) -> None:
        self.driver = driver
        self.errors = []
        self.filename = str(round(time.time(), 0)).replace(".0", "")

    def open_page(self, url) -> Optional[Any]:

        self.driver.get(url)

    def div_control(self):
        try:
            self.wait_element(self.CARD_DIV)
        except NoSuchElementException:
            self.is_continue = False
            self.errors.append({"code": 1000,
                                "message": ERRORS.get(1000)})

    def get_price(self):
        try:
            div = self.driver.find_element(*self.CARD_DIV)
            return div.find_element(*self.PRICE_SPAN).text
        except NoSuchElementException:
            return "Rezervasyon Bulunamadi"

    def record_to_csv(self, data: list):

        if not os.path.exists(f"datas/{self.filename}.csv"):
            with open(f"./datas/{self.filename}.csv", 'w', encoding="utf-8") as f:
                writer = csv.DictWriter(f, fieldnames=self.FIELD_NAMES)
                writer.writeheader()

        with open(f"./datas/{self.filename}.csv", "a+", encoding="utf-8") as f:
            writer = csv.DictWriter(f, fieldnames=self.FIELD_NAMES)
            writer.writerow(
                {"NAME": data[0], "PRICE": data[1], "START_DATE": data[2], "END_DATE": data[3]})

    def wait_element(self, selector, time=10):
        element = WebDriverWait(self.driver, 10).until(
            EC.visibility_of_element_located(
                selector)
        )
        return element

    def close_driver(self):
        self.driver.quit()

    def csv_summary(self, adult_count, child_count, room_count):
        # CSV dosyasını oku
        df = pd.read_csv(f"./datas/{self.filename}.csv")

        # Euro simgesini ve binlik ayracı kaldır
        df['PRICE'] = df['PRICE'].replace({'€': ' '}, regex=True)
        df['PRICE'] = df['PRICE'].str.replace(
            r'(?<=\d)\.(?=\d{3})', '', regex=True)

        # "Rezervasyon Bulunamadı" olanları temizle ve sayısal değere dönüştür
        # Geçersiz değerleri NaN ile değiştirir
        df['PRICE'] = pd.to_numeric(df['PRICE'], errors='coerce')

        # NaN olanları kaldır
        df = df.dropna(subset=['PRICE'])

        # Pozitif fiyatları filtrele
        filtered_df = df[df['PRICE'] > 0]

        if filtered_df.empty:
            print("Filtrelenmiş veri çerçevesi boş. Fiyat verisi içermiyor.")
            return

        # Ortalama fiyat, en düşük ve en yüksek fiyatı hesapla
        average_price = filtered_df['PRICE'].mean()
        min_price = filtered_df['PRICE'].min()
        max_price = filtered_df['PRICE'].max()
        std_dev = filtered_df['PRICE'].std()

        # En düşük ve en yüksek fiyatlı otel isimlerini bulma
        min_price_hotel = filtered_df.loc[filtered_df['PRICE']
                                          == min_price, 'NAME'].values
        max_price_hotel = filtered_df.loc[filtered_df['PRICE']
                                          == max_price, 'NAME'].values

        if min_price_hotel.size == 0 or max_price_hotel.size == 0:
            print("En düşük veya en yüksek fiyatlı otel bilgisi bulunamadı.")
            return

        # İlk otel adını al (Çoğunlukla tek bir otel olur ama bu, birden fazla otel varsa en iyisidir)
        min_price_hotel_name = min_price_hotel[0]
        max_price_hotel_name = max_price_hotel[0]

        # Summary metni oluştur
        summary = (f"\nFiltreler:\nSorgu Tarihi: {datetime.today()}\nYetiskin Sayisi: {adult_count}\nCocuk Sayisi: {child_count}\nOda Sayisi: {room_count}\n\n"
                   f"Ortalama Fiyat: {average_price:.2f}\n"
                   f"Standart Sapma: {std_dev:.2f}\n"
                   f"En Dusuk Fiyat: {min_price:.2f} (En Dusuk Fiyatli Otel: {
            min_price_hotel_name})\n"
            f"En Yuksek Fiyat: {max_price:.2f} (En Yuksek Fiyatli Otel: {max_price_hotel_name})")

        # Sonuçları dosyaya yaz
        with open(f"./datas/{self.filename}.csv", 'a', encoding="utf-8") as file:
            file.write(summary)

    def csv_to_excel(self):
        # CSV dosyasının yolu
        csv_file = f"./datas/{self.filename}.csv"

        # CSV dosyasını pandas ile oku
        df = pd.read_csv(csv_file)

        # Excel dosyasının yolu
        excel_file = f"./datas/{self.filename}.xlsx"

        # CSV'yi Excel'e dönüştür
        df.to_excel(excel_file, index=False)

        # CSV dosyasını sil
        if os.path.exists(csv_file):
            os.remove(csv_file)
        else:
            print(f"{csv_file} bulunamadi.")


def run_bot(adult_count, child_count, room_count, start_date, end_date, background):
    firefox_options = Options()
    firefox_options.set_preference(
        "dom.disable_open_during_load", True)  # Pop-up'ları engelle
    firefox_options.set_preference("dom.webnotifications.enabled", False)

    if background:
        firefox_options.add_argument("--headless")

    driver = webdriver.Firefox(
        service=FirefoxService(GeckoDriverManager().install()),
        options=firefox_options
    )
    driver.maximize_window()
    bot = BookingBot(driver=driver)

    data = read_csv("./new_urls.csv")

    for name, url in data:
        url = url.replace("||start_date||", start_date).replace(
            "||end_date||", end_date).replace(
                "||adult_count||", adult_count).replace(
                "||children_count||", child_count).replace(
                    "||room_count||", room_count)
        bot.open_page(url)
        time.sleep(1)
        if bot.errors:
            price = str(bot.errors)

        else:
            price = bot.get_price()

        bot.record_to_csv([name, price, start_date, end_date])
        time.sleep(2)
    bot.driver.quit()
    bot.csv_summary(adult_count, child_count, room_count)
    bot.csv_to_excel()


def check_inputs():
    adult_count = yetiskin_input.text()
    child_count = cocuk_input.text()
    room_count = oda_input.text()
    start_date = start_calendar.selectedDate().toString("yyyy-MM-dd")
    end_date = end_calendar.selectedDate().toString("yyyy-MM-dd")
    background = background_checkbox.isChecked()

    valid = True

    if not adult_count or not child_count or not room_count:
        QMessageBox.warning(window, 'Hata', 'Tüm alanları doldurun!')
        valid = False

    if end_date < start_date:
        QMessageBox.warning(
            window, 'Hata', 'Çıkış tarihi giriş tarihinden önce olamaz!')
        valid = False
    if valid:
        # run_bot fonksiyonuna takvimden seçilen tarihleri de gönderiyoruz
        run_bot(adult_count, child_count, room_count,
                start_date, end_date, background)
        QMessageBox.information(window, 'Başarılı', 'Bot çalıştırıldı!')
        QApplication.quit()


if __name__ == "__main__":
    app = QApplication([])
    window = QWidget()
    window.setWindowTitle('Booking')

    tab_widget = QTabWidget()

    general_tab = QWidget()
    general_layout = QVBoxLayout()

    # Kaç gün sonrası input alanı
    day_label = QLabel('Kaç gün sonrası: ')
    day_input = QLineEdit()

    # Yetişkin sayısı input alanı
    yetiskin_label = QLabel('Yetişkin sayısı (1-30):')
    yetiskin_input = QLineEdit()

    # Çocuk sayısı input alanı
    cocuk_label = QLabel('Çocuk sayısı (1-10):')
    cocuk_input = QLineEdit()

    # Oda sayısı input alanı
    oda_label = QLabel('Oda sayısı (1-30):')
    oda_input = QLineEdit()

    # Genel bilgileri layout'a ekle
    general_layout.addWidget(yetiskin_label)
    general_layout.addWidget(yetiskin_input)
    general_layout.addWidget(cocuk_label)
    general_layout.addWidget(cocuk_input)
    general_layout.addWidget(oda_label)
    general_layout.addWidget(oda_input)

    general_tab.setLayout(general_layout)

    # İkinci sekme (Tarih Seçimi)
    date_tab = QWidget()
    date_layout = QVBoxLayout()

    # Başlangıç ve bitiş tarihi için QCalendarWidget
    start_calendar_label = QLabel('Başlangıç Tarihi Seçin:')
    start_calendar = QCalendarWidget()
    start_calendar.setGridVisible(True)

    end_calendar_label = QLabel('Bitiş Tarihi Seçin:')
    end_calendar = QCalendarWidget()
    end_calendar.setGridVisible(True)

    # Takvim widget'larını layout'a ekle
    date_layout.addWidget(start_calendar_label)
    date_layout.addWidget(start_calendar)
    date_layout.addWidget(end_calendar_label)
    date_layout.addWidget(end_calendar)

    date_tab.setLayout(date_layout)

    # Üçüncü sekme (Diğer Ayarlar)
    other_tab = QWidget()
    other_layout = QVBoxLayout()

    # Arka planda çalıştırma için QCheckBox
    background_checkbox = QCheckBox("Arka planda çalıştırılsın mı?")

    # Gönder butonu
    submit_button = QPushButton('Gönder')
    submit_button.clicked.connect(check_inputs)

    # Diğer ayarları layout'a ekle
    other_layout.addWidget(background_checkbox)
    other_layout.addWidget(submit_button)

    other_tab.setLayout(other_layout)

    # Sekmeleri QTabWidget'e ekle
    tab_widget.addTab(general_tab, "Genel Bilgiler")
    tab_widget.addTab(date_tab, "Tarih Seçimi")
    tab_widget.addTab(other_tab, "Botu Başlat")

    # Ana layout oluştur ve tab widget'ı ekle
    layout = QVBoxLayout()
    layout.addWidget(tab_widget)

    window.setLayout(layout)
    window.show()
    app.exec_()
Leave a Comment