lunes, 10 de agosto de 2020

BUSCAR Y BORRAR MULTIPLES ARCHIVOS

Este es un programa similar al listador de archivos (Enlace), Este programa busca  todos los archivos con algún nombre o extension en específico que esten en una direccion dada, guarda el resultado de la búsqueda en un archivo de texto tambien da la opcion de borrarlos. Muy util cuando hay muchos archivos indeseables con diferentes nombres o extensiones.

Lo modifiqué para que se pudiera buscar mas de un tipo de archivo o nomnre. Se deben poner en una lista serarada por una coma como se muestra. Al terminar la búsqueda, en la barra de estado muestra cuantos archivos encontró.

Requiere wxpython y python 3 para correr este programa.

import wx
from os      import getcwd
from os      import walk
from os      import stat
from os.path import isfile
from os      import remove


class MyFrame(wx.Frame):
    def __init__(self, parent, title ="Borrador multiple"):
        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    = getcwd() #directorio por defecto
        self.DirSve = getcwd()+"\DefaultName.txt" #directorio por defecto
        #--------------------------------------------------
        #                   Widgets
        #---------------------------------------------------
        self.CreateStatusBar()
        self.SetStatusText("")

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

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


        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)
        
        self.TxtFleToSrch = wx.TextCtrl( panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
        self.TxtFleToSrch.SetEditable(True)
        LblNombre = wx.StaticText(panel)
        LblNombre.SetLabel("extencion o nombre") 
        
        BtnProcesar = wx.Button(panel, label="BUSCAR Y GENERAR LISTA")
        BtnBorrar   = wx.Button(panel, label="BORRAR ARCHIVOS!!!!!")

        #--------------------------------------------------
        #                   BINDS
        #--------------------------------------------------
        BtnProcesar.Bind(wx.EVT_BUTTON, self.onSearch )
        BtnDirSrch .Bind(wx.EVT_BUTTON, self.onDirSrch)
        BtnDirRes  .Bind(wx.EVT_BUTTON, self.onDirSve )
        BtnBorrar  .Bind(wx.EVT_BUTTON, self.onErseFles)
        #--------------------------------------------------
        #                   LAYOUT
        #--------------------------------------------------
        MainSizer = wx.BoxSizer(wx.VERTICAL)
        
        sizrGrid = wx.FlexGridSizer(rows=3, cols=2, hgap=5, vgap=5)
        sizrGrid.AddGrowableCol(1, 1)

        sizrGrid.Add(BtnDirSrch,        0, wx.CENTER)
        sizrGrid.Add(self.TxtDirSrch,   1, wx.CENTER|wx.EXPAND)
        sizrGrid.Add(BtnDirRes,         0, wx.CENTER)
        sizrGrid.Add(self.TxtDirRes,    1, wx.CENTER|wx.EXPAND)
        sizrGrid.Add(LblNombre,         0, wx.CENTER)
        sizrGrid.Add(self.TxtFleToSrch, 0, wx.CENTER|wx.EXPAND)
        
        MainSizer.Add(sizrGrid,   0,wx.ALL|wx.EXPAND,5)
        MainSizer.Add(BtnProcesar,1,wx.ALL|wx.EXPAND,5)
        MainSizer.Add(BtnBorrar,  1,wx.ALL|wx.EXPAND,5) 
        panel.SetSizer(MainSizer)

    def cleanText(self):
        #-------------------------------------------
        #     Palabras no necesarias
        #-------------------------------------------
        quitar = ['',  #en blanco 
                  'de',
                  'del',
                  'el',
                  'la',
                  'los',
                  'las',
                  'y',
                  'en',
                  'con',
                  'para',
                  'por',
                  'a',
                  'desde',
                  'hacia',
                  'excepto',
                  'entre',
                  'sin',
                  'sobre',
                  'tras',
                  'contra',
                  'hasta',
                  'durante',
                  'mediante',
                  'también',
                  'tambien']
        
        FindValue = self.TxtFleToSrch.GetValue()  # obtener texto
        #----------------------------------------------
        #               Tokenizar
        #----------------------------------------------
        FindValue = FindValue.replace(" ",",")
        words = FindValue.split(',')
        for x in quitar:
                while x in words: # quitar de la lista palaras inesesarias
                    words.remove(x)
        return words
        
    def onSearch (self, event):
        DirValuesFound = []
        List = self.cleanText()              
        
        GetBusy = wx.BusyInfo("Procesandio, por favor espere", self) #Mostrar Leyenda (ocupado)
        for root, dirs, files in walk(self.Dir):
            for file in files:
                for value in List:
                    if str(file).find(value) != -1:
                        DirValuesFound.append(root+'/'+str(file)) # Direccion completa
            
        file = open(self.DirSve,'w')
        for x in DirValuesFound:
            file.write(x+"\n")
        file.close()
        self.SetStatusText("Se encontraron " + str(len(DirValuesFound))+ " archivos.")
        del GetBusy # quitar leyenda (ocupado)

    def onErseFles(self, evt):
        RemovedCount = 0
        if isfile(self.DirSve): #archivo existe
            if not stat(self.DirSve).st_size == 0: # lista no vacia
                file = open(self.DirSve,'r')
                filesList = file.read().splitlines()
                file.close()
                for file in filesList:
                    try:
                        remove(file)
                        RemovedCount += 1
                    except:
                        pass
                self.SetStatusText("Se borraron " + str(RemovedCount)+ " archivos.")             
        else:
            self.SetStatusText('No has realizado ninguna busqueda \no el archivo generado fue borrado')

    def onDirSrch(self, event):
        dlg = wx.DirDialog(self, "Elegir directorio de busqueda:",
                           style=wx.DD_DEFAULT_STYLE
                           #| wx.DD_DIR_MUST_EXIST
                           #| wx.DD_CHANGE_DIR
                           )
        if dlg.ShowModal() == wx.ID_OK:
            self.Dir = dlg.GetPath()
            self.TxtDirSrch.SetValue(self.Dir)
        dlg.Destroy()

    def onDirSve(self, event):
        wildcard = "Text Files (*.txt)|*.txt"
        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()
               
app = wx.App(0)
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show()
app.MainLoop()

miércoles, 22 de julio de 2020

¿Por qué usar Fedora en lugar de Ubuntu?



Antes que nada, debo decir que ambas son excelentes distribuciones y aunque son muy similares tanto en en la forma de usar como en su apariencia, hay varias cosas que las distinguen entre si. Para empezar Fedora esta patrocinada por Red Hat Enterprices, la empresa detrás del sistema operativo Red Hat Linux (RHL por sus siglas en inglés), el sistema operativo líder mundial para servidores de nivel empresarial. Ubuntu esta patrocinado por Canonical, una empresa dedicada al desarrollo de software, quien también ofrece una versión de Ubuntu destinada a servidores.

Podría decirse que Fedora es una versión de RHL mas sofisticada. RHL prueba nuevas tecnologías en Fedora antes de incluirlo en RHL por lo que puedes usar lo último en tecnología de código abierto antes de que forme parte de RHL. Por cierto, el proyecto Fedora es uno de los mayores contribuidores de características y nuevas tecnologías a otras distribuciones Linux.

Ubuntu esta basado en Debian, una distribución bastante estable. De forma similar a Fedora, Ubuntu es una versión más sofisticada de Debian. Ubuntu se distingue de Fedora por su entorno y herramientas un tanto más amigables, para ofrecer a los usuarios una experiencia similar a Windows o Mac.

Otra diferencia es que Ubuntu utiliza el gestor de paquetes apt, que utiliza los paquetes con extensión .deb, mientras que Fedora usa dnf, que utiliza los paquetes con extensión .rpm.

Ahora que sabemos de forma general las diferencias más relevantes, podemos hacer una comparación tomando en cuenta mi experiencia personal en cuanto a ambos sistemas. Debo decir que la primera vez que probé Ubuntu me sorprendió su velocidad (comparado con windows), pero me pareció un poco “inestable” debido a que algunos programas fallaban de vez en cuando, pensé que probablemente no es culpa del sistema operativo en si, sino de las aplicaciones. Después de echar a perder Ubuntu un par de veces je je, decidí probar Fedora ya que decían que en cuestión de dificultad era el siguiente nivel, y me sentía más confiado para hacer el cambio.

Probé Fedora y es notoriamente más estable que Ubuntu, rara vez me fallaba. En ese entonces andaba la versión 15 de Fedora, y si, tenía que recurrir más seguido a la línea de comandos, pero hay muy buena información en los foros y siempre pude solucionar los problemas que surgían ocasionalmente, igual que con Ubuntu.

A la fecha (2020) Fedora y Ubuntu usan Gnome, aunque Ubuntu usa una versión modificada de Gnome para imitar el comportamiento de su entorno de escritorio anterior llamado Unity (el cual me parecía un poco lento pero más bonito que el entorno de Fedora). En cuestión de interfase gráfica, ambas son casi iguales, de hecho, los desarrolladores de Fedora se han esforzado para hacer esta distribución bastante mas amigable a comparación con las versiones de hace algunos años (y han hecho un excelente trabajo), pero debo decir que Ubuntu sigue siendo un poco más amigable.

Ubuntu 20

Fedora 32

Otra diferencia es que Fedora tiene SELinux (Security Enhanced Linux) que es un módulo para políticas para el control de acceso, creado en la Agencia de Seguridad Nacional (NSA por sus siglas en inglés).En este módulo se pueden crear o modificar dichas políticas de seguridad de acuerdo con las necesidades del usuario. Suena bien, pero esta seguridad conlleva en ocasiones problemas para correr algunos programas que requieren más libertad. Ubuntu no cuenta con SELinux por defecto, por lo que nunca tuve problemas con eso.

En cuanto a Drivers se refiere, Fedora y Ubuntu me han dado algunos dolores de cabeza con los controladores gráficos de tarjetas nVidia (yo creo que a todos los que usamos Linux je je). Pero hay que mencionar que Ambas distribuciones corren excelente en computadoras con gráficos integrados basados en Intel, debido a que Intel es más amigable con la comunidad del código abierto,y sus drivers están integrados en el Kernel Linux. Tambien debo decir que Fedora soporta una gran cantidad de hardware de nueva generación, Ubuntu después se pone al corriente con las contribuciones de Fedora y en ocasiones viceversa.

Fedora se ha convertido en una distribución semi-rolling-release es decir, en lugar de tener que formatear el disco duro para instalar una nueva versión, en Fedora se puede actualizar a la versión más reciente sin perder los archivos guardados. Ocasionalmente pueden aparecer dificultades por actualizaciones, pero por lo regular se encuentra la solución en los foros.

Como un anuncio, puedes optar por CentOS si quieres estabilidad excepcional de forma gratuita. CentOS es básicamente RHL soportado por la comunidad. CentOS no tendrá el software más reciente, ni las características rimbombantes de Fedora, ni el soporte de hardware de nueva generación, pero es sólido como una Roca. Es por eso que es tan popular para ser usado en servidores caseros, en algunas máquinas de prueba eléctrica y de visión por computadora, solo por mencionar algunos usos.

Regresando al tema, Fedora incluye varias herramientas de desarrollo por defecto como Python, LaTex, compiladores de C++, máquinas virtuales, entre otras cosas. En Ubuntu se pueden instalar opcionalmente.

En resumen, Fedora es discutiblemente más estable que Ubuntu, es casi tan amigable como Ubuntu, en mi opinión Fedora es un poco más rápido que Ubuntu, Fedora tiene SELinux, es más probable que Fedora soporte hardware de nueva generación, Fedora esta listo para iniciar a desarrollar justo después de instalar. Tanto fedora como Ubuntu corren excelentemente bien en computadoras con gráficos integrados Intel. Linus Torvals (creador de Linux) usa Fedora. Por estas razones yo prefiero Fedora.

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>