HTML в Word DOCX - PullRequest
       20

HTML в Word DOCX

0 голосов
/ 15 ноября 2018

У меня есть какой-то текст в формате HTML, который я получил с BeautifulSoup. Я хотел бы преобразовать все курсив (тег i), полужирный (b) и ссылки (a href) в формат Word с помощью команды docx run.

Я могу сделать абзац:

p = document.add_paragraph('text')

Я могу добавить следующую последовательность жирным шрифтом / курсивом:

p.add_run('bold').bold = True
p.add_run('italic.').italic = True

Интуитивно, я мог бы найти все конкретные теги (т. Е. soup.find_all('i')), а затем наблюдать за индексами и затем объединять частичные строки ...

... но, может быть, есть лучший, более элегантный способ?

Мне не нужны библиотеки или решения, которые просто конвертируют html-страницу в слово и сохраняют их. Я хочу немного больше контроля.

Я ничего не получил со словарем. Вот код и визуально неправильный (из кода) и правильный (желательный) результат:

from docx import Document
import os
from bs4 import BeautifulSoup

html = '<a href="http://someurl.you">hi, I am link</a> this is some nice regular text. <i> oooh, but I am italic</i> ' \
        ' or I can be <b>bold</b> '\
        ' or even <i><b>bold and italic</b></i>'

def get_tags(text):
    soup = BeautifulSoup(text, "html.parser")
    tags = {}
    tags["i"] = soup.find_all("i")
    tags["b"] = soup.find_all("b")

    return tags


def make_test_word():
    document = Document()

    document.add_heading('Demo HTML', 0)

    soup = BeautifulSoup(html, "html.parser")

    p = document.add_paragraph(html)

    # p.add_run('bold').bold = True
    # p.add_run(' and some ')
    # p.add_run('italic.').italic = True

    file_name="demo_html.docx"
    document.save(file_name)
    os.startfile(file_name)


make_test_word()

enter image description here

1 Ответ

0 голосов
/ 14 мая 2019

Я только что написал немного кода для преобразования текста из текстового виджета tkinter в текстовый документ, включая любые полужирные теги, которые может добавить пользователь. Это не полное решение для вас, но оно может помочь вам перейти к рабочему решению. Я думаю, что вам придется выполнить некоторые регулярные выражения, чтобы перенести гиперссылки на документ Word. Сложенные теги форматирования могут также стать хитрыми. Надеюсь, это поможет:

from docx import Document

html = 'HTML string <b>here</b>.'

html = html.split('<')
html = [html[0]] + ['<'+l for l in html[1:]]
doc = Document()
p = doc.add_paragraph()
for run in html:
    if run.startswith('<b>'):
        run = run.lstrip('<b>')
        runner = p.add_run(run)
        runner.bold = True
    elif run.startswith('</b>'):
        run = run.lstrip('</b>')
        runner = p.add_run(run)
    else:
        p.add_run(run)
doc.save('test.docx')

Я вернулся к нему и дал возможность разобрать несколько тегов форматирования. Это позволит узнать, какие теги форматирования используются в списке. Для каждого тега создается новый цикл, и форматирование для цикла задается текущими тегами в игре.

from docx import Document
import re
import docx
from docx.shared import Pt
from docx.enum.dml import MSO_THEME_COLOR_INDEX

def add_hyperlink(paragraph, text, url):
    # This gets access to the document.xml.rels file and gets a new relation id value
    part = paragraph.part
    r_id = part.relate_to(url, docx.opc.constants.RELATIONSHIP_TYPE.HYPERLINK, is_external=True)

    # Create the w:hyperlink tag and add needed values
    hyperlink = docx.oxml.shared.OxmlElement('w:hyperlink')
    hyperlink.set(docx.oxml.shared.qn('r:id'), r_id, )

    # Create a w:r element and a new w:rPr element
    new_run = docx.oxml.shared.OxmlElement('w:r')
    rPr = docx.oxml.shared.OxmlElement('w:rPr')

    # Join all the xml elements together add add the required text to the w:r element
    new_run.append(rPr)
    new_run.text = text
    hyperlink.append(new_run)

    # Create a new Run object and add the hyperlink into it
    r = paragraph.add_run ()
    r._r.append (hyperlink)

    # A workaround for the lack of a hyperlink style (doesn't go purple after using the link)
    # Delete this if using a template that has the hyperlink style in it
    r.font.color.theme_color = MSO_THEME_COLOR_INDEX.HYPERLINK
    r.font.underline = True

    return hyperlink

html = '<H1>I want to</H1> <u>convert HTML <a href="http://www.google.com">to docx</a> in <b>bold and <i>bold italic</i></b>.</u>'

html = html.split('<')
html = [html[0]] + ['<'+l for l in html[1:]]
tags = []
doc = Document()
p = doc.add_paragraph()
for run in html:
    tag_change = re.match('(?:<)(.*?)(?:>)', run)
    if tag_change != None:
        tag_strip = tag_change.group(0)
        tag_change = tag_change.group(1)
        if tag_change.startswith('/'):
            if tag_change.startswith('/a'):
                tag_change = next(tag for tag in tags if tag.startswith('a '))
            tag_change = tag_change.strip('/')
            tags.remove(tag_change)
        else:
            tags.append(tag_change)
    else:
        tag_strip = ''
    hyperlink = [tag for tag in tags if tag.startswith('a ')]
    if run.startswith('<'):
        run = run.replace(tag_strip, '')
        if hyperlink:
            hyperlink = hyperlink[0]
            hyperlink = re.match('.*?(?:href=")(.*?)(?:").*?', hyperlink).group(1)
            add_hyperlink(p, run, hyperlink)
        else:
            runner = p.add_run(run)
            if 'b' in tags:
                runner.bold = True
            if 'u' in tags:
                runner.underline = True
            if 'i' in tags:
                runner.italic = True
            if 'H1' in tags:
                runner.font.size = Pt(24)
    else:
        p.add_run(run)
doc.save('test.docx')

Функция гиперссылки благодаря этому вопросу . Меня беспокоит то, что вам нужно будет вручную кодировать каждый HTML-тег, который вы хотите перенести в документ. Я полагаю, что это может быть большое количество. Я привел несколько примеров тегов, которые вы, возможно, захотите учесть.

...