Генерация PDF документов для упражнений по программированию на Python
Введение в создание PDF с задачами по Python
Учебные материалы часто требуют распространения в формате PDF, сохраняющем структуру и шрифты. Рассмотрены способы автоматической генерации PDF с условиями задач по Python с помощью различных библиотек.
Как создать PDF с задачами, используя библиотеку ReportLab?
Цель: Получить гибко настраиваемый PDF с текстом задач, возможностью вставки формул и таблиц.
Решение: Библиотека ReportLab предоставляет низкоуровневый доступ к построению страниц. Для работы с кириллицей требуется регистрация шрифта.
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
pdfmetrics.registerFont(TTFont('DejaVu', 'DejaVuSans.ttf'))
c = canvas.Canvas('zadachi.pdf', pagesize=A4)
width, height = A4
c.setFont('DejaVu', 14)
c.drawString(50, height - 50, 'Задача 1. Сумма чисел')
c.setFont('DejaVu', 12)
c.drawString(50, height - 80, 'Напишите функцию, которая принимает список чисел и возвращает их сумму.')
c.save()задачи python pdf (задачи по python в формате pdf)
Пояснение: После регистрации шрифта DejaVuSans (скачайте его) кириллица отображается корректно. Canvas рисует строки в абсолютных координатах.
Проблема: Шрифт не найден. Решение: указать полный путь к файлу .ttf или использовать встроенный шрифт Helvetica (не поддерживает кириллицу).
Как упростить создание PDF с задачами через библиотеку FPDF2?
Цель: Быстрое прототипирование PDF с автоматическим переносом строк.
Решение: FPDF2 предоставляет класс FPDF с методами add_font, cell, multi_cell.
from fpdf import FPDF
pdf = FPDF()
pdf.add_page()
pdf.add_font('DejaVu', '', 'DejaVuSans.ttf', uni=True)
pdf.set_font('DejaVu', size=14)
pdf.cell(200, 10, text='Задача 2. Факториал', new_x='LMARGIN', new_y='NEXT')
pdf.set_font('DejaVu', size=12)
pdf.multi_cell(0, 10, text='Вычислите факториал числа, введённого пользователем.')
pdf.output('zadachi_fpdf2.pdf')уроки и задачи python (уроки и задачи по python)
Пояснение: multi_cell автоматически разбивает текст на строки. Преимущество: не нужно вычислять координаты вручную.
Ошибка: Кириллица отображается как кракозябры. Решение: при добавлении шрифта обязательно указать uni=True и использовать .ttf файл с поддержкой Unicode.
Как создать PDF из HTML шаблона с задачами с помощью WeasyPrint?
Цель: Использовать привычный HTML/CSS для оформления, затем преобразовать в PDF.
Решение: Библиотека WeasyPrint преобразует HTML и CSS в PDF.
from weasyprint import HTML
html_content = '''
<h2>Задача 3. Чётные числа</h2>
<p>Выведите все чётные числа от 1 до 100 в одну строку.</p>
'''
HTML(string=html_content).write_pdf('zadachi_weasy.pdf')Пояснение: Можно подгружать CSS из файла или использовать встроенные стили. Случай использования: когда дизайн сложный (таблицы, списки, цвета).
Проблема: Неправильное отображение кириллицы. Решение: указать кодировку в HTML <meta charset='utf-8'> и использовать шрифты, поддерживающие кириллицу (например, через @font-face).
Расширенные примеры создания PDF с задачами по Python
Многостраничный PDF с нумерацией страниц (ReportLab)
Создание документа с несколькими десятками задач, автоматическая нумерация страниц и колонтитулы.
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
from reportlab.lib.units import mm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
pdfmetrics.registerFont(TTFont('DejaVu', 'DejaVuSans.ttf'))
def draw_page(c, page_num):
c.setFont('DejaVu', 8)
c.drawRightString(200*mm, 10*mm, f'Страница {page_num}')
c.drawString(20*mm, 10*mm, 'Курс Python. Задачи')
c = canvas.Canvas('many_tasks.pdf', pagesize=A4)
width, height = A4
tasks = ['Задача {}: ...'.format(i) for i in range(1, 31)]
page_num = 1
y = height - 30
for task in tasks:
if y < 50:
draw_page(c, page_num)
c.showPage()
page_num += 1
y = height - 30
c.setFont('DejaVu', 12)
c.drawString(50, y, task)
y -= 20
# последняя страница
if y < height - 30:
draw_page(c, page_num)
c.save()Создан PDF файл 'many_tasks.pdf' с 2 страницами, содержащими 30 задач, нумерация страниц и колонтитулы.
Добавление таблицы с условиями и ответами (FPDF2)
Формирование таблицы, где в каждой строке номер задачи, условие и правильный ответ.
from fpdf import FPDF
class PDF(FPDF):
def header(self):
self.set_font('DejaVu', 'B', 12)
self.cell(0, 10, 'Таблица задач', align='C', new_x='LMARGIN', new_y='NEXT')
pdf = PDF()
pdf.add_page()
pdf.add_font('DejaVu', '', 'DejaVuSans.ttf', uni=True)
pdf.add_font('DejaVu', 'B', 'DejaVuSans-Bold.ttf', uni=True)
# заголовки
pdf.set_font('DejaVu', 'B', 10)
pdf.cell(20, 10, '№', border=1)
pdf.cell(80, 10, 'Условие', border=1)
pdf.cell(50, 10, 'Ответ', border=1, new_x='LMARGIN', new_y='NEXT')
# данные
pdf.set_font('DejaVu', '', 10)
tasks_data = [
(1, 'Найти сумму 1+2+3', '6'),
(2, 'Проверить чётность числа 7', 'False'),
(3, 'Вывести 'Hello, World!'', 'Hello, World!')
]
for num, cond, ans in tasks_data:
pdf.cell(20, 10, str(num), border=1)
pdf.cell(80, 10, cond, border=1)
pdf.cell(50, 10, ans, border=1, new_x='LMARGIN', new_y='NEXT')
pdf.output('tasks_table.pdf')PDF с таблицей из 3 строк задач, каждая ячейка имеет границы.
Генерация PDF с использованием шаблонов Jinja2 и WeasyPrint
Динамическое создание HTML из шаблона, затем преобразование в PDF.
from jinja2 import Template
from weasyprint import HTML
template = Template('''
<!DOCTYPE html>
<html>
<head><meta charset='utf-8'></head>
<body>
<h1>Задачи по Python</h1>
{% for task in tasks %}
<div class='task'>
<h3>Задача {{ task.num }}</h3>
<p>{{ task.text }}</p>
</div>
{% endfor %}
</body>
</html>
''')
tasks = [
{'num': 1, 'text': 'Напишите программу для перевода градусов Цельсия в Фаренгейты.'},
{'num': 2, 'text': 'Создайте класс Car с методами start и stop.'}
]
html = template.render(tasks=tasks)
HTML(string=html).write_pdf('tasks_jinja_weasy.pdf')Сформирован PDF с HTML стилизацией, заголовками и отступами, автоматически подставляются данные из словаря.
Извлечение задач из существующего PDF с помощью pdfplumber
Обратная задача: прочитать PDF с условиями и обработать их. Пример извлечения текста всех страниц.
import pdfplumber
with pdfplumber.open('tasks.pdf') as pdf:
for page_num, page in enumerate(pdf.pages, start=1):
text = page.extract_text()
print(f'Страница {page_num}:')
print(text[:200]) # первые 200 символовСтраница 1: Задача 1. Сумма чисел Напишите функцию, которая принимает список чисел и возвращает их сумму. ...
Примечание: pdfplumber хорошо работает с текстовыми PDF, но не подходит для отсканированных документов.