martes, 21 de julio de 2020

Tablas HTML a Tablas de Excel


Este programa extrae todas las tabulaciones tradicionales en en un archivo HTML local y las guarda en un archivo de Excel, donde cada tabla tendrá su hoja. En este ejemplo se extrae el texto o los links de las imagenes dependiendo de lo que contenga la tabla..



Para correr este programa se requiere Python 3 y las librerías conocidas como wxpython, Beautifulsoup y oprnpyxl. Se instalan fácilmente usando pip.

El código fuente esta comentado para que sepas lo que sucede.

import wx
import wx.lib.agw.hyperlink as hl
from   os              import getcwd
from   openpyxl        import Workbook
from   openpyxl.styles import Border,Side, Alignment, Font, Color, PatternFill
from   bs4             import BeautifulSoup

class MyFrame(wx.Frame):
    def __init__(self, parent, title ="Extractor de Tablas HTML"):
        super().__init__(parent, title = title , size = (600,240))
        self.SetMinSize(size = (600,240)) #Set minimum size to current
        self.locale   = wx.Locale(wx.LANGUAGE_ENGLISH) # Fix locale unknown error
        self.Dir    = ""                       #directorio por defecto
        self.DirSve = getcwd()+"\DefaultName.xlsx" #directorio por defecto guardar
        self.wb = Workbook()
        #--------------------------------------------------
        #                   Widgets
        #---------------------------------------------------
        self.CreateStatusBar()
        self.SetStatusText("")

        panel = wx.Panel(self, wx.ID_ANY)

        BtnDirSrch = wx.Button(panel, label="HTML")
        self.TxtDirSrch = wx.TextCtrl( panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        self.TxtDirSrch.SetEditable(False)
        self.TxtDirSrch.SetValue("")

        BtnDirRes = wx.Button(panel, label="Dir. Guardar")
        self.TxtDirRes = wx.TextCtrl( panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        self.TxtDirRes.SetEditable(False)
        self.TxtDirRes.SetValue(self.DirSve)
        
        BtnProcesar = wx.Button(panel, label="Crear Tabla de Excel")

        LblDeveloper = wx.StaticText(panel,-1, style = wx.ALIGN_CENTER | wx.ST_ELLIPSIZE_MIDDLE) 
        LblDeveloper.SetLabel("http://mecatroncharly.blogspot.com") 
        LblDeveloper.SetForegroundColour((255,255,255)) 
        LblDeveloper.SetBackgroundColour((0,0,0))

        hyper1 = hl.HyperLinkCtrl(panel, -1, "http://mecatroncharly.blogspot.com",
                                  URL="http://mecatroncharly.blogspot.com")
        hyper1.SetColours("BLUE", "BLUE", "BLUE")
        #--------------------------------------------------
        #                   BINDS
        #--------------------------------------------------
        BtnProcesar.Bind(wx.EVT_BUTTON, self.onProcesar )
        BtnDirSrch .Bind(wx.EVT_BUTTON, self.onSetDirHtml)
        BtnDirRes  .Bind(wx.EVT_BUTTON, self.onSetDirSve )
        #--------------------------------------------------
        #                   LAYOUT
        #--------------------------------------------------
        MainSizer = wx.BoxSizer(wx.VERTICAL)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        
        sizerBtns = wx.BoxSizer(wx.VERTICAL)
        sizerDir  = wx.BoxSizer(wx.VERTICAL)
        sizerBtns.Add(BtnDirSrch, 0, wx.ALL|wx.CENTER, 5)
        sizerBtns.Add(BtnDirRes,  0, wx.ALL|wx.CENTER, 5)

        sizerDir.Add(self.TxtDirSrch,   1, wx.ALL|wx.CENTER|wx.EXPAND, 5)
        sizerDir.Add(self.TxtDirRes,    1, wx.ALL|wx.CENTER|wx.EXPAND, 5)
        
        sizer.Add(sizerBtns, 0,wx.EXPAND)
        sizer.Add(sizerDir,  1,wx.EXPAND)
        
        MainSizer.Add(sizer,      0,wx.EXPAND)
        MainSizer.Add(BtnProcesar,1,wx.EXPAND,5)
        MainSizer.Add(hyper1,0,wx.EXPAND,5)
        panel.SetSizer(MainSizer)
        
    def onProcesar (self, event):
        if self.Dir == '': #prevenir errores causados por descuido del usiario.
            wx.MessageBox('No has elegido el archivo HTML', 'Info', wx.OK | wx.ICON_INFORMATION)
            return
        
        GetBusy = wx.BusyInfo("Procesandio, por favor espere", self) #Mostrar Leyenda (ocupado)
        #-----------------------------------------------------------------------------------------
        file = open(self.Dir, 'r')              # abrir archivo
        theString = file.read()                 # Obtener texto
        soup = BeautifulSoup(theString, 'lxml') # frasear el archivo HTML
        tables = soup.find_all('table')         # Encontrar tablas HTML
        
        #-----------------------------------------------------
        #         Estilos a usar en la hoja de Excel
        #-----------------------------------------------------
        Borders = Border(left  = Side(style='thin'),
                        right  = Side(style='thin'),
                        top    = Side(style='thin'),
                        bottom = Side(style='thin'))
        ALCentered = Alignment(horizontal = 'center',vertical = 'center')
        FuenteHdr = Font(bold = True) 
        #-----------------------------------------------------
        #    Iterar sobre las tablas que fueron encontradas
        #-----------------------------------------------------
        for x in range(len(tables)): #iterar sobre las tablas
            ws = self.wb.create_sheet('Tabla '+str(x+1))
            self.wb.active = x
            HdrCols = 1
            #-----------------------------------------------------
            #   Encontrar encabezados y ponerlos en el documento
            #-----------------------------------------------------
            for Hdr in tables[x].find_all('th'): #iterar sobre encabezados de esta tabla
                ws.cell(row    = 1,
                        column = HdrCols,
                        value  = Hdr.get_text()).border = Borders
                ws.cell(row    = 1, column = HdrCols).alignment = ALCentered
                ws.cell(row    = 1, column = HdrCols).font = FuenteHdr
                HdrCols += 1
                #-----------------------------------------------------
                #          Encontrar Datos de la tabla
                #-----------------------------------------------------
                row_marker = 0
            for row in tables[x].find_all('tr'):
                columns = row.find_all('td')
                column_marker = 1
                row_marker += 1
                for column in columns:
                    img = column.find('img') #encontrar si tiene una imagen
                    if img:                  #Si tiene una imagen, extraer el link
                        txtImg = img.get('src')
                        ws.cell(row    = row_marker,
                                column = column_marker,
                                value  = txtImg).border = Borders
                    else:                    #Si no tiene una imagen, extraer el texto
                        ws.cell(row    = row_marker,
                                column = column_marker,
                                value  = column.get_text()).border = Borders

                    ws.cell(row    = row_marker, column = column_marker).alignment = ALCentered
                    column_marker += 1
                    
        del self.wb["Sheet"]       # hoja se crea por defecto,la borramos porque no la queremos
        self.wb.save(self.DirSve)  # Guardar
        #------------------------------------------------------------------------------------
        del GetBusy # quitar leyenda (ocupado)
        wx.MessageBox('Se ha creado la tabla de Excel', 'Info', wx.OK | wx.ICON_INFORMATION)

    def onSetDirHtml(self, event):
        wildcard = "HTML (*.html)|*.html"
        dlg = wx.FileDialog(self,
                            message     = "Choose a file",
                            defaultDir  = self.Dir, 
                            defaultFile = "",
                            wildcard    = wildcard,
                            style       = wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            self.Dir = dlg.GetPath()
            self.TxtDirSrch.SetValue(self.Dir)
        dlg.Destroy()
        print(self.Dir)

    def onSetDirSve(self, event):
        wildcard = "Archivos de Excel(*.xlsx)|*.xlsx"
        dlg = wx.FileDialog(
            self, message="Elegir dereccion y numbre", 
            defaultDir=self.DirSve, 
            defaultFile="", wildcard=wildcard, style=wx.FD_SAVE
            )
        if dlg.ShowModal() == wx.ID_OK:
            self.DirSve = dlg.GetPath()
            self.TxtDirRes.SetValue(self.DirSve)
          
        dlg.Destroy()
        print(self.DirSve)
               
app = wx.App(0)
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()


puedes usar este ejemplo de una tabla HTML: 


<!DOCTYPE html>
<html>
<head>
<style>
table, th, td {
  border: 1px solid black;
  border-collapse: collapse;
}
th, td {
  padding: 5px;
  text-align: left;
}
</style>
</head>
<body>

<h2>Table Caption</h2>
<p>To add a caption to a table, use the caption tag.</p>

<table style="width:100%">
  <caption>Monthly savings</caption>
  <tr>
    <th>Month</th>
    <th>Savings</th>
  </tr>
  <tr>
    <td>January</td>
    <td>$100</td>
  </tr>
  <tr>
    <td>February</td>
    <td>$50</td>
  </tr>
</table>

</body>
</html>

No hay comentarios.:

Publicar un comentario