Olá a todos, este artigo apresentará como usar Python para implementar facilmente a escrita de documentos, reduzir a dificuldade de escrever relatórios e usar o Microsoft Word e python
bibliotecas python-docx
para simplificar a escrita de relatórios e extrair informações dos relatórios.
Caso
-
Leia um documento do Word e edite-o.
Embora possa não parecer muito interessante, dependendo do sistema suportado, o tempo necessário para produzir relatórios pode ser significativamente reduzido pelo uso inteligente desta configuração. O código é compartilhado e explicado abaixo, mas uma versão base do código está disponível no GitHub. É altamente recomendável modificar o código para atender a casos de uso específicos.
começar
Após utilizar pip3
a instalação python-docx
, recomenda-se dividir o programa em partes que leiam dois tipos diferentes de conteúdo, nomeadamente parágrafos e tabelas.
def tableSearch(doc):
""" Takes doc file
Purpose: Scrapes all tables and pulls back text
Returns: Dictionary of tables
"""
tables = {}
table = 0
x = 0
y = 0
while table != len(doc.tables):
logging.debug("Table {} Row: {}".format(table, len(doc.tables[table].rows)))
logging.debug("Table {} Column: {}".format(table, len(doc.tables[table].columns)))
logging.debug("Table {}".format(table))
table_test = doc.tables[table]
run = doc.add_paragraph().add_run()
font = run.font
while x != len(table_test.rows):
while y != len(table_test.columns):
logging.debug("Table: {}, X: {}, Y: {}\n{}\n".format(table, x,y,table_test.cell(x,y).text))
tables[str(table)+"."+str(x)+"."+str(y)] = {"row": x, "column": y, "text": table_test.cell(x,y).text}
y += 1
x += 1
y = 0
x = 0
y = 0
table += 1
return tables
# 读取Word文档
def wordDocx(file):
""" Takes file
Purpose: Reads the Word Doc
Returns: Nothing
"""
logging.debug("File: {}".format(file))
doc = docx.Document(file)
fullText = []
for para in doc.paragraphs:
logging.debug("Paragraph: {}".format(para.text))
fullText.append(para.text)
tableInfo = tableSearch(doc)
return [fullText, tableInfo]
parágrafo
A análise dos parágrafos é muito simples. Eles são definidos como uma lista e podem ser acessados de forma semelhante ( doc.paragraphs[n]
).
Se você quiser alterar o texto de um parágrafo, basta usar o seguinte código para modificar o texto:
oldText = doc.paragraphs[indexOfParagraph].text
replacedText = oldText.replace("<CLIENT_LONGNAME>",clientLongName)
doc.paragraphs[indexOfParagraph].text = "{} + Text to add".format(oldText)
doc.paragraphs[indexOfParagraph].text = "{} + Replaced text".format(replacedText)
Conforme mencionado acima, você pode fazer isso criando um <CLIENT_LONGNAME>
modelo de documento simples contendo palavras-chave como e, em seguida, usando um programa como este para alterar todas as instâncias de cada palavra-chave. Embora isso também possa ser alcançado abrindo um documento e realizando uma operação de localização e substituição, a infraestrutura para dar suporte a essa operação pode tornar o processo rápido de alterações manuais ainda mais rápido.
folha
As tabelas são um pouco mais complicadas, porque as tabelas são bidimensionais, enquanto os parágrafos são unidimensionais (os parágrafos são de 0 a n, enquanto as tabelas têm uma coordenada X e uma coordenada Y). Como as tabelas são tratadas de maneira diferente, é necessária uma maneira mais complexa de percorrer todas as tabelas e indexar algo dentro delas.
Outra observação importante sobre a seleção de elementos em tabelas. Embora a seleção de células exija o uso de valores x
e y
, você também precisa selecionar a tabela para referência.
table = 0
x = 0
y = 0
while table != len(doc.tables):
table_test = doc.tables[table]
while x != len(table_test.rows):
while y != len(table_test.columns):
logging.debug("Table: {}, X: {}, Y: {}\n{}\n".format(table, x,y,table_test.cell(x,y).text))
y += 1
x += 1
y = 0
x = 0
y = 0
table += 1
Iterar um programa como este serve a vários propósitos.
-
Independentemente da estrutura de cada tabela, o programa percorre cada tabela da mesma maneira.
-
Gravar e exibir a posição das células permite integrações interessantes.
Um exemplo de integração interessante é a criação de um dicionário contendo valores e suas posições para que as informações possam ser inseridas.
Embora projetar um sistema de consulta para isso esteja além do escopo deste artigo, este artigo fornece uma configuração básica para você começar:
ref = {
"Date": [0,2,12]
}
info = {
"Date": "08/24/2023"
}
for key,value in ref.items:
if table == value[0] and x == value[1] and y == value[2]:
table_test.cell(x,y).text = info[key]
Uso prolongado
Usando o mesmo sistema de loop de antes, você também pode fazer com que um programa analise as informações do relatório concluído e exporte-as para um CSV
arquivo para uso em outros programas de elaboração de relatórios. Duas plataformas de elaboração de relatórios que foram usadas e recomendadas neste artigo são PlexTrac e AttackForge. Ambas as plataformas permitem que os resultados da pesquisa sejam importados por meio de um CSV
arquivo ou arquivos especialmente formatados.JSON
Como simplificar o processo de importação de informações para outros sistemas/relatórios:
No código acima, há um código que analisa o conteúdo do objeto cada vez que ele percorre um parágrafo ou célula da tabela. Isso não só pode ser usado para depuração, como também adiciona texto a um dicionário. Isso economiza tempo na extração de dados e mais tempo na análise e reformatação dos dados extraídos.
# 段落
fullText = []
# 表格
tables = {}
fullText.append(para.text)
tables[str(table)+"."+str(x)+"."+str(y)] = {"row": x, "column": y, "text": table_test.cell(x,y).text}
Depois de adicionar essas linhas respectivamente, você pode pegar os dados e salvá-los em um formato semelhante ao modo como você acessa os dados. Depois de ter os dados e saber onde encontrá-los, você pode percorrer os respectivos objetos e criar um novo arquivo com os dados.
Como exemplo simples, este artigo adicionará uma função ao código no GitHub para salvar dados em um CSV
formato.
import docx
import logging
import argparse
import re
import sys
logging.basicConfig(level=logging.DEBUG)
# 设置日志记录
def get_arg():
""" Takes nothing
Purpose: Gets arguments from command line
Returns: Argument's values
"""
parser = argparse.ArgumentParser()
# CLI 版本
# parser.add_argument("-d","--debug",dest="debug",action="store_true",help="Turn on debugging",default=False)
parser.add_argument("-d","--debug",dest="debug",action="store_false",help="Turn on debugging",default=True)
# 文件版本
parser.add_argument("-f","--file",dest="file", help="Name of the Word Doc.")
parser.add_argument("-o","--output",dest="output", help="Name of the file to output the results.")
options = parser.parse_args()
if not options.output:
options.output = "output.csv"
if not options.file:
logging.error("Please provide a file name.")
sys.exit()
if options.debug:
logging.basicConfig(level=logging.DEBUG)
global DEBUG
DEBUG = True
else:
logging.basicConfig(level=logging.INFO)
return options
def tableSearch(doc):
""" Takes doc file
Purpose: Scrapes all tables and pulls back text
Returns: Dictionary of tables
"""
tables = {}
table = 0
x = 0
y = 0
while table != len(doc.tables):
logging.debug("Table {} Row: {}".format(table, len(doc.tables[table].rows)))
logging.debug("Table {} Column: {}".format(table, len(doc.tables[table].columns)))
logging.debug("Table {}".format(table))
table_test = doc.tables[table]
run = doc.add_paragraph().add_run()
font = run.font
while x != len(table_test.rows):
while y != len(table_test.columns):
logging.debug("Table: {}, X: {}, Y: {}\n{}\n".format(table, x,y,table_test.cell(x,y).text))
tables[str(table)+"."+str(x)+"."+str(y)] = {"row": x, "column": y, "text": table_test.cell(x,y).text}
y += 1
x += 1
y = 0
x = 0
y = 0
table += 1
return tables
# 读取word文档
def wordDocx(file):
""" Takes file
Purpose: Reads the Word Doc
Returns: Nothing
"""
logging.debug("File: {}".format(file))
doc = docx.Document(file)
fullText = []
for para in doc.paragraphs:
logging.debug("Paragraph: {}".format(para.text))
fullText.append(para.text)
tableInfo = tableSearch(doc)
return [fullText, tableInfo]
def infoToCSV(para, table):
""" Takes a list and a dictionary
Purpose: Convert dictionary and paragraph into a CSV file
Returns: Nothing
"""
csvHeaders = "Name,Description,Recommendation\n"
for key, values in table.items():
Name = ""
Description= ""
Recommendation= ""
nameRegex = re.search("0\.\d+\.1",key)
desRegex = re.search("0\.\d+\.3",key)
recRegex = re.search("0\.\d+\.6",key)
if nameRegex:
Name = value["text"]
if desRegex:
Description = value["text"]
if recRegex:
Recommendation = value["text"]
csvHeaders += "{},{},{}\n".format(Name,Description,Recommendation)
for item in para:
values = re.findall("Name\":\"(.+?)\".+?Description\":\"(.+?)\".+?Recommendation\":\"(.+?)\"",item)
try:
csvHeaders += "{},{},{}\n".format(values[0],values[1],values[2])
except IndexError:
continue
f = open("Output.csv", "w")
f.write(csvHeaders)
f.close()
def main():
options = get_arg()
logging.debug("Options: {}".format(options))
info = wordDocx(options.file)
logging.debug("Info: {}".format(info))
infoToCSV(info[0], info[1])
if __name__ == '__main__':
main()
A função precisa ser modificada dependendo do programa que está tentando importar a informação infoToCSV
. Embora isso possa ser um pouco chato, os 5 a 20 minutos gastos aqui para adaptar a função às suas necessidades valem a pena quando você precisa produzir vários relatórios. Na minha experiência com este artigo, inserir novamente essas informações manualmente pode rapidamente se tornar entediante.
limitação
Você deve ter notado neste artigo que não há nada tocando nas imagens, e há uma triste razão para isso: ele python-docx
não consegue lidar com arquivos de imagens e parece não notá-los, a menos que você o use ao adicionar eles. Para resolver esse problema, você precisa acessar o código-fonte da biblioteca e integrá-lo ou descompactar .docx
o arquivo e analisar a tag da imagem XML
e, em seguida, localizar a imagem na pasta de mídia.