TransWikia.com

Как записать несколько DataFrame в мультистраничную книгу .xlsx используя xlsxwriter?

Stack Overflow на русском Asked by Genken on November 7, 2021

Стоит задача, спарсить (с парсингом проблем нет) несколько однообразных страничек и записать полученные данные в таблицу, причём во время парсинга каждой из страничек мы должны создать словарь, из него DataFrame, и этот DataFrame записать в отдельный лист в .xlsx книге, после чего операция повторяется.

Если нужно обработать лишь одну страничку всё нормально. Но если их несколько, возникает одна проблема: новые листы не создаются. Вместо этого, DataFrame записываются в один и тот же лист (также странно, что в конечном файле остаётся не последний DataFrame, а ВСЕ DataFrame, несмотря на то, что xlsxwriter режим append не поддерживает и в теории должен делать перезапись), и этот лист имеет название последней итерируемой странички.

Скорее всего это происходит, потому что используется один и тот же DataFrame (под именем database), имя которого не меняется и он просто обнуляется при анализе новой страницы, но я не уверен – если создать его копию, она по-прежнему записывается в один и тот же лист (хотя это может быть из-за того что я оставлял ссылку на один и тот же DataFrame, пытаясь оставить копию). Вряд ли xlsxwriter сохраняет по принципу "Сохранять в один и тот же лист, если имя DataFrame не меняется"

Код:

from bs4 import BeautifulSoup
from pandas import ExcelWriter
import pandas as pd
import os
import xlsxwriter

def nametreat(txt):                        # Это функции для обработки текста
    if txt[-1] == ')':
        bracktxt = ''
        i = 1
        while txt[-i] != '(':
            bracktxt += txt[-i]
            i += 1
        bracktxt = bracktxt[::-1]
        if 'класс' in bracktxt:
            while txt[-1] != '(':
                txt = txt[0:-1:1]
        return txt[0:-2:1]
    else:
        return txt

def spaceclear(txt):                       # Это функция для обработки текста
    while len(txt) > 0 and (txt[0] == ' ' or txt[0] == 'n'):
        txt = txt[1:]
    
    while len(txt) > 0 and (txt[-1] == ' ' or txt[-1] == 'n'):
        txt = txt[0:-1]
    
    return txt

def courseinfo(bs):
    clss_, times, month = bs.find_all('div', attrs = {'class': "course__info-item"})
    clss_, times, month = map(spaceclear, [clss_.text, times.text, month.text])
    
    nums = '0123456789'
    while clss_[-1] not in nums:
        clss_ = clss_[0:-1:1]
    if '-' not in clss_:
        start = int(clss_)
        end = start
    else:
        start, end = map(int, clss_.split('-'))
    clss_ = list(range(start, end + 1))
    
    while times[-1] not in nums:
        times = times[0:-1:1]
    times = [int(times[0]), int(times[-1])]
    
    month = list(month.split('-'))
    
    res = [clss_, times, month]
    return res

science = open('schools_science.html', encoding = 'utf-8', mode = 'r')
sport = open('schools_sport.html', encoding = 'utf-8', mode = 'r')
creative = open('schools_creative.html', encoding = 'utf-8', mode = 'r')
teaming = open('schools_teaming.html', encoding = 'utf-8', mode = 'r')
responsib = open('schools_responsib.html', encoding = 'utf-8', mode = 'r')
files = [science, sport, teaming, creative, responsib]

maindict = {
    'name': [],
    'type': [],
    'description': [],
    'text': [],
    'grades': [],
    'times_a_week': [],
    'lessons': [],
    'from_month': [],
    'to_month': []
}

database = pd.DataFrame(maindict)

tablist = ['Science', 'Sport', 'Creative', 'Teaming', 'Responsibility']
tab = 0

for file in files:
    
    soup = BeautifulSoup(file, 'lxml')
    courses = soup.find_all("div", attrs = {'class': "courses-list__item"})
    
    for cl in courses:
        maindict['type'].append(spaceclear(cl.find("div", attrs = {'class': "course__desc"}).text))
        maindict['name'].append(nametreat(spaceclear(cl.find("h2").text)))
        maindict['description'].append(spaceclear(cl.find("div", attrs = {'class': "course__big-text"}).text))
        maindict['text'].append(spaceclear(cl.find("div", attrs = {'class': "course__small-text"}).find("p").text))
        clss_, times, month = map(spaceclear, courseinfo(cl))
        maindict['grades'].append(clss_)
        maindict['times_a_week'].append(times[0])
        maindict['lessons'].append(times[1])
        maindict['from_month'].append(month[0])
        maindict['to_month'].append(month[1])
    
    database = pd.DataFrame(maindict)
    
    with ExcelWriter(path = 'schools.xlsx', engine = 'xlsxwriter') as writer:
        database.to_excel(writer, sheet_name = tablist[tab], index = False)
    writer.save()
    tab += 1
exit(0)

One Answer

Используя XlsxWriter можно создать новый excel файл с несколькими листами - пример:

import pandas as pd


# Create some Pandas dataframes from some data.
df1 = pd.DataFrame({'Data': [11, 12, 13, 14]})
df2 = pd.DataFrame({'Data': [21, 22, 23, 24]})
df3 = pd.DataFrame({'Data': [31, 32, 33, 34]})

# Create a Pandas Excel writer using XlsxWriter as the engine.
writer = pd.ExcelWriter('pandas_multiple.xlsx', engine='xlsxwriter')

# Write each dataframe to a different worksheet.
df1.to_excel(writer, sheet_name='Sheet1')
df2.to_excel(writer, sheet_name='Sheet2')
df3.to_excel(writer, sheet_name='Sheet3')

# Close the Pandas Excel writer and output the Excel file.
writer.save()

Для того, чтобы дописывать данные в существующий Excel файл, можно воспользоваться функцией append_df_to_excel():

append_df_to_excel('d:/temp/test.xlsx', df, sheet_name='Sheet2', index=False)

append_df_to_excel('d:/temp/test.xlsx', df, sheet_name='Sheet3', index=False)

Answered by MaxU on November 7, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP