Python ile LC Waikiki indirim dedektörü nasıl yapılır?

mrcbrbn

Hectopat
Katılım
11 Eylül 2020
Mesajlar
159
Çözümler
1
GitHub'da Zara indirim dedektörü diye bir Python projesi buldum, bu proje Tolga Bıyık tarafından yapıldı ben bu projeyi değiştirmek istediğim için ve kendisinin yoğun bir zamanı olduğu zorlanıyorum, bildiğiniz üzere Zara boykot ürünü ve birçok kişi bu yüzden LC Waikiki ve DeFacto üzerinden alışveriş yapmaya yöneliyor ben de bunun için bu projeyi LC Waikiki ve DeFacto'ya özel olarak yapmak istiyorum, bana yardımcı olabilir misiniz?
 
Kod:
import json
import requests
import pandas as pd
from flask import Flask, render_template, request, send_from_directory
import threading
import os

app = Flask(__name__)

# Sabitler (Constants)
DEFAULT_PRODUCT_COUNT = 24
TIMEOUT = 15 # Bağlantı zaman aşımı süresi (saniye)
EXCEL_FILE_NAME = "urunler.xlsx"

# Kategori Linkleri ve ID'leri
CATEGORY_LINKS = {
 "Kadın": {
 "Tüm Kadın Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1",
 "Tişört": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1413",
 "Gömlek": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1414",
 "Bluz": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1415",
 "Elbise": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1416",
 "Pantolon": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1417",
 "Etek": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1418",
 "Şort": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1419",
 "Ceket": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1420",
 "Hırka & Triko": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1421",
 "Sweatshirt": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1422",
 "Mont": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1423",
 "Trençkot": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1718",
 "Jean": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1424",
 "Tayt": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1730",
 "Tulum": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1459",
 "İç Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1430",
 "Pijama & Ev Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1432",
 "Mayo & Bikini": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1431",
 "Büyük Beden": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1451",
 "Hamile Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1658",
 "Aksesuar": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1434",
 "Ayakkabı": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1674",
 "Çanta": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1435",
 "Spor Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1610",
 "Abiye": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1741"
 },
 "Erkek": {
 "Tüm Erkek Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2",
 "Tişört": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1438",
 "Gömlek": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1439",
 "Polo Yaka Tişört": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1440",
 "Pantolon": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1441",
 "Şort": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1442",
 "Ceket": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1443",
 "Hırka & Triko": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1444",
 "Sweatshirt": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1445",
 "Mont": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1446",
 "Jean": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1447",
 "İç Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1449",
 "Pijama & Ev Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1450",
 "Aksesuar": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1452",
 "Ayakkabı": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1676",
 "Spor Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1611",
 "Büyük Beden": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1672"
 },
 "Çocuk": {
 "Tüm Çocuk Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3",
 "Bebek (0-24 Ay) Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1454",
 "Kız Çocuk Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1455",
 "Erkek Çocuk Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1456",
 "İç Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1457",
 "Pijama & Ev Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1458",
 "Ayakkabı": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1678",
 "Aksesuar": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1460",
 "Okul Koleksiyonu": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1700",
 "Lisanslı Ürünler": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1733"
 }
}

# Sıralama Seçenekleri
SORT_OPTIONS = {
 "Varsayılan": 0,
 "En Düşük Fiyat": 1,
 "En Yüksek Fiyat": 2,
 "Çok Satanlar": 4,
 "Yeni Eklenenler": 5
}

# Global değişkenler
old_products = pd.DataFrame()
products = []
selected_category_link = None
selected_sort_order = 0

# HTML şablonu (index.html) - GÜNCELLENDİ
HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
 <title>Defacto İndirim Takip</title>
 <style>
 body {
 font-family: 'Roboto', sans-serif;
 margin: 20px;
 background-color: #f8f9fa;
 color: #343a40;
 }
 .container {
 max-width: 1200px;
 margin: 0 auto;
 padding: 20px;
 }
 h1, h2 {
 color: #2c3e50;
 text-align: center;
 margin-bottom: 30px;
 }
 /* Form ve buton stilleri */
 .form-group {
 display: flex;
 align-items: center;
 margin-bottom: 15px;
 justify-content: center;
 }
 .form-group label {
 margin-right: 10px;
 font-weight: bold;
 }
 input[type="number"] {
 width: 80px;
 padding: 8px;
 border: 1px solid #ced4da;
 border-radius: 4px;
 text-align: center;
 }
 .button-group {
 display: flex;
 justify-content: center;
 margin-bottom: 20px;
 gap: 10px;
 }
 .button-group button {
 background-color: #3498db;
 color: white;
 padding: 12px 24px;
 border: none;
 border-radius: 6px;
 cursor: pointer;
 transition: background-color 0.3s ease;
 }
 .button-group button:hover {
 background-color: #2980b9;
 }
 .button-group button:active {
 background-color: #2471a3;
 }
 #message {
 margin-top: 10px;
 margin-bottom: 10px;
 padding: 10px;
 border-radius: 4px;
 font-weight: bold;
 text-align: center;
 color: #27ae60;
 background-color: #dff0d8;
 border: 1px solid #d0e9c6;
 }
 /* Tablo stilleri */
 table {
 border-collapse: collapse;
 width: 100%;
 box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
 border-radius: 8px;
 overflow: hidden;
 margin-top: 20px;
 }
 th, td {
 text-align: left;
 padding: 15px;
 border-bottom: 1px solid #e0e0e0;
 }
 th {
 background-color: #34495e;
 color: white;
 font-weight: bold;
 }
 tr:nth-child(even) {
 background-color: #f9f9f9;
 }
 tr:hover {
 background-color: #ecf0f1;
 }
 .error {
 color: red;
 text-align: center;
 margin-top: 10px;
 margin-bottom: 10px;
 }
 /* Dosya Yükleme Stili */
 #fileInput {
 display: none; /* Dosya seçme alanını gizle */
 }
 #upload-message {
 margin-top: 10px;
 margin-bottom: 10px;
 padding: 10px;
 border-radius: 4px;
 font-weight: bold;
 text-align: center;
 color: #27ae60;
 background-color: #dff0d8;
 border: 1px solid #d0e9c6;
 }

 /* Kategori Seçimi Stili */
 .select-group {
 display: flex;
 justify-content: center;
 margin-bottom: 20px;
 }
 .select-group select {
 padding: 10px;
 border: 1px solid #ced4da;
 border-radius: 4px;
 }
 /* Seçenek stili */
 select option {
 padding: 8px;
 }

 select option:hover {
 background-color: #e2e6ea; /* Seçenek üzerine gelindiğinde */
 }
 /* Sıralama Seçimi Stili */
 .sort-group {
 display: flex;
 justify-content: center;
 margin-bottom: 20px;
 }
 .sort-group select {
 padding: 10px;
 border: 1px solid #ced4da;
 border-radius: 4px;
 }

 </style>
</head>
<body>
 <div class="container">
 <h1>Defacto İndirimli Ürünler</h1>
 <div class="select-group">
 <label for="categorySelect">Kategori Seç:</label>
 <select id="categorySelect">
 <optgroup label="Kadın">
 {% for category, link in category_links['Kadın'].items() %}
 <option value="{{link}}">{{category}}</option>
 {% endfor %}
 </optgroup>
 <optgroup label="Erkek">
 {% for category, link in category_links['Erkek'].items() %}
 <option value="{{link}}">{{category}}</option>
 {% endfor %}
 </optgroup>
 <optgroup label="Çocuk">
 {% for category, link in category_links['Çocuk'].items() %}
 <option value="{{link}}">{{category}}</option>
 {% endfor %}
 </optgroup>
 </select>
 </div>
 <div class="sort-group">
 <label for="sortSelect">Sıralama Seç:</label>
 <select id="sortSelect">
 {% for key, value in sort_options.items() %}
 <option value="{{value}}">{{key}}</option>
 {% endfor %}
 </select>
 </div>
 <div class="form-group">
 <label for="product_count">Kaç ürün çekmek istersiniz?</label>
 <input type="number" id="product_count" name="product_count" value="24">
 </div>
 <div class="button-group">
 <button onclick="fetchData()">İndirimli Ürünleri Çek</button>
 <button onclick="saveToExcel()">Excel'e Kaydet</button>
 <button onclick="uploadExcel()">Excel Dosyasını Yükle</button>
 <button onclick="checkForDiscounts()">İndirimleri Kontrol Et</button>
 </div>
 <input type="file" name="file" id="fileInput">
 <p id="upload-message"></p>
 <p id="message"></p>
 <div id="products">
 <h2>Ürünler</h2>
 <table>
 <thead>
 <tr>
 <th>Ürün Adı</th>
 <th>İndirim</th>
 <th>Normal Fiyat</th>
 </tr>
 </thead>
 <tbody id="product_list">
 <!-- Ürünler buraya eklenecek -->
 </tbody>
 </table>
 </div>

 </div>

 <script>
 let selectedCategoryLink = null;
 let selectedSortOrder = 0;
 document.addEventListener('DOMContentLoaded', function() {
 const categorySelect = document.getElementById('categorySelect');
 const sortSelect = document.getElementById('sortSelect');
 selectedCategoryLink = categorySelect.value; // Default value
 selectedSortOrder = sortSelect.value;
 categorySelect.addEventListener('change', function() {
 selectedCategoryLink = this.value;
 });
 sortSelect.addEventListener('change', function() {
 selectedSortOrder = this.value;
 });
 });
 function fetchData() {
 if (!selectedCategoryLink) {
 document.getElementById("message").innerHTML = "Lütfen bir kategori seçin.";
 return;
 }

 var productCount = document.getElementById("product_count").value;
 document.getElementById("message").innerHTML = "Veriler çekiliyor...";
 fetch('/fetch_data?product_count=' + productCount + '&category_link=' + encodeURIComponent(selectedCategoryLink)+ '&sort_order=' + encodeURIComponent(selectedSortOrder))
 .then(response => response.json())
 .then(data => {
 document.getElementById("message").innerHTML = data.message;
 var productList = document.getElementById("product_list");
 productList.innerHTML = "";
 if (data.products && data.products.length > 0) {
 data.products.forEach(product => {
 var row = productList.insertRow();
 var cell1 = row.insertCell();
 var cell2 = row.insertCell();
 var cell3 = row.insertCell();
 cell1.innerHTML = product.name;
 cell2.innerHTML = product.discount;
 cell3.innerHTML = product.normalPrice;
 });
 } else{
 document.getElementById("message").innerHTML = "Seçilen kategoride indirimli ürün bulunamadı.";
 }
 })
 .catch(error => {
 document.getElementById("message").innerHTML = "Hata: " + error;
 });
 }

 function saveToExcel() {
 document.getElementById("message").innerHTML = "Excel'e kaydediliyor...";
 fetch('/save_to_excel')
 .then(response => response.json())
 .then(data => {
 document.getElementById("message").innerHTML = data.message;
 })
 .catch(error => {
 document.getElementById("message").innerHTML = "Hata: " + error;
 });
 }

 function checkForDiscounts() {
 document.getElementById("message").innerHTML = "İndirimler kontrol ediliyor...";
 fetch('/check_for_discounts?category_link=' + encodeURIComponent(selectedCategoryLink)+ '&sort_order=' + encodeURIComponent(selectedSortOrder))
 .then(response => response.json())
 .then(data => {
 document.getElementById("message").innerHTML = data.message;
 })
 .catch(error => {
 document.getElementById("message").innerHTML = "Hata: " + error;
 });
 }
 function uploadExcel() {
 document.getElementById('fileInput').click(); // Dosya seçme alanını tetikle
 }

 document.getElementById('fileInput').addEventListener('change', function() {
 var file = this.files[0];
 var formData = new FormData();
 formData.append('file', file);
 document.getElementById("upload-message").innerHTML = "Dosya yükleniyor...";
 fetch('/upload_excel', {
 method: 'POST',
 body: formData
 })
 .then(response => response.json())
 .then(data => {
 document.getElementById("upload-message").innerHTML = data.message;
 if (!data.error){
 checkForDiscounts();
 }

 })
 .catch(error => {
 document.getElementById("upload-message").innerHTML = "Hata: " + error;
 });

 });
 </script>
</body>
</html>
"""

# Dosya yükleme formu ve ana sayfa artık aynı yerde
@app.route("/")
def index():
 return render_template_string(HTML_TEMPLATE, category_links=CATEGORY_LINKS,sort_options = SORT_OPTIONS)

# Veri çekme fonksiyonu
@app.route("/fetch_data")
def fetch_data():
 global products
 try:
 max_products = int(request.args.get('product_count', DEFAULT_PRODUCT_COUNT))
 category_link = request.args.get('category_link')
 sort_order = int(request.args.get('sort_order', 0))

 if not category_link:
 return {"message": "Kategori linki bulunamadı.", "products": []}

 url = category_link.replace("{pageSize}", str(max_products)).replace("{sortOrder}",str(sort_order))

 response = requests.get(url, timeout=TIMEOUT)
 response.raise_for_status()
 api_response = response.json()
 products = filter_discounted_products(api_response, max_products)

 return {"message": "Veriler çekildi.", "products": products}
 except (ValueError, requests.exceptions.RequestException, json.JSONDecodeError) as e:
 return {"message": f"Hata: {e}", "products": []}

# Excel'e kaydetme fonksiyonu
@app.route("/save_to_excel")
def save_to_excel():
 global products
 try:
 if products:
 df = pd.DataFrame(products)
 df.to_excel(EXCEL_FILE_NAME, index=False)
 return {"message": f"Veriler {EXCEL_FILE_NAME} dosyasına kaydedildi."}
 else:
 return {"message": "Kaydedilecek veri yok.", "error": True}
 except Exception as e:
 return {"message": f"Kaydetme hatası: {e}", "error": True}

# İndirim kontrol fonksiyonu
@app.route("/check_for_discounts")
def check_for_discounts():
 global old_products
 if old_products.empty:
 return {"message": "Lütfen önce Excel dosyasını yükleyin.", "error": True}

 try:
 max_products = int(request.args.get('product_count', DEFAULT_PRODUCT_COUNT))
 category_link = request.args.get('category_link', None)
 sort_order = int(request.args.get('sort_order', 0))
 if not category_link:
 return {"message": "Lütfen bir kategori seçin.", "error": True}

 url = category_link.replace("{pageSize}", str(max_products)).replace("{sortOrder}",str(sort_order))
 response = requests.get(url, timeout=TIMEOUT)
 response.raise_for_status()
 current_products = filter_discounted_products(response.json(), max_products)

 changes_message = ""
 for old_product in old_products.to_dict('records'):
 if matching_current_product := next((p for p in current_products if p['name'] == old_product['name']), None):
 if matching_current_product['discount'] > 0:
 changes_message += (f"Ürün: {old_product['name']}\n"
 f"Eski Fiyat: {old_product['normalPrice']}\n"
 f"Güncel İndirim: {matching_current_product['discount']}\n\n")

 if changes_message:
 return {"message": changes_message}
 else:
 return {"message": "İndirim değişikliği bulunamadı."}

 except (ValueError, requests.exceptions.RequestException, json.JSONDecodeError) as e:
 return {"message": f"Hata: {e}", "error": True}
 except Exception as e:
 return {"message": f"Bir hata oluştu: {e}", "error": True}

# İndirimli ürünleri filtreleyen fonksiyon - GÜNCELLENDİ
def filter_discounted_products(api_data, max_products):
 discounted_products = []
 product_count = 0
 if "Data" in api_data and "SearchResponse" in api_data["Data"]:
 for product in api_data["Data"]["SearchResponse"]["Documents"]:
 if product_count >= max_products:
 break
 campaign = product.get("CampaignBadge")
 if campaign and campaign and "DiscountAmount" in campaign:
 discounted_products.append({
 "name": product.get("ProductName", "Unknown"),
 "discount": campaign["DiscountAmount"],
 "normalPrice": product.get("ProductPriceInclTax", 0)
 })
 product_count += 1
 return discounted_products

# Excel dosyasını yükleme fonksiyonu
@app.route('/upload_excel', methods=['POST'])
def upload_excel():
 global old_products
 try:
 if 'file' not in request.files:
 return {"message": "Dosya seçilmedi.", "error": True}
 file = request.files['file']
 if file.filename == '':
 return {"message": "Dosya seçilmedi.", "error": True}
 if file:
 old_products = pd.read_excel(file)
 if not {'name', 'normalPrice'}.issubset(old_products.columns):
 return {"message": "Excel dosyasında 'name' ve 'normalPrice' sütunları bulunamadı.", "error": True}
 return {"message": "Excel dosyası başarıyla yüklendi."}
 except Exception as e:
 return {"message": f"Excel dosyası yüklenirken bir hata oluştu: {e}", "error": True}

from flask import render_template_string

if __name__ == "__main__":
 # Uygulamayı ayrı bir iş parçacığında (thread) çalıştır
 def run_app():
 app.run(host='0.0.0.0', port=8081, debug=True, use_reloader=False)

 thread = threading.Thread(target=run_app)
 thread.daemon = True # Ana iş parçacığı sonlandığında bu iş parçacığının da sonlanmasını sağla
 thread.start()

 # Pydroid3'te ana iş parçacığının çalışmaya devam etmesini sağlamak için bir döngü ekleyin
 # (Aksi takdirde uygulama hemen kapanır)
 while True:
 import time
 time.sleep(1)

Bu kodda linklerden veri çekilmiyor bana yardımcı olur musun?
 
Son düzenleme:
Hata bildirimi eklesene. Sebebini veya hatanın yerini görelim. Kim o kadar kodu sana düzenleyiverecek.

Python:
Traceback (most recent call last):
 File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 31, in <module>
 start(fakepyfile,mainpyfile)
 File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 30, in start.
 exec(open(mainpyfile).read(), __main__.__dict__)
 File "<string>", line 420.
 max_products = int(request.args.get('product_count', DEFAULT_PRODUCT_COUNT))
 ^
IndentationError: expected an indented block after 'try' statement on line 419.

[Program finished]

Verdiğim kodda bu hata var ama sorun şu PC kullanmadığım için koddaki kategorilerin doğru linkini bulamıyorum ve mecburen ChatGPT ile yaptım doğru promptu giremediğim için böyle oluyor.
 
419 numaralı satırda girinti hatası varmış. Oradan düzeltmeye başla. Linkler doğru değilse yapılacak bir şey de yok. Linkler her ürün değiştiğinde değişebilir.
 
Kod:
import json
import requests
import pandas as pd
from flask import Flask, render_template, request, send_from_directory
import threading
import os

app = Flask(__name__)

# Sabitler (Constants)
DEFAULT_PRODUCT_COUNT = 24
TIMEOUT = 15 # Bağlantı zaman aşımı süresi (saniye)
EXCEL_FILE_NAME = "urunler.xlsx"

# Kategori Linkleri ve ID'leri
CATEGORY_LINKS = {
 "Kadın": {
 "Tüm Kadın Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1",
 "Tişört": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1413",
 "Gömlek": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1414",
 "Bluz": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1415",
 "Elbise": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1416",
 "Pantolon": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1417",
 "Etek": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1418",
 "Şort": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1419",
 "Ceket": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1420",
 "Hırka & Triko": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1421",
 "Sweatshirt": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1422",
 "Mont": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1423",
 "Trençkot": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1718",
 "Jean": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1424",
 "Tayt": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1730",
 "Tulum": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1459",
 "İç Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1430",
 "Pijama & Ev Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1432",
 "Mayo & Bikini": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1431",
 "Büyük Beden": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1451",
 "Hamile Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1658",
 "Aksesuar": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1434",
 "Ayakkabı": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1674",
 "Çanta": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1435",
 "Spor Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1610",
 "Abiye": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=1&fx_c2=1741"
 },
 "Erkek": {
 "Tüm Erkek Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2",
 "Tişört": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1438",
 "Gömlek": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1439",
 "Polo Yaka Tişört": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1440",
 "Pantolon": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1441",
 "Şort": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1442",
 "Ceket": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1443",
 "Hırka & Triko": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1444",
 "Sweatshirt": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1445",
 "Mont": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1446",
 "Jean": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1447",
 "İç Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1449",
 "Pijama & Ev Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1450",
 "Aksesuar": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1452",
 "Ayakkabı": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1676",
 "Spor Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1611",
 "Büyük Beden": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=2&fx_c2=1672"
 },
 "Çocuk": {
 "Tüm Çocuk Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3",
 "Bebek (0-24 Ay) Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1454",
 "Kız Çocuk Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1455",
 "Erkek Çocuk Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1456",
 "İç Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1457",
 "Pijama & Ev Giyim": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1458",
 "Ayakkabı": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1678",
 "Aksesuar": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1460",
 "Okul Koleksiyonu": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1700",
 "Lisanslı Ürünler": "https://www.defacto.com.tr/Catalog/PartialIndexScrollResult?page=1&SortOrder={sortOrder}&pageSize={pageSize}&fx_c1=3&fx_c2=1733"
 }
}

# Sıralama Seçenekleri
SORT_OPTIONS = {
 "Varsayılan": 0,
 "En Düşük Fiyat": 1,
 "En Yüksek Fiyat": 2,
 "Çok Satanlar": 4,
 "Yeni Eklenenler": 5
}

# Global değişkenler
old_products = pd.DataFrame()
products = []
selected_category_link = None
selected_sort_order = 0

# HTML şablonu (index.html) - GÜNCELLENDİ
HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
 <title>Defacto İndirim Takip</title>
 <style>
 body {
 font-family: 'Roboto', sans-serif;
 margin: 20px;
 background-color: #f8f9fa;
 color: #343a40;
 }
 .container {
 max-width: 1200px;
 margin: 0 auto;
 padding: 20px;
 }
 h1, h2 {
 color: #2c3e50;
 text-align: center;
 margin-bottom: 30px;
 }
 /* Form ve buton stilleri */
 .form-group {
 display: flex;
 align-items: center;
 margin-bottom: 15px;
 justify-content: center;
 }
 .form-group label {
 margin-right: 10px;
 font-weight: bold;
 }
 input[type="number"] {
 width: 80px;
 padding: 8px;
 border: 1px solid #ced4da;
 border-radius: 4px;
 text-align: center;
 }
 .button-group {
 display: flex;
 justify-content: center;
 margin-bottom: 20px;
 gap: 10px;
 }
 .button-group button {
 background-color: #3498db;
 color: white;
 padding: 12px 24px;
 border: none;
 border-radius: 6px;
 cursor: pointer;
 transition: background-color 0.3s ease;
 }
 .button-group button:hover {
 background-color: #2980b9;
 }
 .button-group button:active {
 background-color: #2471a3;
 }
 #message {
 margin-top: 10px;
 margin-bottom: 10px;
 padding: 10px;
 border-radius: 4px;
 font-weight: bold;
 text-align: center;
 color: #27ae60;
 background-color: #dff0d8;
 border: 1px solid #d0e9c6;
 }
 /* Tablo stilleri */
 table {
 border-collapse: collapse;
 width: 100%;
 box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
 border-radius: 8px;
 overflow: hidden;
 margin-top: 20px;
 }
 th, td {
 text-align: left;
 padding: 15px;
 border-bottom: 1px solid #e0e0e0;
 }
 th {
 background-color: #34495e;
 color: white;
 font-weight: bold;
 }
 tr:nth-child(even) {
 background-color: #f9f9f9;
 }
 tr:hover {
 background-color: #ecf0f1;
 }
 .error {
 color: red;
 text-align: center;
 margin-top: 10px;
 margin-bottom: 10px;
 }
 /* Dosya Yükleme Stili */
 #fileInput {
 display: none; /* Dosya seçme alanını gizle */
 }
 #upload-message {
 margin-top: 10px;
 margin-bottom: 10px;
 padding: 10px;
 border-radius: 4px;
 font-weight: bold;
 text-align: center;
 color: #27ae60;
 background-color: #dff0d8;
 border: 1px solid #d0e9c6;
 }

 /* Kategori Seçimi Stili */
 .select-group {
 display: flex;
 justify-content: center;
 margin-bottom: 20px;
 }
 .select-group select {
 padding: 10px;
 border: 1px solid #ced4da;
 border-radius: 4px;
 }
 /* Seçenek stili */
 select option {
 padding: 8px;
 }

 select option:hover {
 background-color: #e2e6ea; /* Seçenek üzerine gelindiğinde */
 }
 /* Sıralama Seçimi Stili */
 .sort-group {
 display: flex;
 justify-content: center;
 margin-bottom: 20px;
 }
 .sort-group select {
 padding: 10px;
 border: 1px solid #ced4da;
 border-radius: 4px;
 }

 </style>
</head>
<body>
 <div class="container">
 <h1>Defacto İndirimli Ürünler</h1>
 <div class="select-group">
 <label for="categorySelect">Kategori Seç:</label>
 <select id="categorySelect">
 <optgroup label="Kadın">
 {% for category, link in category_links['Kadın'].items() %}
 <option value="{{link}}">{{category}}</option>
 {% endfor %}
 </optgroup>
 <optgroup label="Erkek">
 {% for category, link in category_links['Erkek'].items() %}
 <option value="{{link}}">{{category}}</option>
 {% endfor %}
 </optgroup>
 <optgroup label="Çocuk">
 {% for category, link in category_links['Çocuk'].items() %}
 <option value="{{link}}">{{category}}</option>
 {% endfor %}
 </optgroup>
 </select>
 </div>
 <div class="sort-group">
 <label for="sortSelect">Sıralama Seç:</label>
 <select id="sortSelect">
 {% for key, value in sort_options.items() %}
 <option value="{{value}}">{{key}}</option>
 {% endfor %}
 </select>
 </div>
 <div class="form-group">
 <label for="product_count">Kaç ürün çekmek istersiniz?</label>
 <input type="number" id="product_count" name="product_count" value="24">
 </div>
 <div class="button-group">
 <button onclick="fetchData()">İndirimli Ürünleri Çek</button>
 <button onclick="saveToExcel()">Excel'e Kaydet</button>
 <button onclick="uploadExcel()">Excel Dosyasını Yükle</button>
 <button onclick="checkForDiscounts()">İndirimleri Kontrol Et</button>
 </div>
 <input type="file" name="file" id="fileInput">
 <p id="upload-message"></p>
 <p id="message"></p>
 <div id="products">
 <h2>Ürünler</h2>
 <table>
 <thead>
 <tr>
 <th>Ürün Adı</th>
 <th>İndirim</th>
 <th>Normal Fiyat</th>
 </tr>
 </thead>
 <tbody id="product_list">
 <!-- Ürünler buraya eklenecek -->
 </tbody>
 </table>
 </div>

 </div>

 <script>
 let selectedCategoryLink = null;
 let selectedSortOrder = 0;
 document.addEventListener('DOMContentLoaded', function() {
 const categorySelect = document.getElementById('categorySelect');
 const sortSelect = document.getElementById('sortSelect');
 selectedCategoryLink = categorySelect.value; // Default value
 selectedSortOrder = sortSelect.value;
 categorySelect.addEventListener('change', function() {
 selectedCategoryLink = this.value;
 });
 sortSelect.addEventListener('change', function() {
 selectedSortOrder = this.value;
 });
 });
 function fetchData() {
 if (!selectedCategoryLink) {
 document.getElementById("message").innerHTML = "Lütfen bir kategori seçin.";
 return;
 }

 var productCount = document.getElementById("product_count").value;
 document.getElementById("message").innerHTML = "Veriler çekiliyor...";
 fetch('/fetch_data?product_count=' + productCount + '&category_link=' + encodeURIComponent(selectedCategoryLink)+ '&sort_order=' + encodeURIComponent(selectedSortOrder))
 .then(response => response.json())
 .then(data => {
 document.getElementById("message").innerHTML = data.message;
 var productList = document.getElementById("product_list");
 productList.innerHTML = "";
 if (data.products && data.products.length > 0) {
 data.products.forEach(product => {
 var row = productList.insertRow();
 var cell1 = row.insertCell();
 var cell2 = row.insertCell();
 var cell3 = row.insertCell();
 cell1.innerHTML = product.name;
 cell2.innerHTML = product.discount;
 cell3.innerHTML = product.normalPrice;
 });
 } else{
 document.getElementById("message").innerHTML = "Seçilen kategoride indirimli ürün bulunamadı.";
 }
 })
 .catch(error => {
 document.getElementById("message").innerHTML = "Hata: " + error;
 });
 }

 function saveToExcel() {
 document.getElementById("message").innerHTML = "Excel'e kaydediliyor...";
 fetch('/save_to_excel')
 .then(response => response.json())
 .then(data => {
 document.getElementById("message").innerHTML = data.message;
 })
 .catch(error => {
 document.getElementById("message").innerHTML = "Hata: " + error;
 });
 }

 function checkForDiscounts() {
 document.getElementById("message").innerHTML = "İndirimler kontrol ediliyor...";
 fetch('/check_for_discounts?category_link=' + encodeURIComponent(selectedCategoryLink)+ '&sort_order=' + encodeURIComponent(selectedSortOrder))
 .then(response => response.json())
 .then(data => {
 document.getElementById("message").innerHTML = data.message;
 })
 .catch(error => {
 document.getElementById("message").innerHTML = "Hata: " + error;
 });
 }
 function uploadExcel() {
 document.getElementById('fileInput').click(); // Dosya seçme alanını tetikle
 }

 document.getElementById('fileInput').addEventListener('change', function() {
 var file = this.files[0];
 var formData = new FormData();
 formData.append('file', file);
 document.getElementById("upload-message").innerHTML = "Dosya yükleniyor...";
 fetch('/upload_excel', {
 method: 'POST',
 body: formData
 })
 .then(response => response.json())
 .then(data => {
 document.getElementById("upload-message").innerHTML = data.message;
 if (!data.error){
 checkForDiscounts();
 }

 })
 .catch(error => {
 document.getElementById("upload-message").innerHTML = "Hata: " + error;
 });

 });
 </script>
</body>
</html>
"""

# Dosya yükleme formu ve ana sayfa artık aynı yerde
@app.route("/")
def index():
 return render_template_string(HTML_TEMPLATE, category_links=CATEGORY_LINKS,sort_options = SORT_OPTIONS)

# Veri çekme fonksiyonu
@app.route("/fetch_data")
def fetch_data():
 global products
 try:
 max_products = int(request.args.get('product_count', DEFAULT_PRODUCT_COUNT))
 category_link = request.args.get('category_link')
 sort_order = int(request.args.get('sort_order', 0))

 if not category_link:
 return {"message": "Kategori linki bulunamadı.", "products": []}

 url = category_link.replace("{pageSize}", str(max_products)).replace("{sortOrder}",str(sort_order))

 response = requests.get(url, timeout=TIMEOUT)
 response.raise_for_status()
 api_response = response.json()
 products = filter_discounted_products(api_response, max_products)

 return {"message": "Veriler çekildi.", "products": products}
 except (ValueError, requests.exceptions.RequestException, json.JSONDecodeError) as e:
 return {"message": f"Hata: {e}", "products": []}

# Excel'e kaydetme fonksiyonu
@app.route("/save_to_excel")
def save_to_excel():
 global products
 try:
 if products:
 df = pd.DataFrame(products)
 df.to_excel(EXCEL_FILE_NAME, index=False)
 return {"message": f"Veriler {EXCEL_FILE_NAME} dosyasına kaydedildi."}
 else:
 return {"message": "Kaydedilecek veri yok.", "error": True}
 except Exception as e:
 return {"message": f"Kaydetme hatası: {e}", "error": True}

# İndirim kontrol fonksiyonu
@app.route("/check_for_discounts")
def check_for_discounts():
 global old_products
 if old_products.empty:
 return {"message": "Lütfen önce Excel dosyasını yükleyin.", "error": True}

 try:
 max_products = int(request.args.get('product_count', DEFAULT_PRODUCT_COUNT))
 category_link = request.args.get('category_link', None)
 sort_order = int(request.args.get('sort_order', 0))
 if not category_link:
 return {"message": "Lütfen bir kategori seçin.", "error": True}

 url = category_link.replace("{pageSize}", str(max_products)).replace("{sortOrder}",str(sort_order))
 response = requests.get(url, timeout=TIMEOUT)
 response.raise_for_status()
 current_products = filter_discounted_products(response.json(), max_products)

 changes_message = ""
 for old_product in old_products.to_dict('records'):
 if matching_current_product := next((p for p in current_products if p['name'] == old_product['name']), None):
 if matching_current_product['discount'] > 0:
 changes_message += (f"Ürün: {old_product['name']}\n"
 f"Eski Fiyat: {old_product['normalPrice']}\n"
 f"Güncel İndirim: {matching_current_product['discount']}\n\n")

 if changes_message:
 return {"message": changes_message}
 else:
 return {"message": "İndirim değişikliği bulunamadı."}

 except (ValueError, requests.exceptions.RequestException, json.JSONDecodeError) as e:
 return {"message": f"Hata: {e}", "error": True}
 except Exception as e:
 return {"message": f"Bir hata oluştu: {e}", "error": True}

# İndirimli ürünleri filtreleyen fonksiyon - GÜNCELLENDİ
def filter_discounted_products(api_data, max_products):
 discounted_products = []
 product_count = 0
 if "Data" in api_data and "SearchResponse" in api_data["Data"]:
 for product in api_data["Data"]["SearchResponse"]["Documents"]:
 if product_count >= max_products:
 break
 campaign = product.get("CampaignBadge")
 if campaign and campaign and "DiscountAmount" in campaign:
 discounted_products.append({
 "name": product.get("ProductName", "Unknown"),
 "discount": campaign["DiscountAmount"],
 "normalPrice": product.get("ProductPriceInclTax", 0)
 })
 product_count += 1
 return discounted_products

# Excel dosyasını yükleme fonksiyonu
@app.route('/upload_excel', methods=['POST'])
def upload_excel():
 global old_products
 try:
 if 'file' not in request.files:
 return {"message": "Dosya seçilmedi.", "error": True}
 file = request.files['file']
 if file.filename == '':
 return {"message": "Dosya seçilmedi.", "error": True}
 if file:
 old_products = pd.read_excel(file)
 if not {'name', 'normalPrice'}.issubset(old_products.columns):
 return {"message": "Excel dosyasında 'name' ve 'normalPrice' sütunları bulunamadı.", "error": True}
 return {"message": "Excel dosyası başarıyla yüklendi."}
 except Exception as e:
 return {"message": f"Excel dosyası yüklenirken bir hata oluştu: {e}", "error": True}

from flask import render_template_string

if __name__ == "__main__":
 # Uygulamayı ayrı bir iş parçacığında (thread) çalıştır
 def run_app():
 app.run(host='0.0.0.0', port=8081, debug=True, use_reloader=False)

 thread = threading.Thread(target=run_app)
 thread.daemon = True # Ana iş parçacığı sonlandığında bu iş parçacığının da sonlanmasını sağla
 thread.start()

 # Pydroid3'te ana iş parçacığının çalışmaya devam etmesini sağlamak için bir döngü ekleyin
 # (Aksi takdirde uygulama hemen kapanır)
 while True:
 import time
 time.sleep(1)

Bu kodda linklerden veri çekilmiyor bana yardımcı olur musun?
Konudan biraz alakasız olacak ama apilerde değişen tek kısım fx_c2 parametresi.
Aynı şeyleri tekrar tekrar yazmak yerine sadece idleri koymak daha mantıklı ve temiz olur 🙃.
 
Çok yardımcı olduğunuzun farkındayım, ancak ben doğru linkleri bulamazken sürekli “Şunu düzeltirsen olur”, “Bunu böyle yapmayacaktın”, “Şöyle yap” gibi cümlelerle yardımcı olmuyorsunuz. Neden mi? Çünkü kodlama bilgim yok, bilgisayarım yok ve doğru verileri çekemediğim için burada dönüp dolaşıp yine aynı döngüye giriyorum. Ayrıca dikkat dağınıklığı ve hiperaktivite bozukluğu hastası olduğum için kendimi geliştirmekte zorlanıyorum. Biriniz gelip de “Kardeşim, gel sana yardımcı olayım. Şu linkler aslında bu linkler olacaktı, şu linkler için bu kısımları ekledim. Bir sıkıntın olursa yardım ederim” demiyorsunuz.
 
Çok yardımcı olduğunuzun farkındayım, ancak ben doğru linkleri bulamazken sürekli “Şunu düzeltirsen olur”, “Bunu böyle yapmayacaktın”, “Şöyle yap” gibi cümlelerle yardımcı olmuyorsunuz. Neden mi? Çünkü kodlama bilgim yok, bilgisayarım yok ve doğru verileri çekemediğim için burada dönüp dolaşıp yine aynı döngüye giriyorum. Ayrıca dikkat dağınıklığı ve hiperaktivite bozukluğu hastası olduğum için kendimi geliştirmekte zorlanıyorum. Biriniz gelip de “Kardeşim, gel sana yardımcı olayım. Şu linkler aslında bu linkler olacaktı, şu linkler için bu kısımları ekledim. Bir sıkıntın olursa yardım ederim” demiyorsunuz.
Hocam burası yardım forumu. Kimse ekstra uğraşıp da hazır script vermez. Ben yine de sizin için apiye baktım.

Python:
def scrape_and_show():
    global products

    url = "https://www.lcw.com/ajax/ProductList/ProductListPageData?xhrKeys=CategoryTreeId,xhrKeys&CategoryTreeId=2&PageIndex=1"

    products = []

    response = requests.get(url, headers=headers)
    jsonList = response.json()["CatalogList"]["Items"]
    for product in jsonList:
        product_name = product["ProductDescription"]
        product_price = product["Price"]
        product_url = "https://www.lcw.com"+product["ModelUrl"]
        products.append({"name": product_name, "price": product_price, "url": product_url})

    product_list.delete(1.0, tk.END)
    for product in products:
        product_list.insert(tk.END, f"Ürün Adı: {product['name']}\nFiyat: {product['price']}\nURL: {product['url']}\n\n")

    if messagebox.askyesno("Excel Kaydet", "Ürün verilerini Excel dosyasına kaydetmek ister misiniz?"):
        save_to_excel()

Bu api erkek ürün kategorisinden direkt json şeklinde size ürünleri veriyor. Daha fazla ürün için PageIndex değeri arttırılmalı.

Bu arada referans verdiğiniz github projesi çok kötü ve hantal :D en basitinden selenium kullanmış ayrıca fiyat değişikliklerini gözlemlemek için tek tek ürünleri geziyor. 100 ürün gözlemleyen biri için bu eziyet olacaktır.

Apiyi zaten Rasgool isimli arkadaş vermiş yeni görüyorum :).
 
Hocam burası yardım forumu. Kimse ekstra uğraşıp da hazır script vermez. Ben yine de sizin için apiye baktım.

Python:
def scrape_and_show():
 global products.

 url = "https://www.lcw.com/ajax/ProductList/ProductListPageData?xhrKeys=CategoryTreeId,xhrKeys&CategoryTreeId=2&PageIndex=1"

 products = []

 response = requests.get(url, headers=headers)
 jsonList = response.json()["CatalogList"]["Items"]
 for product in jsonList:
 product_name = product["ProductDescription"]
 product_price = product["Price"]
 product_url = "https://www.lcw.com"+product["ModelUrl"]
 products.append({"name": product_name, "price": product_price, "url": product_url})

 product_list.delete(1.0, tk.END)
 for product in products:
 product_list.insert(tk.END, f"Ürün Adı: {product['name']}\nFiyat: {product['price']}\nURL: {product['url']}\n\n")

 if messagebox.askyesno("Excel Kaydet", "Ürün verilerini Excel dosyasına kaydetmek ister misiniz?"):
 save_to_excel()

Bu API erkek ürün kategorisinden direkt JSON şeklinde size ürünleri veriyor. Daha fazla ürün için pageındex değeri arttırılmalı.

Bu arada referans verdiğiniz GitHub projesi çok kötü ve hantal :D en basitinden Selenium kullanmış ayrıca fiyat değişikliklerini gözlemlemek için tek tek ürünleri geziyor. 100 ürün gözlemleyen biri için bu eziyet olacaktır.

Hocam zaten onu düzelttim birkaç mesaj öncesinde DeFacto için yaptığım kodun GitHub linkini verdim bu verdiğim kodu geliştirmek istiyorum indirim takibini kategorilerde kendimiz seçebilelim istiyorum hangi kategoriyi seçerek o kategoriden ürün bilgisini çekecek ayrıca sıralama mantığı da olsun istiyorum bu istediğimi hem DeFacto hem LCW için yapabilir misiniz?
 
Hocam zaten onu düzelttim birkaç mesaj öncesinde DeFacto için yaptığım kodun GitHub linkini verdim bu verdiğim kodu geliştirmek istiyorum indirim takibini kategorilerde kendimiz seçebilelim istiyorum hangi kategoriyi seçerek o kategoriden ürün bilgisini çekecek ayrıca sıralama mantığı da olsun istiyorum bu istediğimi hem DeFacto hem LCW için yapabilir misiniz?
Hocam bunları zaten yapmışsınız 🤔 ben mi yanlış anladım acaba? Kategoriler kısmı yanlış yapmışsınız kadın ürünü diye erkek kısmını getiriyor.
1735928762814.png
 

Technopat Haberler

Yeni konular

Geri
Yukarı