Add script, readme and requirements.

This commit is contained in:
enricoschroeder 2025-07-23 10:43:53 +02:00
parent e395e76562
commit 0f532bd16a
4 changed files with 134 additions and 1 deletions

2
.gitignore vendored
View File

@ -168,3 +168,5 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder. # option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/ #.idea/
pdfs/
export/

View File

@ -1,3 +1,39 @@
# moodle_quiz_pdf_export # moodle_quiz_pdf_export
Kleines Script, um Moddle Quizzes/Tests von Studierenden automatisiert als PDF zu exportieren. Kleines Script, um Moddle Quizzes/Tests von Studierenden automatisiert als PDF zu exportieren.
# Installation
Requirements installieren:
```
pip install -r requirements.txt
```
# Konfiguration
Eine Textdatei `.env` im Hauptverzeichnis anlegen mit folgenden Inhalten und entsprechend anpassen:
```
MOODLE_URL="https://elearning.ohmportal.de"
QUIZ_ATTEMPTS_URL="URL der Ergebnisübersicht des Tests"
USERNAME="Moodle Username"
PASSWORD="Moodle Passwort"
PDF_OUTPUT_DIR="Gewünschtes Ausgabeverzeichnis"
```
**Hinweis:** `QUIZ_ATTEMPTS_URL` sollte die vollständige URL der Ergebnisübersicht des Moodle Tests sein, ggf. inklusive der gewünschten Filter (z.B. Gruppe) sowie einer Seitengröße, die alle Versuche anzeigt. Das Skript extrahiert die Versuche der Studierenden aus dieser Seite, d.h. es werden genau diejenigen Versuche exportiert, die bei Aufruf der URL in der Tabelle sichtbar sind.
# Ausführen
Das Skript ausführen.
```
python moodle_quiz_pdf_export.py
```
Es sollte eine Ausgabe ähnlich wie unten erscheinen und die PDF-Dateien im gewünschten Ordner gespeichert werden.
```
Found 53 attempt URLs.
[1/53] Downloading: https://elearning.ohmportal.de/mod/quiz/review.php?attempt=241863
[2/53] Downloading: https://elearning.ohmportal.de/mod/quiz/review.php?attempt=241865
[3/53] Downloading: https://elearning.ohmportal.de/mod/quiz/review.php?attempt=241866
...
[53/53] Downloading: https://elearning.ohmportal.de/mod/quiz/review.php?attempt=241948
✅ All PDFs downloaded.
```

93
moodle_quiz_pdf_export.py Normal file
View File

@ -0,0 +1,93 @@
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
import time
import os
import base64
import dotenv
# Load configuration variables from .env File
dotenv.load_dotenv()
MOODLE_URL = os.getenv('MOODLE_URL')
QUIZ_ATTEMPTS_URL = os.getenv('QUIZ_ATTEMPTS_URL')
USERNAME = os.getenv('USERNAME')
PASSWORD = os.getenv('PASSWORD')
PDF_OUTPUT_DIR = os.getenv('PDF_OUTPUT_DIR')
# Ensure output directory exists
os.makedirs(PDF_OUTPUT_DIR, exist_ok=True)
# Chrome options for headless PDF printing
chrome_options = Options()
chrome_options.add_argument('--headless=new') # use --headless=new for Chrome v112+
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--kiosk-printing')
chrome_prefs = {
"printing.print_preview_sticky_settings.appState": '{"recentDestinations":[{"id":"Save as PDF","origin":"local"}],"selectedDestinationId":"Save as PDF","version":2}',
"savefile.default_directory": PDF_OUTPUT_DIR
}
chrome_options.add_experimental_option("prefs", chrome_prefs)
chrome_options.add_argument('--disable-popup-blocking')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--print-to-pdf-no-header')
# Start driver
driver = webdriver.Chrome(options=chrome_options)
# --- LOGIN ---
driver.get(MOODLE_URL)
driver.find_element(By.ID, "username").send_keys(USERNAME)
driver.find_element(By.ID, "password").send_keys(PASSWORD)
driver.find_element(By.ID, "loginbtn").click()
time.sleep(2)
# --- GO TO QUIZ RESULTS PAGE ---
driver.get(QUIZ_ATTEMPTS_URL)
time.sleep(3)
# --- SCRAPE ATTEMPT LINKS ---
attempt_links = []
elements = driver.find_elements(By.CSS_SELECTOR, "a[href*='review.php?attempt=']")
for elem in elements:
url = elem.get_attribute("href")
if url and url not in attempt_links:
attempt_links.append(url)
print(f"Found {len(attempt_links)} attempt URLs.")
# --- HELPER: Save PDF from current page ---
def save_pdf_from_current_page(filename):
# Call DevTools Protocol directly
result = driver.execute_cdp_cmd("Page.printToPDF", {
"format": "A4",
"printBackground": True
})
pdf_data = base64.b64decode(result['data'])
with open(filename, "wb") as f:
f.write(pdf_data)
# --- DOWNLOAD EACH AS PDF ---
for idx, url in enumerate(attempt_links, start=1):
print(f"[{idx}/{len(attempt_links)}] Downloading: {url}")
driver.get(url)
time.sleep(2)
try:
# Try to get the student's name near the profile picture
student_name_elem = driver.find_element(By.CSS_SELECTOR, "td.cell a[href*='/user/view.php']")
student_name = student_name_elem.text.strip()
except NoSuchElementException:
# Fallback if name is not found
student_name = f"student_{idx}"
# Clean the name for filename use
safe_name = "".join(c for c in student_name if c.isalnum() or c in ('_', '-'))
filename = os.path.join(PDF_OUTPUT_DIR, f"{safe_name}.pdf")
save_pdf_from_current_page(filename)
print("✅ All PDFs downloaded.")
driver.quit()

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
selenium
dotenv