Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Automatización del Pipeline

36/38
Recursos

Aportes 58

Preguntas 11

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Para los no conformes (principalmente)

Cierto, es un curso muy practico y centrado en el problema de los periodicos, personalmente aprendi mucho haciendo un proyecto totalmente diferente.
Sin embargo, es indispensable conocer Programación Orientada a Objetos y tener los entornos virtuales
Ahí, me toco probar que etiqueta HTML me servia y con prints ver que dato obtenia versus el que queria. Tambien me pase por las clases de HTML para entender un poco ese arbol.

Acá mi proyecto de verificación de precios
Observador de precios de tecnologia

Para los conformes y el profe David

Excelente curso como todos los de David, puede que una representación grafica del flujo de información le ayude a los estudiantes a entender la primera parte, pero siguiendolo con detalle sale!

A la espera de los cursos de Spark y Hadoop de la escuela de Data Science 😄

Todo este curso es FANTASTICO!!!

Si quieren ver los datos de la base de datos generada pueden poner en la terminal:

sqlite3
  • .open + la ruta donde se encuentra el archivo de la base de datos. Si vas a la carpeta donde lo tienes y pones el comando pwd te dará la ruta.
.open /ingenieria-datos-python/load/newspaper.db
  • Ver las tablas:
.tables  // articles
  • Ver el contenido de la tabla:
select * from articles;

https://github.com/fathooo/Datascience-scrapping

lo dejo en git para que los que deseen verlo, puedan compararlo con su codigo 😉 suerte, en este curso me demoré bastante. Algunos consejos.

1- Vayan lento, vean el video una vez, luego copien el codigo.
2- entiendan el codigo, busquen en internet los modulos y sus directorios.
3- tomen nota, yo ocupo principalmente notion. muestro una imagen como ejemplo
4- tranquilos si no lo entienden a la primera, continuen intentando

Les comparto mi respositorio, donde está este ejercicio (para windows) y todos los ejemeplos anteriores. https://github.com/crissebasbol/Data_engineering_python

Comparto repositorio con los apuntes del curso, hechos como guia y el proyecto en sí.
https://github.com/francomanca93/ingenieria-de-datos
.
Tambien comparto una pequeña agregación ya que me gusta tener los datasets y databases en una carpeta por sepatado dentro… Lo que hace la función es sacar el archivo generado al final y moverlo autimaticamente a una carpeta llamada database

def _to_databe_folder():
    '''ETL: Función para mover base de datos database folder.'''
    
    logger.info('Moving database to databe folder')
    database_name = 'newspaper.db'
    subprocess.run(['mv', database_name, '../database/{}'.format(database_name)],
                    cwd='./load')

He quedado muy satisfecho con este curso, de lejos el mejor de la ruta de aprendizaje.

Bueno, digamos que pude llegar al final del curso desde Windows empleando la consola de Anaconda, sin embargo, al momento de ejecutar este script me dio error desde el comando FIND (pensaba que Anaconda emplearia Linux por debajo). Igual un excelente curso

Este es uno de mis cursos favoritos, poder hacer web scrapping siempre me había parecido algo súper difícil y el profesor lo enseña aquí de la mejor forma posible.

Importante.
Esta clase y la siguiente tienen el orden intercambiado.
Toma la siguiente clase 37 cargando datos a SQLlite y luego vuelve a esta clase 36 de Automatización del Pipeline.

Este curso es un compendio de ingeniería del software aplicado a un proceso que en este caso es E.T.L.

Muy fluido el instructor!

Se cumplio el objetivo, aunque fue gracias por los aportes de los compañeros, no solo en este sino en gran cantidad de clases pasadas del curso.

para windows este código me funcionó en el archivo pipeline

import logging
logging.basicConfig(level=logging.INFO)
import subprocess
import os
import shutil


logger = logging.getLogger(__name__)
news_sites_uids = ['eluniversal']

def main():
	try:
	    logger.info('Starting ETL process')
	    _extract()
	    _transform()
	    _load()
	    logger.info('ETL process finished')
	except FileNotFoundError as err:
		logger.warning(str(err))
	except Exception as e:
		logger.warning('Process Error')
		logger.warning(str(e))

def _extract():
	logger.info('Starting extract process')
	for news_site_uid in news_sites_uids:
		subprocess.run(['python', 'main.py', news_site_uid], cwd='./extract')
		path = '.\\extract'
		file = _search_file(path, news_site_uid)
		_move_file(path + '\\' + file, '.\\transform\\' + file)
		# subprocess.run(['find', '.', '-name', '{}*'.format(news_site_uid),
		# 				'-exec', 'mv', '{}', '../transform/{}_.csv'.format(news_site_uid),
		# 				';'], cwd='./extract')

def _transform():
	logger.info('Starting transform process')
	for news_site_uid in news_sites_uids:
		dirty_data_filename = _search_file('.\\transform', news_site_uid)
		clean_data_filename = f'clean_{dirty_data_filename}'
		subprocess.run(['python', 'main.py', dirty_data_filename], cwd='./transform')
		_remove_file('.\\transform', dirty_data_filename)
		_move_file('.\\transform\\'+ clean_data_filename, '.\\load\\' + clean_data_filename)
		# dirty_data_filename = '{}_.csv'.format(news_site_uid)
		# clean_data_filename = 'clean_{}'.format(dirty_data_filename)
		# subprocess.run(['python', 'main.py', dirty_data_filename], cwd='./transform')
		# subprocess.run(['rm', dirty_data_filename], cwd='./transform')
		# subprocess.run(['mv', clean_data_filename, '../load/{}.csv'.format(news_site_uid)],
		# 	cwd='./transform')

def _load():
	logger.info('Starting load process')
	for news_site_uid in news_sites_uids:
		clean_data_filename = _search_file('.\\load', news_site_uid)
		subprocess.run(['python', 'load_db.py', clean_data_filename], cwd='./load')
		_remove_file('.\\load', clean_data_filename)
		# clean_data_filename = '{}.csv'.format(news_site_uid)
		# subprocess.run(['python', 'main.py', clean_data_filename], cwd='./load')
		# subprocess.run(['rm', clean_data_filename], cwd='./load') 


def _remove_file(path, file):
	logger.info(f'Removing file {file}')
	os.remove(f'path\\{file}')

def _search_file(path, file_match):
	logger.info('Searching file')
	for rutas in list(os.walk(path))[0]:
		if len(rutas) > 1:
			for file in rutas:
				if file_match in file:
					return file
	return None

def _move_file(origen, destino):
	logger.info('Moving file')
	shutil.move(origen, destino)

if __name__ == '__main__':
	main()

Hay que tener en cuenta que en el curso se usan los comandos de Unix porque es lo que predomina en el mundo profesional. Así que no viene mal ir de una vez acostumbrándose a eso. Creo que es mejor buscar como hacer uso de esos comandos en Windows, que estar buscando su equivalente

Excelente curso, excelente el profesor. No en todos lados se ve la calidad de estos cursos y sobre todo la buena explicación en la diferencia de los roles.

Puedo decir que en muchas de las clases perdí la atención de lo que decía, hubo que repetir varias veces.

David, eres excelente profesor, gracias hermano!!!

Genial !

Hasta que por fin, logré implementar mi automatización, luego de la clase, un gran análisis de esto y de los aportes de todos mis compañeros. Gracias profe, y compañeros. Lo logré:

Con un .bat.

Pude guardar en mi base de datos:

Gracias a todos.

Funciono que emocion tan grande, ahora a seguir explorando y practicando que de esa forma se obtiene experiencia, muchas gracias por el curso, ahora veo un mundo distinto llenos de datos y yo con muchas ganas de minarlos como minero digital en esta nueva era digital, saludos a todos recuerden los datos esta la mina de oro si son de buena calidad se obtienen buenos diamantes. Esto lo escribi en el pasado viajeros del tiempo.

Excelente Curso! Excelente Profesor! Pero nunca pude conseguir la solucion al error “requests received response with content encoding gzip but failed to decode it” así que mi scraper no funciona 😕

import argparse
import hashlib
import logging
logging.basicConfig(level=logging.INFO)
from urllib.parse import urlparse


import pandas as pd
import nltk
from nltk.corpus import stopwords


logger = logging.getLogger(__name__)

def main(filename):
    logger.info('Starting cleaning process')

    df = _read_data(filename)
    newspaper_uid = _extract_newspaper_uid(filename)
    df = _add_newspaper_uid_column(df, newspaper_uid)
    df = _extract_host(df)
    df = _fill_missing_titles(df)
    df = _generate_uids_for_rows(df)
    df = _remove_new_lines_from_body(df)
    df = _tokenize_column(df, 'title')
    df = _tokenize_column(df, 'body')
    df = _remove_duplicate_entries(df, 'title')
    df = _drop_rows_with_missing_values(df)
    _save_data(df, filename)

    return df

def _read_data(filename):
    logger.info('Reading file {}'.format(filename))

    return pd.read_csv(filename)


def _extract_newspaper_uid(filename):
    logger.info('Extracting newspaper uid')
    newspaper_uid = filename.split('_')[0]

    logger.info('Newspaper uid detected: {}'.format(newspaper_uid))
    return newspaper_uid


def _add_newspaper_uid_column(df, newspaper_uid):
    logger.info('Filling newspaper_uid column with {}'.format(newspaper_uid))
    df['newspaper_uid'] = newspaper_uid

    return df


def _extract_host(df):
    logger.info('Extracting host from urls')
    df['host'] = df['url'].apply(lambda url: urlparse(url).netloc)

    return df


def _fill_missing_titles(df):
    logger.info('Filling missing titles')
    missing_titles_mask = df['title'].isna()
    missing_titles = (df[missing_titles_mask]['url']
                        .str.extract(r'(?P<missing_titles>[^/]+)$')
                        .applymap(lambda title: title.split('-'))
                        .applymap(lambda title_word_list: ' '.join(title_word_list))
                      )

    df.loc[missing_titles_mask, 'title'] = missing_titles.loc[:, 'missing_titles']

    return df


def _generate_uids_for_rows(df):
    logger.info('Generating uids for each row')
    uids = (df
            .apply(lambda row: hashlib.md5(bytes(row['url'].encode())), axis=1)
            .apply(lambda hash_object: hash_object.hexdigest())
            )
    df['uid'] = uids

    return df.set_index('uid')


def _remove_new_lines_from_body(df):
    logger.info('Remove new lines from body')
    stripped_body = (df
                     .apply(lambda row: row['body'], axis=1)
                     .apply(lambda body: list(body))
                     .apply(lambda letters: list(map(lambda letter: letter.replace('\n', ' '), letters)))
                     .apply(lambda letters: ''.join(letters))
                    )
    df['body'] = stripped_body

    return df

def _tokenize_column(df, column_name):
    logger.info('Calculating the number of unique tokens in {}'.format(column_name))
    stop_words = set(stopwords.words('spanish'))
    n_tokens =  (df
                 .dropna()
                 .apply(lambda row: nltk.word_tokenize(row[column_name]), axis=1)
                 .apply(lambda tokens: list(filter(lambda token: token.isalpha(), tokens)))
                 .apply(lambda tokens: list(map(lambda token: token.lower(), tokens)))
                 .apply(lambda word_list: list(filter(lambda word: word not in stop_words, word_list)))
                 .apply(lambda valid_word_list: len(valid_word_list))
            )
    df['n_tokens_' + column_name] = n_tokens

    return df


def _remove_duplicate_entries(df, column_name):
    logger.info('Removing duplicate entries')
    df.drop_duplicates(subset=[column_name], keep='first', inplace=True)

    return df


def _drop_rows_with_missing_values(df):
    logger.info('Dropping rows with missing values')
    return df.dropna()


def _save_data(df, filename):
    clean_filename = 'clean_{}'.format(filename)
    logger.info('Saving data at location: {}'.format(clean_filename))
    df.to_csv(clean_filename, encoding='utf-8-sig')


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('filename',help='The path to the dirty data', type=str)

    args = parser.parse_args()

    df = main(args.filename)
    print(df)

Comparto mi repositorio con un proyecto muy similar pero con diferentes librerias
https://github.com/thonyblaz/ETL_newspaper

Para aquellos que usen Windows 10 con Powershell para mover los archivos entre carpetas

Pienso que este curso deberia ser antes de ML, pues es la etapa inicial y de ahi seguir todo el proceso con un mismo proyecto.

Muy bueno el resultado del curso.

  1. Extraer
  2. Transformar
  3. Insertar

A mi me gustó el curso, es verdad que es nivel avanzado. No soy usuario experto pero llegué aquí siguiendo la ruta de “Escuela de Data Science” y pude comprender la mayoría de temas vistos.
El proyecto práctico me pareció muy bueno, hicimos todo el proceso ETL.
Eso no lo enseñan en la universidad, por experiencia propia tomé un curso de ETL en otro lado, pero no escribimos ni una sola linea de código y todo fue contenido teorico. Al menos en Platzi uno si tiene la oportunidad de estar manos a la obra, escribiendo, buscando informacion, solucionando errores.
Gracias por el curso!!

Excelente!

Mis felicitaciones al profesor. Excelente curso.

En mi punto de vista, si se trabaja con una mayor cantidad de periodicos o fuentes, el hecho de escribir en disco la información y leerla nuevamente, hará que el programa se vuelva lento. Alguna recomendacón?

Este curso no dejo de sorprenderme en ningun momento, voy a intentar hacer mis propios webscraper y empezar a minar informacion. Genial el curso, genial la ejecucion y el profesor, muy buen comunicador. Aqui se ve la calidad de los cursos de platzi

Genial. En mi trabajo hago estas automatizaciones sobre la plataforma de Cloudera creando diferentes acciones en serie o paralelo (seria el equivalente a correr un script). No había pensando como hacerlo en mi maquina local y es grandioso ahora saberlo. Ahora el reto es hacer una aplicaciones como esta para que corra en la nube.

Saludos… Gran tema… un poco acelerado.,… pero nos queda practicar y practicar… gracias a los compañeros por los aportes y ayudas en las dudas y en compartir soluciones a codigo actualizado… gracias

El curso me parece muy bueno, el profesor es muy claro (aunque debi repasar varias veces algunos conceptos ). Recomendable.

Es cierto que usuarios de windows deben adaptar los comandos a su sistema operativo.-

Muy chevere el curso y su contenido
un poco tedioso para algunos que no sean ing de software, sistemas o datos
para los que no, nos toca aprender mucho sobre los lenguajes de programacion

el web scrapper con la automatización me quedo espectacular. Gracias profe

excelente curso, aprendi mucho

Hola compañeros, excelente curso!!, ahora estoy tratando de convertir el pipeline.py a pypeline.exe, para poder ejecutarlo en una tarea programada de windows, pero he tenido algunos problemas para realizarlo con Pyinstaller, traté tambien con Py2exe pero al parecer esta descontinuada esa libreria y no sirve para Python 3.*, si alguien que pueda contribuir con la conversión de este proyecto a .exe, se lo agradecería, yo seguiré intentando, si lo logro, lo compartiré. Sldos.

muy interesante!

ETL Completo. Gracias David

Excelente clase!

Muchas gracias! Pipeline funcionando, ahora a con este proyecto y unas modificaciones, se puede sacar todo tipo de información de la web y estructurarla para una BD, de verdad excelente curso!

Este curso está increíble. Es genial todo lo que se puede lograr con estos programas que hemos ido construyendo, puede ser algo complejo de entender, pero es una gran introducción. No puedo esperar a tomar los demás cursos de Pandas y WebScraping que tiene Platzi para mejorar las habilidades vistas aquí. 💪🤓🐍

Muy buen curso.

Me encantó el curso, queda muchísimo por aprender, pero lo aprendido acá ha sido incríble.

Comandos de la línea de comandos powershell en Windows:

Ejemplo Mover un archivo:

        subprocess.run(['powershell', 'Get-ChildItem', '-Path', '.', '-Recurse', '-Filter', f'{news_site_uid}*',
                        r'|', 'Move-Item', '-Destination', f'../transform/'],
                       cwd='./extract')

Ejemplo Borrar archivo:

        subprocess.run(['powershell', 'Remove-Item', dirty_data_filename],
                       cwd='./transform')

Es un curso bueno, bastante denso y requiere bastante destreza en python.
Este ultimo capitulo consolida los anteriores, pero creo se debió dar una mejor introducción para llegar a este árbol de programas y automatización-

Muy buen curso, la verdad aprendi muchismas cosas de este universo de los datos, empezare con la escuela de data science desde cero y afianzare mis bases. Muchas gracias David.

Muchas gracias david por enseñar un poco del mundo de las datos. vamos por mas

Para los novatos como yo en programación este es un buen curso para entender el poder que hay detrás de la programación y con ello motivar a aprender mucho más.

Me enrrede un poco al final porque no cai en cueta que el el main.py que el profe habia cargado en la carpeta transform era el archivo: newspaper_receipe.py

Muy buen curso. Para los que estamos iniciando Python nos cuesta pero lo importante es ir avanzando. Sé muchas cosas que antes no tenía ni idea y motivado a seguir aprendiendo

muchachos buenas noches, espero se encuentren bien, les aconsejo utilizar funciones para mover, remover y buscar en vez de los comandos directos de subprocess, ya que estos dependen del sistema operaivo que uses.

fue acelerado el curso esta muy enfocado a windows queda completamente por fuera

En mi caso solo tuve el siguiente error:

Que lo solucione cambiando en el main.py de load el ‘uid’ por ‘uids’:

Luego me funciono perfecto 😃

Tengo este error. Estoy corriendo Ubuntu WSL en Windows

jme@JMe6Z2:/mnt/c/Users/JMe6Z2/Desktop/PL/Scraping/final_project/extract$ python main.py elpais
/mnt/c/Users/JMe6Z2/Desktop/PL/Scraping/final_project/extract/common.py:11: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
  __config = yaml.load(f)
INFO:root:Beginning scraper for https://elpais.com
Traceback (most recent call last):
  File "main.py", line 89, in <module>
    _news_scraper(args.news_site)
  File "main.py", line 24, in _news_scraper
    homepage = news.HomePage(news_site_uid, host)
  File "/mnt/c/Users/JMe6Z2/Desktop/PL/Scraping/final_project/extract/news_page_objects.py", line 30, in __init__
    super().__init__(news_site_uid, url)
TypeError: super() takes at least 1 argument (0 given)```

Gracias

Bueno se logro con inconvenientes que nunca faltan, en mi caso tuve problemas con el archivo newspaper_receipe.py , el encarfado de la limpieza del dataframe. puntualmente en la parte de la lectura del archivo generado despues del proceso de obtencion de de las URL, en la parte del extract. resulta que no me estaba leyendo el .CSV por que venia en codificacion UTF-8. la solucion fue usar el atributo encoding quedaria de la siguiente manera:

return pd.read_csv(filename, encoding = “ISO-8859-1”)

trate con return pd.read_csv(filename,encoding = “utf-8” ) pero no me funciono.

El siguiente era el error:
![](

A mi me gusto el curso no es algo básico y cumple con las expectativas!

para mover archivos desde consola usando la subprocess en windows hice esta prueba y me funcionó.

import subprocess

site = 'eluniversal'
subprocess.run(["MOVE", "extract\{}*.csv".format(site), "transform\{}_.csv".format(site)], shell=True)