Q:

Знаки вопроса на странице html, сгенерированной с помощью python

Вообщем, единственная проблема в том, что на странице html, которую генерирует код python, знаки вопроса. ( Кодировка  utf-8 поставлена )
Вот коды:

generate_index.py
from datetime import datetime as dt
from horoscope import generate_prophecies

#body = generate_body(header="Гороскоп на 2012-12-12", paragraphs=generated_prophecies)

def generate_head(title):
    head =  "<meta charset='utf-8'>" + "<title>" + title + "</title>" 
    return "<head>" + head + "</head>"

def generate_page(head, body):
    page = "<html>" + head + body + "</html>"
    return page

def generate_body(header, paragraphs):
    body = "<h1>" + header + "</h1>"
    for p in paragraphs:
        body = body + "<p>" + p + "</p>"
    return "<body>" + body + "</body>"

def save_page(title, header, paragraphs, output="index.html"):
    fp = open(output, "w")
    today = dt.now().date()
    page = generate_page(
            head= generate_head(title),
            body= generate_body(header=header, paragraphs=paragraphs)
        )
    print(page, file=fp)
    fp.close()

body = generate_body(header="Гороскоп на 2012-12-12", paragraphs=generate_prophecies())

today = dt.now().date()
save_page(
    title="Гороскоп на сегодня",
    header="Что день " + str(today) + " готовит",
    paragraphs=generate_prophecies()
    )

horoscope.py
import random

times = ["утром", "днём", "вечером", "ночью", "после обеда", "перед сном"]
advices = ["ожидайте", "предостерегайтесь", "будьте открыты для"]
promises = ["гостей из забытого прошлого", "встреч со старыми знакомыми",
            "неожиданного праздника", "приятных перемен"]

def generate_prophecies(total_num=5, num_sentences=3):
    prophecies = []

    i = 0
    while i < total_num:
        j = 0
        forecast = ""
        while j < num_sentences:
            t = random.choice(times)
            a = random.choice(advices)
            p = random.choice(promises)

            full_sentence = t.title() + " " + a + " " + p + "."
            if j != num_sentences - 1:
                full_sentence = full_sentence + " "

            forecast = forecast + full_sentence
            j = j + 1

        prophecies.append(forecast)
        i = i + 1

    return prophecies

А в самом файле index.html вот что:
<html><head><meta charset='utf-8'><title>Ãîðîñêîï íà ñåãîäíÿ</title></head><body><h1>×òî äåíü 2020-06-21 ãîòîâèò</h1><p>Âå÷åðîì ïðåäîñòåðåãàéòåñü ïðèÿòíûõ ïåðåìåí. Íî÷üþ áóäüòå îòêðûòû äëÿ ïðèÿòíûõ ïåðåìåí. Íî÷üþ ïðåäîñòåðåãàéòåñü âñòðå÷ ñî ñòàðûìè çíàêîìûìè.</p><p>Äí¸ì îæèäàéòå ïðèÿòíûõ ïåðåìåí. Ïåðåä Ñíîì áóäüòå îòêðûòû äëÿ ãîñòåé èç çàáûòîãî ïðîøëîãî. Ïîñëå Îáåäà áóäüòå îòêðûòû äëÿ íåîæèäàííîãî ïðàçäíèêà.</p><p>Íî÷üþ áóäüòå îòêðûòû äëÿ íåîæèäàííîãî ïðàçäíèêà. Âå÷åðîì áóäüòå îòêðûòû äëÿ ãîñòåé èç çàáûòîãî ïðîøëîãî. Óòðîì ïðåäîñòåðåãàéòåñü âñòðå÷ ñî ñòàðûìè çíàêîìûìè.</p><p>Íî÷üþ îæèäàéòå ïðèÿòíûõ ïåðåìåí. Ïîñëå Îáåäà áóäüòå îòêðûòû äëÿ ïðèÿòíûõ ïåðåìåí. Ïîñëå Îáåäà îæèäàéòå ïðèÿòíûõ ïåðåìåí.</p><p>Íî÷üþ áóäüòå îòêðûòû äëÿ ïðèÿòíûõ ïåðåìåí. Äí¸ì áóäüòå îòêðûòû äëÿ ãîñòåé èç çàáûòîãî ïðîøëîãî. Óòðîì ïðåäîñòåðåãàéòåñü âñòðå÷ ñî ñòàðûìè çíàêîìûìè.</p></body></html>
Честно говоря, у меня даже нет идей, я код просмотрел несколько раз.

A:

При открытии файла на запись нужно указать ту же кодировку, что указана в теге <meta charset='...'>, в данном случае - utf-8:
def save_page(title, header, paragraphs, output="index.html"):
    fp = open(output, "w", encoding='utf-8')
    today = dt.now().date()
    page = generate_page(
            head= generate_head(title),
            body= generate_body(header=header, paragraphs=paragraphs)
        )
    print(page, file=fp)
    fp.close()

