z230
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
"""
|
||||
=======================================================================
|
||||
Název: save_first_email_per_folder_v1.0.py
|
||||
Verze: 1.0
|
||||
Datum: 2026-06-04
|
||||
Popis: Testovací skript: projde všechny složky OWA, z každé stáhne
|
||||
první email jako EML a uloží ho do downloads/.
|
||||
|
||||
Používá persistent profil z outlook_login_v1.0.py.
|
||||
=======================================================================
|
||||
"""
|
||||
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
PROFILE_DIR = BASE_DIR / "outlook_profile"
|
||||
OUT_DIR = BASE_DIR / "downloads"
|
||||
START_URL = "https://outlook.cloud.microsoft/mail/"
|
||||
|
||||
# Složky: (zobrazovaný název, způsob navigace, hodnota)
|
||||
# způsob: "url" = přímá URL, "click" = klik na text v levém panelu
|
||||
FOLDERS = [
|
||||
("Inbox", "url", "https://outlook.cloud.microsoft/mail/"),
|
||||
("Sent Items", "url", "https://outlook.cloud.microsoft/mail/sentitems"),
|
||||
("Deleted Items", "url", "https://outlook.cloud.microsoft/mail/deleteditems"),
|
||||
("Drafts", "url", "https://outlook.cloud.microsoft/mail/drafts"),
|
||||
("Junk Email", "url", "https://outlook.cloud.microsoft/mail/junkemail"),
|
||||
("Archive", "url", "https://outlook.cloud.microsoft/mail/archive"),
|
||||
("77242113UCO3002", "click", "77242113UCO3002"),
|
||||
("Hrabak", "click", "Hrabak"),
|
||||
("Request assessment", "click", "Request assessment"),
|
||||
("SAM tickets", "click", "SAM tickets"),
|
||||
("TMP", "click", "TMP"),
|
||||
]
|
||||
|
||||
SEARCH_READY = (
|
||||
'[placeholder*="Search"], [aria-label*="Search"], '
|
||||
'[placeholder*="Hledat"], [aria-label*="Hledat"]'
|
||||
)
|
||||
|
||||
|
||||
def wait_ready(page):
|
||||
page.wait_for_load_state("domcontentloaded")
|
||||
page.wait_for_selector(SEARCH_READY, timeout=30_000)
|
||||
|
||||
|
||||
def navigate_to_folder(page, nav_type, value):
|
||||
if nav_type == "url":
|
||||
page.goto(value)
|
||||
wait_ready(page)
|
||||
else:
|
||||
# klik na text v levém panelu — čekej na viditelný element
|
||||
loc = page.locator(f'div[role="treeitem"]:has-text("{value}")').last
|
||||
loc.wait_for(state="visible", timeout=10_000)
|
||||
loc.click()
|
||||
page.wait_for_timeout(1_500)
|
||||
|
||||
|
||||
def download_first_eml(page, tmp_dir):
|
||||
"""Klikne na první zprávu, pravý klik → Download → EML.
|
||||
Vrátí (path, suggested_filename) nebo None pokud složka prázdná."""
|
||||
|
||||
msgs = page.locator('div[role="option"]')
|
||||
if msgs.count() == 0:
|
||||
# zkus počkat chvíli
|
||||
try:
|
||||
page.wait_for_selector('div[role="option"]', timeout=5_000)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
first = msgs.first
|
||||
if not first.is_visible():
|
||||
return None
|
||||
|
||||
first.click()
|
||||
page.wait_for_timeout(800)
|
||||
first.click(button="right")
|
||||
page.wait_for_timeout(700)
|
||||
|
||||
# Najdi "Download" v menu
|
||||
download_parent = None
|
||||
for name in ("Download", "Stáhnout"):
|
||||
loc = page.get_by_role("menuitem", name=name).first
|
||||
if loc.count() and loc.is_visible():
|
||||
download_parent = loc
|
||||
break
|
||||
|
||||
if download_parent is None:
|
||||
print(" ! 'Download' položka v menu nenalezena — přeskakuji")
|
||||
page.keyboard.press("Escape")
|
||||
return None
|
||||
|
||||
download_parent.hover()
|
||||
page.wait_for_timeout(600)
|
||||
|
||||
eml_item = None
|
||||
for name in ("Download as EML", "Stáhnout jako EML", "Stáhnout jako .eml"):
|
||||
loc = page.get_by_role("menuitem", name=name).first
|
||||
if loc.count() and loc.is_visible():
|
||||
eml_item = loc
|
||||
break
|
||||
|
||||
try:
|
||||
target = eml_item if eml_item else download_parent
|
||||
with page.expect_download(timeout=20_000) as dl_info:
|
||||
target.click()
|
||||
dl = dl_info.value
|
||||
out_path = Path(tmp_dir) / (dl.suggested_filename or "email.eml")
|
||||
dl.save_as(str(out_path))
|
||||
return out_path
|
||||
except Exception as e:
|
||||
print(f" ! Stažení selhalo: {e}")
|
||||
page.keyboard.press("Escape")
|
||||
return None
|
||||
|
||||
|
||||
def save_eml(folder_name, eml_path):
|
||||
OUT_DIR.mkdir(exist_ok=True)
|
||||
# Název souboru: složka__původní_název.eml
|
||||
safe = folder_name.replace(" ", "_").replace("/", "-")
|
||||
dest = OUT_DIR / f"{safe}__{eml_path.name}"
|
||||
if dest.exists():
|
||||
dest.unlink()
|
||||
dest.write_bytes(eml_path.read_bytes())
|
||||
print(f" + uloženo: {dest.name} ({dest.stat().st_size:,} B)")
|
||||
return dest
|
||||
|
||||
|
||||
def main():
|
||||
if not PROFILE_DIR.exists():
|
||||
print(f"Profil nenalezen: {PROFILE_DIR}")
|
||||
print("Nejprve spusť outlook_login_v1.0.py.")
|
||||
return
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
with sync_playwright() as p:
|
||||
context = p.chromium.launch_persistent_context(
|
||||
user_data_dir=str(PROFILE_DIR),
|
||||
headless=False,
|
||||
no_viewport=True,
|
||||
accept_downloads=True,
|
||||
args=[
|
||||
"--disable-blink-features=AutomationControlled",
|
||||
"--start-maximized",
|
||||
],
|
||||
)
|
||||
page = context.pages[0] if context.pages else context.new_page()
|
||||
|
||||
print("Otevírám Outlook...")
|
||||
page.goto(START_URL)
|
||||
wait_ready(page)
|
||||
|
||||
results = []
|
||||
for folder_name, nav_type, value in FOLDERS:
|
||||
print(f"\n[{folder_name}]")
|
||||
try:
|
||||
navigate_to_folder(page, nav_type, value)
|
||||
eml_path = download_first_eml(page, tmp_dir)
|
||||
if eml_path is None:
|
||||
print(" - složka prázdná nebo stažení selhalo")
|
||||
results.append((folder_name, "skip"))
|
||||
continue
|
||||
dest = save_eml(folder_name, eml_path)
|
||||
results.append((folder_name, f"ok → {dest.name}"))
|
||||
except Exception as e:
|
||||
print(f" ! Chyba: {e}")
|
||||
results.append((folder_name, f"error: {e}"))
|
||||
|
||||
context.close()
|
||||
|
||||
print("\n=== Výsledky ===")
|
||||
for name, status in results:
|
||||
print(f" {name:<25} {status}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user