Ana içeriğe geç
Kesit Python
Orta · Otomasyon, web ve araçlar

Excel otomasyonu: openpyxl, pandas ve rapor üretimi

Excel dosyasını kod gözüyle tanır; openpyxl ile hücre, formül, stil ve grafik yazar, pandas ile çok sayfalı rapor üretir, Türkçe sayı ve tarih biçimlerini doğru çevirirsin.

Uygulamada aç, 40 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

Neden önemli?

Anadolu Market finans ekibinde her pazartesi aynı iş yapılıyor: satış sisteminden CSV indirilir, Excel'de açılır, şehirlere göre özet tablo hazırlanır, toplam satırına formül yazılır, başlık kalın yapılır, sütunlar genişletilir, bir grafik eklenir ve dosya yöneticilere gönderilir. Bu iş her hafta 1–2 saat sürer ve her seferinde küçük bir kopyala-yapıştır hatası riski taşır. Python ile aynı rapor birkaç saniyede, her hafta aynı biçimde ve hatasız üretilir.

Şirketlerin büyük kısmında veri hâlâ Excel'de yaşar: bütçe tabloları, stok sayımları, İK puantajları, belediye tahsilat listeleri. Excel'i okuyup yazabilen bir Python geliştiricisi, "veri ekibi" ile "iş birimi" arasındaki köprü olur. Bu derste iki ana aracı öğreneceksin: hücre düzeyinde kontrol için openpyxl, tablo düzeyinde hızlı iş için pandas.

Excel dosyasının yapısı

Bir .xlsx dosyası aslında içinde XML dosyaları olan bir ZIP arşividir. Kod gözüyle bakınca üç katman vardır:

Kavramİngilizcesiopenpyxlpandas
Çalışma kitabıworkbookWorkbook(), load_workbook()pd.ExcelFile, ExcelWriter
Sayfaworksheetwb["Özet"], wb.activesheet_name="Özet"
Hücrecellws["B2"], ws.cell(row=2, column=2)df.iloc[0, 1]
Aralıkrangews["A1:C10"], iter_rows()usecols="A:C", nrows=10

Hücre adresi (cell address) harf + sayıdır: B2 2. satır, 2. sütun demektir. Sütun harfleri 26 tabanlı ama sıfırsız bir sayma sistemidir: A=1 … Z=26, AA=27, AZ=52, BA=53. Bu yüzden "harfi sayıya çevir" işlemi klasik bir mülakat sorusudur ve Excel otomasyonunda sürekli lazım olur.

def sutun_no(harfler):
    no = 0
    for ch in harfler.upper():
        no = no * 26 + (ord(ch) - ord("A") + 1)
    return no

for h in ["A", "Z", "AA", "AZ", "BA", "XFD"]:
    print(h, "→", sutun_no(h))

Son satırdaki XFD Excel'in en son sütunudur (16.384). Bir sayfada en fazla 1.048.576 satır bulunur; daha büyük veri için Excel doğru araç değildir.

openpyxl ile rapor yazmak

Aşağıdaki kod hem bilgisayarında hem de bu sayfada çalışır: dersin sonundaki "Gerçek .xlsx dosyasıyla çalışmak" bölümünde ve alıştırmalarda openpyxl tarayıcıda gerçek dosya yazar. İlk bölüm hücre modelini saf Python ile kurar, mantığı görmen için.

from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment
from openpyxl.chart import BarChart, Reference

wb = Workbook()
ws = wb.active
ws.title = "Şehir Özeti"

ws["A1"] = "Anadolu Market — Haftalık Ciro"
ws.merge_cells("A1:C1")                       # başlığı üç sütuna yay
ws["A1"].font = Font(size=14, bold=True)
ws["A1"].alignment = Alignment(horizontal="center")

ws.append(["Şehir", "Sipariş", "Ciro"])       # 2. satır: başlıklar
for satir in [["İzmir", 42, 18250.5], ["Ankara", 35, 15100.0], ["Bursa", 18, 7420.75]]:
    ws.append(satir)

ws["A6"] = "TOPLAM"
ws["B6"] = "=SUM(B3:B5)"                      # formül metin olarak yazılır
ws["C6"] = "=SUM(C3:C5)"

baslik = PatternFill("solid", fgColor="DDEBF7")
for hucre in ws[2]:                            # 2. satırın tüm hücreleri
    hucre.font = Font(bold=True)
    hucre.fill = baslik
for satir in ws.iter_rows(min_row=3, min_col=3, max_col=3):
    satir[0].number_format = "#,##0.00"        # binlik ayraç + 2 ondalık

ws.column_dimensions["A"].width = 16
ws.freeze_panes = "A3"                        # başlıklar kaydırınca sabit kalsın

grafik = BarChart()
grafik.title = "Şehre göre ciro"
veri = Reference(ws, min_col=3, min_row=2, max_row=5)
etiket = Reference(ws, min_col=1, min_row=3, max_row=5)
grafik.add_data(veri, titles_from_data=True)
grafik.set_categories(etiket)
ws.add_chart(grafik, "E2")

wb.save("haftalik_rapor.xlsx")
Kendi bilgisayarında deneKurulum: pip install openpyxl (pandas ile Excel yazmak için de gerekir). Dosyayı Excel ya da LibreOffice ile açıp sonucu gör. Bu sayfada openpyxl ilk kullanımda iner (yaklaşık 270 KB); pandas ile Excel de aynı paketi kullanır.

Okumak için load_workbook kullanılır. iter_rows(values_only=True) hücre nesneleri yerine doğrudan değerleri demet (tuple) olarak verir; veriyi işlemenin en pratik yoludur:

from openpyxl import load_workbook

wb = load_workbook("stok.xlsx", data_only=True)   # formül yerine son hesaplanan değer
ws = wb["Depo"]
print(ws.max_row, ws.max_column)
for urun, adet, fiyat in ws.iter_rows(min_row=2, values_only=True):
    if adet is None:          # boş hücre None gelir
        continue
    print(urun, adet * fiyat)
openpyxl formül hesaplamazws["B6"] = "=SUM(B3:B5)" yazdığında dosyaya yalnızca formül metni gider; değeri Excel dosyayı açınca hesaplar. data_only=True ile okuduğunda ise Excel'in en son kaydettiği değeri görürsün. Dosyayı hiç Excel'de açılmamış (yalnız Python'la üretilmiş) bir formül hücresi None döner. Değere kodda ihtiyacın varsa toplamı Python'da hesapla.

Hücreleri kod içinde modellemek

openpyxl'in yaptığı iş özünde "adres → değer" eşlemesidir. Bunu bir sözlükle taklit edersen hem mantığı kavrar hem de raporu test edilebilir hale getirirsin: önce sözlüğü üret ve test et, en son tek bir fonksiyonla Excel'e dök.

def harf(n):
    s = ""
    while n > 0:
        n, kalan = divmod(n - 1, 26)
        s = chr(65 + kalan) + s
    return s

satirlar = [["Şehir", "Ciro"], ["İzmir", 18250.5], ["Ankara", 15100.0]]
sayfa = {}
for r, satir in enumerate(satirlar, start=1):
    for c, deger in enumerate(satir, start=1):
        sayfa[f"{harf(c)}{r}"] = deger
son = len(satirlar)
sayfa[f"A{son + 1}"] = "TOPLAM"
sayfa[f"B{son + 1}"] = f"=SUM(B2:B{son})"
for adres, deger in sayfa.items():
    print(adres, deger)

Formüller: İngilizce ad, virgül ayraç

Türkçe Excel'de =TOPLA(B2;B10) görürsün ama dosyanın içinde formüller her zaman İngilizce ad ve virgül ayraç ile saklanır. Excel açılırken arayüz diline çevirir. Bu yüzden openpyxl ile Türkçe formül yazarsan Excel #AD? (#NAME?) hatası gösterir.

Türkçe arayüzDosyaya yazılacakÖrnek
TOPLASUM=SUM(C2:C50)
ORTALAMAAVERAGE=AVERAGE(C2:C50)
EĞERIF=IF(C2>1000,"Büyük","Küçük")
ETOPLASUMIF=SUMIF(A:A,"İzmir",C:C)
EĞERSAYCOUNTIF=COUNTIF(A:A,"Ankara")
DÜŞEYARAVLOOKUP=VLOOKUP(A2,Fiyat!A:B,2,FALSE)
TR_EN = {"TOPLA": "SUM", "ORTALAMA": "AVERAGE", "EĞERSAY": "COUNTIF"}

def formul(islev, sutun, ilk, son):
    ad = TR_EN.get(islev.upper(), islev.upper())
    return f"={ad}({sutun}{ilk}:{sutun}{son})"

print(formul("TOPLA", "C", 2, 41))
print(formul("average", "D", 2, 41))

pandas ile Excel: tablo düzeyinde iş

Hücre biçimiyle değil, veriyle ilgileniyorsan pandas çok daha kısadır. pandas'ı ileri seviyede derinlemesine göreceksin; burada Excel'e özgü kısımlar yeterli.

import pandas as pd

df = pd.read_excel("satislar.xlsx", sheet_name="Ekim", usecols="A:D", dtype={"musteri_no": str})
tum = pd.read_excel("satislar.xlsx", sheet_name=None)   # {sayfa_adı: DataFrame} sözlüğü
birlesik = pd.concat(tum.values(), keys=tum.keys(), names=["ay", None]).reset_index(level=0)

ozet = df.pivot_table(index="sehir", columns="kategori", values="tutar", aggfunc="sum", fill_value=0)

with pd.ExcelWriter("rapor.xlsx", engine="openpyxl") as yazici:
    df.to_excel(yazici, sheet_name="Ham Veri", index=False)
    ozet.to_excel(yazici, sheet_name="Özet")
    yazici.sheets["Özet"].column_dimensions["A"].width = 18   # openpyxl sayfasına erişim
Kendi bilgisayarında denepip install pandas openpyxl. pandas .xlsx okumak ve yazmak için arka planda openpyxl kullanır; eski .xls için xlrd gerekir.

Rapor üretiminin "hesap" kısmı dosya biçiminden bağımsızdır. Aynı pivot mantığını CSV ile görelim; Excel'e yazmayı dersin sonundaki görevlerde yapacaksın:

import io
import pandas as pd

csv_metni = """sehir,ay,tutar
İzmir,Eylül,1200
İzmir,Ekim,1500
Ankara,Ekim,900
Ankara,Ekim,300
Bursa,Eylül,450
"""
df = pd.read_csv(io.StringIO(csv_metni))
ozet = df.pivot_table(index="sehir", columns="ay", values="tutar", aggfunc="sum", fill_value=0)
print(ozet)
print(ozet.reset_index().to_csv(index=False))

openpyxl mi, xlsxwriter mı, CSV mi?

AraçOkurYazarGüçlü yanıZayıf yanı
openpyxlEvetEvetVar olan dosyayı açıp değiştirme, şablon doldurmaBüyük dosyada yavaş, formül hesaplamaz
xlsxwriterHayırEvetHızlı, zengin grafik ve koşullu biçimYalnız yeni dosya; var olanı düzenleyemez
pandasEvetEvetTablo dönüştürme, pivot, çok sayfaHücre stili için alttaki motora inmen gerekir
CSVEvetEvetEvrensel, hızlı, satır satır akışTek sayfa, stil/formül/tip yok

Kural: sistemden sisteme veri taşıyorsan CSV (ya da Parquet); insanların okuyacağı biçimli bir rapor üretiyorsan XLSX. Şirket şablonunu doldurmak gerekiyorsa openpyxl, sıfırdan büyük ve grafikli rapor için xlsxwriter (pip install xlsxwriter, pd.ExcelWriter(..., engine="xlsxwriter")).

Türkçe sayı ve tarih biçimleri

Excel bir sayıyı içeride her zaman sayı olarak tutar; 1.234,56 yalnızca görünüştür (number format). Sorun, birileri Türkçe Excel'den CSV aldığında ya da hücreye sayıyı metin olarak yapıştırdığında başlar: "1.234,56" metni float() ile çevrilemez. Doğru sıra önemlidir: önce binlik noktalarını sil, sonra ondalık virgülünü noktaya çevir.

def tr_coz(metin):
    temiz = metin.strip().replace("TL", "").strip()
    return float(temiz.replace(".", "").replace(",", "."))

def tr_yaz(sayi):
    s = f"{sayi:,.2f}"                       # 1,234,567.89
    return s.replace(",", "_").replace(".", ",").replace("_", ".")

print(tr_coz("1.234,56"), tr_coz("  -12,5 TL"))
print(tr_yaz(1234567.891), tr_yaz(0.5))

pandas'ta aynı iş parametreyle yapılır: pd.read_csv(yol, sep=";", decimal=",", thousands=".", encoding="utf-8-sig"). Türkçe Excel CSV'yi noktalı virgülle ayırır, çünkü virgül ondalık işaretidir. utf-8-sig ise Excel'in dosya başına koyduğu BOM işaretini temizler; bunu json-csv dersinde de görmüştün.

Tarihler ise Excel'de seri numarası olarak saklanır: 1899-12-30'dan bu yana geçen gün sayısı. Bazen tarih sütunu 45000 gibi sayılarla gelir; bunu şöyle çevirirsin:

from datetime import date, timedelta, datetime

def excel_tarih(seri):
    return date(1899, 12, 30) + timedelta(days=int(seri))

print(excel_tarih(45000), excel_tarih(46323))
print(datetime.strptime("28.10.2026", "%d.%m.%Y").date())
print(date(2026, 10, 28).strftime("%d.%m.%Y"))
Biçim ve değer ayrı tutuluropenpyxl'de hücreye date nesnesi yaz ve number_format = "DD.MM.YYYY" ver; tarihi metin olarak yazma. Böylece Excel'de sıralama, filtre ve tarih formülleri çalışır.

Büyük dosyalar

openpyxl normal modda tüm dosyayı belleğe alır; 200 bin satırlık bir dosyada yüzlerce MB bellek kullanabilir. İki özel mod vardır:

pandas read_excel parça parça (chunk) okumayı desteklemez. Düzenli gelen büyük Excel dosyalarını bir kez CSV ya da Parquet'e çevirmek, sonraki işleri çok hızlandırır.

Rapor otomasyonunun adımları

  1. Girdiyi doğrula: beklenen sayfa ve sütunlar var mı, tipler doğru mu? Eksikse anlaşılır bir hata ver.
  2. Temizle: boş satırları at, Türkçe sayı/tarih metinlerini çevir, şehir adlarını standartlaştır.
  3. Hesapla: özetleri Python/pandas ile hesapla ve test et; Excel formülüne güvenme.
  4. Yerleştir: sonucu hücre sözlüğüne ya da DataFrame'e koy; toplam satırına okuyan kişi için formül de ekleyebilirsin.
  5. Biçimlendir: başlık stili, sayı biçimi, sütun genişliği, dondurulmuş bölmeler, grafik.
  6. Kaydet ve dağıt: tarihli dosya adı (rapor_2026-10-26.xlsx), arşiv klasörü, e-posta ya da paylaşım klasörü.
Gerçek işteBir lojistik firmasının bölge müdürleri her sabah "dünkü teslimat başarısı" Excel'ini bekler. İyi kurulmuş otomasyon şablon dosyayı (sablon.xlsx) openpyxl ile açar, yalnızca veri hücrelerini doldurur, logoyu ve biçimleri olduğu gibi bırakır, dosyayı tarihli adla kaydeder. İş birimi tanıdığı görünümden vazgeçmek zorunda kalmaz, sen de biçimle uğraşmazsın.
Derinleş

Gerçek .xlsx dosyasıyla çalışmak

Bu bölümdeki kod tarayıcıda gerçek Excel dosyası yazar ve okur. Dosya tarayıcının belleğinde durur; çıktının altındaki İndir düğmesiyle alıp Excel'de açabilirsin. openpyxl ilk kullanımda iner (yaklaşık 270 KB), XlsxWriter yaklaşık 180 KB.

from openpyxl import Workbook, load_workbook
from openpyxl.styles import Font

wb = Workbook()
ws = wb.active
ws.title = "Satış"
ws.append(["Ürün", "Adet"])
ws.append(["Çay", 3])
ws["A1"].font = Font(bold=True)
ws["C2"] = "=B2*2"
wb.save("ornek.xlsx")

okunan = load_workbook("ornek.xlsx")
print(okunan.sheetnames, okunan["Satış"]["C2"].value)
print(load_workbook("ornek.xlsx", data_only=True)["Satış"]["C2"].value)

Son satır None yazar: openpyxl formülü hesaplamaz, yalnız yazar. Hesaplanmış değer dosyaya Excel açıp kaydedince girer. Bu yüzden Python'da hesap yapıp sonucu ayrıca denetlemek gerekir.

AraçNe zaman
openpyxlVar olan dosyayı açmak, şablon doldurmak, okumak
XlsxWriterSıfırdan biçimli ve grafikli rapor; var olan dosyayı açamaz
pandasTabloyu toplu okumak ve yazmak; arka planda ikisini kullanır
SınırTarayıcıda gerçek Excel yok: grafik ve koşullu biçim dosyaya doğru yazılır ve testler dosyayı yeniden okuyarak denetler, ama görünümü ancak indirip Excel'de açınca görürsün. xlwings ve makro bilgisayarında kurulu Excel ister; burada çalışmaz.
Derinleş

Derinleş: Power BI ve Excel köprüsü

Çoğu kurumda Python tek başına rapor aracı değildir; sonuçlar Excel'e ya da Power BI panolarına gider. Python'un bu dünyaya üç kapısı var: Power BI içinde Python betik kaynağı ve Python görseli, Excel içinde =PY formülü ve en sağlamı, Python'un temizleyip Power BI'a hazır yıldız şemalı dosyalar (CSV/Parquet) üretmesi. Bu bölümde Kesit Power BI'ın kullandığı kesit_bi modelini ve Kesit SQL'in anadolu_market tablolarını kullanacaksın; ikisi aynı kurgusal şirketin iki görünümü.

Power BI'da Python: betik kaynağı ve görsel

Veri al → Diğer → Python betiği ile yazdığın betik çalışır ve betik bittiğinde ad alanındaki her pandas DataFrame ayrı bir tablo olarak seçime sunulur. Power BI Desktop, bilgisayarındaki Python yorumlayıcısını kullanır (Seçenekler → Python betiği oluşturma); pandas ve matplotlib orada kurulu olmalıdır. Python görseli ise rapor sayfasında çalışır: seçtiğin alanlar dataset adlı DataFrame olarak gelir, sen matplotlib ile çizersin.

# Power BI → Veri al → Python betiği
import pandas as pd
satis = pd.read_csv(r"C:\veri\kesit_bi\Satislar.csv")
satis = satis[satis["Durum"] != "İptal"]          # yalnız DataFrame'ler tablo olur
ozet = satis.groupby("Kanal", as_index=False)["Tutar"].sum()

# Python görseli (rapor sayfasında): Power BI "dataset" DataFrame'ini verir
import matplotlib.pyplot as plt
dataset.groupby("Kategori")["Tutar"].sum().sort_values().plot.barh()
plt.show()
İki tuzak1) Python görseline gelen dataset içinde tekrarlanan satırlar silinir; aynı ürün ve tutarlı iki satış tek satıra iner ve toplam yanlış çıkar. Alanlara benzersiz bir sütun (SatirNo) ekle. 2) Python kaynakları Power BI Hizmeti'nde (bulut) yenilenirken kişisel ağ geçidi ister; kurumsal yenilemelerde Python adımını Power BI dışına (zamanlanmış betik) taşımak daha sağlamdır.

Excel'de Python: =PY

Microsoft 365 Excel'de bir hücreye =PY( yazınca Python düzenleyicisi açılır. Kod Microsoft bulutunda (Anaconda dağıtımıyla) çalışır; yerel dosyalara ve internete erişemez. Hücre aralığı xl("A1:D100", headers=True) ile DataFrame olarak gelir; sonuç hücreye değer ya da Excel tablosu olarak dökülür.

=PY(
df = xl("Satislar[#All]", headers=True)
df.groupby("Kanal")["Tutar"].sum()
)

Yıldız şeması: Power BI'ın sevdiği biçim

Power BI modeli en iyi yıldız şemasıyla çalışır: ortada olayları (satış satırları) tutan uzun ve dar bir olgu tablosu (fact), çevresinde tanımlayıcı bilgileri tutan boyut tabloları (dimension: Ürünler, Müşteriler, Tarih). Olgu tablosunda yalnız anahtarlar ve ölçülebilir sayılar (Adet, Tutar) bulunur; boyutlarda her anahtar bir kez geçer. Tek dev düz tablo yerine yıldız şeması: dosya küçülür, DAX ölçüleri doğru filtrelenir ve aynı boyut birden çok olguya bağlanabilir.

import veri

satis = veri.oku("kesit_bi", "Satislar")
urun = veri.oku("kesit_bi", "Urunler")
musteri = veri.oku("kesit_bi", "Musteriler")
print("olgu:", satis.shape, "| ürün:", urun.shape, "| müşteri:", musteri.shape)

# boyut anahtarları tekil mi? olgudaki her anahtarın boyutta karşılığı var mı?
print(urun["UrunNo"].is_unique, musteri["MusteriNo"].is_unique)
print(satis["UrunNo"].isin(urun["UrunNo"]).all(), satis["MusteriNo"].isin(musteri["MusteriNo"]).all())

tablo = satis.merge(urun[["UrunNo", "Kategori"]], on="UrunNo", validate="many_to_one")
print(tablo.groupby("Kategori")["Tutar"].sum().round(0).sort_values(ascending=False).head(3))

validate="many_to_one" birleştirmede boyut anahtarının tekil olduğunu denetler; tekil değilse hata verir. Bu tek parametre, raporda tutarların sessizce ikiye katlanmasını önler.

Düz tablodan yıldız şemasına

Kaynak sistemden çoğu zaman tek bir düz (denormalize) dışa aktarım gelir. Python'un işi: boyutları ayırmak (drop_duplicates), anahtarları denetlemek, bir tarih boyutu üretmek ve dosyaları Power BI'ın sorunsuz okuyacağı biçimde yazmaktır. Anadolu Market'in SQL tablolarını birleştirip yeniden ayıralım:

kalem = veri.oku("anadolu_market", "order_items")
siparis = veri.oku("anadolu_market", "orders")
urunler = veri.oku("anadolu_market", "products")
duz = (kalem.merge(siparis, on="order_id")
            .merge(urunler[["product_id", "name", "category"]], on="product_id"))
print(duz.shape)

dim_urun = duz[["product_id", "name", "category"]].drop_duplicates().sort_values("product_id")
olgu = duz[["item_id", "order_id", "order_date", "product_id", "quantity", "unit_price", "discount"]].copy()
olgu["TarihKey"] = olgu["order_date"].str.replace("-", "").astype(int)   # 20240131 biçimi
olgu["tutar"] = (olgu["quantity"] * olgu["unit_price"] * (1 - olgu["discount"])).round(2)
print(dim_urun.shape, olgu.shape)
print(olgu[["TarihKey", "tutar"]].head(3))
BiçimArtısıDikkat
CSV (UTF-8)Her yerde açılır, okunabilirTür bilgisi yok; tarih ISO (YYYY-AA-GG), ondalık nokta, index=False. Excel'de açılacaksa encoding="utf-8-sig".
ParquetTür bilgisi, sıkıştırma, hızlı; Power BI doğrudan okurdf.to_parquet("olgu.parquet") için pyarrow gerekir
Excel (.xlsx)İş kullanıcısı için tanıdık1.048.576 satır sınırı; büyük olgu tablosu için uygun değil
Gerçek işteAnalist ekiplerinin yaygın düzeni: Python (zamanlanmış betik ya da boru hattı (pipeline)) kaynakları çeker ve temizler, yıldız şemalı Parquet/CSV dosyalarını paylaşılan klasöre ya da veri ambarına yazar; Power BI bu dosyalara bağlanır ve yalnız modelleme ile DAX işini yapar. Böylece ağır dönüşümler sürüm kontrolündeki Python kodunda kalır. Modelleme, ilişkiler ve DAX ölçülerinin devamı Kesit Power BI'da; bu tablolar orada da aynı adlarla seni bekliyor.
Uzmanlaş

Hesap Python'da, sunum Excel'de

Olgun otomasyonlarda hesap mantığı saf Python fonksiyonlarındadır (test edilebilir), Excel katmanı ince bir "yazıcı"dır. Bu derste hücre sözlüğü kurmanın nedeni budur: {"B7": "=SUM(B2:B6)"} sözlüğünü birim testle doğrularsın, openpyxl'e döken 5 satırlık fonksiyon nadiren hata yapar.

Formülleri yeniden hesaplatmak

Formül değerlerine Python'dan ihtiyacın varsa ya değeri kendin hesaplarsın ya da dosyayı hesaplayan bir programdan geçirirsin: LibreOffice'in başsız (headless) modu ya da Windows'ta Excel'i süren xlwings. Sunucu ortamında Excel kurulu olmadığı için genelde ilk yol seçilir.

Güvenlik ve sürdürülebilirlik

  • .xlsm dosyaları makro içerir; openpyxl makroları çalıştırmaz, keep_vba=True ile yalnızca korur.
  • Kullanıcıdan gelen metinler = ile başlıyorsa Excel onu formül sanar (CSV/formula injection). Dışa aktarırken başına ' eklemek ya da metin tipini zorlamak yaygın önlemdir.
  • Aynı girdi aynı dosyayı üretmeli (idempotent): sabit sıralama, sabit sayfa sırası, tarih datetime.now() yerine parametre.
Alıştırmalara geç (40)