Construyendo un Web Scraper con Python en 30 minutos

Blog

Construyendo un Web Scraper con Python en 30 minutos

Mis habilidades en Python son básicas, así que si estás aquí sin muchas habilidades en codificación, espero que esta guía te ayude a adquirir más conocimientos y comprensión.



El proyecto perfecto para principiantes

Para obtener datos para proyectos de ML, IA o ciencia de datos, a menudo dependerá de bases de datos, API o conjuntos de datos CSV listos para usar. Pero, ¿qué pasa si no puede encontrar un conjunto de datos que desee utilizar y analizar? Ahí es donde entra en juego un raspador web.






Trabajar en proyectos es fundamental para consolidar los conocimientos adquiridos. Cuando comencé este proyecto, estaba un poco abrumado porque realmente no sabía nada.



Seguir con él, encontrar respuestas a mis preguntas en Stack Overflow y muchas pruebas y errores me ayudaron a comprender realmente cómo funciona la programación: cómo funcionan las páginas web, cómo usar bucles y cómo crear funciones y mantener los datos limpios. Hace que la construcción de un raspador web sea el proyecto perfecto para principiantes para cualquiera que se esté iniciando en Python.



Que cubriremos

Esta guía lo guiará a través de la comprensión de las páginas web HTML, la creación de un raspador web con Python y la creación de un DataFrame con pandas. Cubrirá la calidad de los datos, la limpieza de datos y la conversión de tipos de datos, completamente paso a paso y con instrucciones, código y explicaciones sobre cómo funciona cada pieza. ¡Espero que codifiques y disfrutes!






Descargo de responsabilidad

Los sitios web pueden restringir o prohibir la extracción de datos de su sitio web. Los usuarios pueden estar sujetos a ramificaciones legales dependiendo de dónde y cómo intente recopilar información. Los sitios web suelen describir esto en sus términos de uso y en su robots.txt archivo encontrado en su sitio, que generalmente se parece a esto: [www.example.com/robots.txt](http://www.[site].com/robots.txt.). Así que raspe responsablemente y respete el robots.txt.

¿Qué es Web Scraping?

Raspado web Consiste en recopilar datos disponibles en sitios web. Esto se puede hacer manualmente por un humano o usando un bot.

A Bot es un programa creado por usted que le ayuda a extraer los datos que necesita mucho más rápido que la mano y los ojos de un ser humano.

¿Qué vamos a raspar?

Es esencial identificar el objetivo de su raspado desde el principio. No queremos extraer ningún dato que en realidad no necesitemos.

Para este proyecto, extraeremos datos de las 1,000 películas principales de IMDb, específicamente las 50 películas principales de esta página. Aquí está la información que recopilaremos de cada lista de películas:

  • El título
  • El año en que fue lanzado
  • Cuanto dura la pelicula
  • Calificación de IMDb de la película
  • El Metascore de la película
  • ¿Cuántos votos obtuvo la película?
  • Las ganancias brutas de la película en EE. UU.

¿Cómo funcionan los Web Scrapers?

Los web scrapers recopilan datos del sitio web de la misma manera que lo haría un humano: van a una página web del sitio web, obtienen los datos relevantes y pasan a la siguiente página web, solo que mucho más rápido.

Cada sitio web tiene una estructura diferente. Estas son algunas cosas importantes en las que pensar al crear un raspador web:

  • ¿Cuál es la estructura de la página web que contiene los datos que busca?
  • ¿Cómo llegamos a esas páginas web?
  • ¿Necesitará recopilar más datos de la página siguiente?

La URL

Para empezar, veamos la URL de la página que queremos raspar.

Notamos algunas cosas sobre la URL:

  • ? actúa como un separador: indica el final de la ruta del recurso URL y el inicio de los parámetros
  • groups=top_1000 especifica de qué se tratará la página
  • &ref_adv_prv nos lleva a la página anterior o siguiente. La referencia es la página en la que estamos actualmente. adv_nxt y adv_prv hay dos valores posibles, traducidos a avanzar a la página siguiente y avanzar a la página anterior.

Cuando navega hacia adelante y hacia atrás por las páginas, notará que solo cambian los parámetros. Tenga en cuenta esta estructura, ya que es útil saberlo mientras construimos el raspador.

El HTML

HTML significa Lenguaje de marcado de hipertexto, y la mayoría de las páginas web se escriben con él. Esencialmente, HTML es cómo dos computadoras se comunican entre sí a través de Internet, y los sitios web están qué ellos dicen.

Cuando accede a una URL, su computadora envía una solicitud al servidor que aloja el sitio. Se puede ejecutar cualquier tecnología en ese servidor (JavaScript, Ruby, Java, etc.) para procesar su solicitud. Finalmente, el servidor devuelve una respuesta a su navegador; a menudo, esa respuesta será en forma de una página HTML para que la muestre su navegador.

HTML describe la estructura de una página web de forma semántica y originalmente incluía señales para la apariencia del documento.

Inspeccionar HTML

Los usuarios de Chrome, Firefox y Safari pueden examinar la estructura HTML de cualquier página haciendo clic con el botón derecho del mouse y presionando la opción Inspeccionar.

Este es el título de la imagen

Aparecerá un menú en la parte inferior o en el lado derecho de su página con una lista larga de todas las etiquetas HTML que contienen la información que se muestra en la ventana de su navegador. Si estás en Safari (foto de arriba), querrás presionar el botón a la izquierda de la barra de búsqueda, que parece un objetivo. Si está en Chrome o Firefox, hay un pequeño cuadro con un ícono de flecha en la parte superior izquierda que usará para inspeccionar.

Una vez que haga clic, si mueve el cursor sobre cualquier elemento de la página, notará que se resaltará junto con las etiquetas HTML en el menú con el que están asociados, como se ve arriba.

Saber cómo leer la estructura básica de la página HTML de una página es importante para que podamos recurrir a Python para que nos ayude a extraer el HTML de la página.

Instrumentos

Las herramientas que vamos a utilizar son:

  • Responder (opcional) es un entorno de programación informática interactivo y sencillo que se utiliza a través de su navegador web. Recomiendo usar esto solo para propósitos de código si aún no tiene un IDE. Si usa Repl, asegúrese de estar usando el entorno Python.
  • Peticiones nos permitirá enviar solicitudes HTTP para obtener archivos HTML
  • Hermosa Sopa nos ayudará a analizar los archivos HTML
  • pandas nos ayudará a reunir los datos en un DataFrame para limpiarlo y analizarlo
  • NumPy agregará soporte para funciones matemáticas y herramientas para trabajar con matrices

Ahora, codifiquemos

Puede seguir a continuación dentro de su entorno Repl o IDE, o puede ir directamente a el código completo aquí . ¡Divertirse!

Importar herramientas

Primero, importaremos las herramientas que necesitaremos para que podamos usarlas para ayudarnos a construir el raspador y obtener los datos que necesitamos.

|_+_|

Películas en inglés

Es muy probable que cuando ejecutemos nuestro código para extraer algunas de estas películas, obtengamos los nombres de las películas traducidos al idioma principal del país en el que se originó.

Utilice este código para asegurarse de que obtengamos títulos traducidos al inglés de todas las películas que extraemos:

validación de formulario js vainilla
|_+_|

Solicitar contenido de la URL

Obtenga el contenido de la página que estamos viendo solicitando la URL:

|_+_|

Desglose de las solicitudes de URL:

  • import requests from requests import get from bs4 import BeautifulSoup import pandas as pd import numpy as np es la variable que creamos y asignamos la URL a
  • headers = {'Accept-Language': 'en-US, en;q=0.5'} es la variable que creamos para almacenar nuestro url = 'https://www.imdb.com/search/title/?groups=top_1000&ref_=adv_prv' results = requests.get(url, headers=headers) acción
  • url es el método que usamos para capturar el contenido de la URL. El results parte le dice a nuestro raspador que nos traiga inglés, basado en nuestra línea de código anterior.

Usando BeautifulSoup

Haga que el contenido que tomamos sea fácil de leer usando request.get:

|_+_|

Rompiendo BeautifulSoup Down:

  • requests.get(url, headers=headers) es la variable que creamos para asignar el método headers to, que especifica un formato de resultados deseado utilizando el analizador HTML; esto permite que Python lea los componentes de la página en lugar de tratarla como una cadena larga
  • BeautifulSoup imprimirá lo que hemos tomado en un formato de árbol más estructurado, lo que facilitará su lectura.

Los resultados de la impresión se verán más ordenados, así:

|_+_|

Rotura |_+_| abajo:

Prepárate para extraer cada artículo

Este es el título de la imagen

¡Nos están perdiendo los ingresos brutos! Si miras la segunda película, la han incluido allí.

Este es el título de la imagen

Algo a tener en cuenta siempre al crear un raspador web es la idea de que no toda la información que busca estará disponible para que la recopile.

En estos casos, debemos asegurarnos de que nuestro raspador web no deje de funcionar o se rompa cuando llegue a los datos faltantes y construyamos en torno a la idea de que simplemente no sabemos si eso sucederá o no.

Entrar en cada lister-item div

Cuando tomamos cada uno de los elementos que necesitamos en un solo mode-advanced lister-item mode-advanced contenedor, necesitamos que el raspador pase al siguiente div lister-item mode-advanced contenedor y coge esos elementos de la película también. Y luego debe pasar a la siguiente y así sucesivamente, 50 veces para cada página. Para que esto se ejecute, tendremos que envolver nuestro raspador en un bucle for.

|_+_|

Rompiendo el |_+_| círculo:

  • Un bucle lister-item mode-advanced se utiliza para iterar sobre una secuencia. Nuestra secuencia es cada contenedor movie_div = soup.find_all('div', class_='lister-item mode-advanced') div que almacenamos en **find_all**
  • movie_div es el nombre de la variable que ingresa cada div. Puede nombrar esto como quiera (lister-item mode-advanced, find_all(), div, class), y no cambiará la función del bucle.

Se puede leer así:

|_+_|

Extrae el título de la película.

Comenzando con el nombre de la película, busquemos su línea HTML correspondiente usando inspeccionar y haciendo clic en el título.

Este es el título de la imagen

Vemos que el nombre está contenido dentro de una etiqueta de anclaje, lister-item mode-advanced. El lister-item mode-advanced etiqueta. Este `` es el tercero de los lister-item mode-advanced s anidados en el contenedor de la primera película.

|_+_|

Desglosando títulos:

  • div es la variable que usaremos para almacenar los datos del título que encontremos
  • lister-item mode-advanced es lo que se usa en nuestro bucle for; se usa para iterar cada vez
  • div y #initiate the for loop #this tells your scraper to iterate through #every div container we stored in move_div for container in movie_div: es notación de atributo y le dice al raspador que acceda a cada una de esas etiquetas
  • **for** le dice al raspador que tome el texto anidado en la etiqueta ``
  • for le dice al raspador que tome lo que encontramos y almacenamos en lister-item mode-advanced y agregarlo a nuestra lista vacía llamada movie_div, que creamos al principio

Extraer año de lanzamiento

Busquemos el año de la película y su línea HTML correspondiente usando inspeccionar y haciendo clic en el año.

Este es el título de la imagen

Vemos que estos datos se almacenan dentro de container etiqueta que contiene el título de la película. La notación de puntos, que usamos para encontrar los datos del título (div), funcionó porque era la primera x La etiqueta que queremos es la segunda etiqueta, tenemos que usar un método diferente.

En cambio, podemos decirle a nuestro raspador que busque por la marca distintiva del segundo ''. Usaremos el loop método , que es similar a banana excepto que solo devuelve la primera coincidencia.

|_+_|

Desglosando años:

  • cheese es la variable que usaremos para almacenar los datos del año que encontremos
  • for in : OR in our case... for each lister-item mode-advanced div container: scrape these elements es lo que usamos en nuestro . This tag is nested within a header tag, bucle: se usa para iterar cada vez
  • tag is nested within a es la notación de atributo, que le dice al raspador que acceda a esa etiqueta
  • div es un método que usaremos para acceder a esta `` etiqueta
  • name = container.h3.a.text titles.append(name) es la etiqueta distintiva que queremos
  • name le dice al raspador que tome lo que encontramos y almacenamos en container y agregarlo a nuestra lista vacía llamada .h3 (que creamos al principio)

Extraer la duración de la película

Busque la duración de la película y su línea HTML correspondiente utilizando inspeccionar y haciendo clic en el total de minutos.

Este es el título de la imagen

Los datos que necesitamos se pueden encontrar en una etiqueta con una clase de .a. Como hicimos con el año, podemos hacer algo similar:

|_+_|

Rompiendo el tiempo:

  • .text es la variable que usaremos para almacenar los datos de tiempo que encontremos
  • titles.append(name) es lo que usamos en nuestro name bucle: se usa para iterar cada vez
  • titles es un método que usaremos para acceder a esta `` etiqueta
  • tag below the es la etiqueta distintiva que queremos
  • .h3.a dice que si hay datos allí, consígalos, pero si faltan datos, coloque un guión allí
  • tag after the `h3` tag. Since the le dice al raspador que tome ese texto en la etiqueta ``
  • find() le dice al raspador que tome lo que encontramos y almacenamos en find_all() y agregarlo a nuestra lista vacía llamada year = container.h3.find('span', class_='lister-item-year').text years.append(year) (que creamos al principio)

Extraer calificaciones de IMDb

Busque la calificación de IMDb de la película y su línea HTML correspondiente utilizando inspeccionar y haciendo clic en la calificación de IMDb.

Este es el título de la imagen

Ahora, nos centraremos en extraer la calificación de IMDb. Los datos que necesitamos se pueden encontrar en un year etiqueta. Como no veo ningún otro container etiquetas, podemos usar la notación de atributos (notación de puntos) para capturar estos datos.

|_+_|

Desglosando las calificaciones de IMDb:

  • for es la variable que usaremos para almacenar los datos de calificaciones de IMDB que encuentre
  • .h3 es lo que usamos en nuestro .find() bucle: se usa para iterar cada vez
  • (‘span’, class_ = ‘lister-item-year’) es una notación de atributo que le dice al raspador que acceda a esa etiqueta
  • years.append(year) le dice al raspador que tome ese texto
  • El year El método convierte el texto que encontramos en un flotante, que es un decimal
  • years le dice al raspador que tome lo que encontramos y almacenamos en runtime y agregarlo a nuestra lista vacía llamada runtime = container.find('span', class_='runtime').text if container.p.find('span', class_='runtime') else '' time.append(runtime) (que creamos al principio)

Extraer Metascore

Busque la calificación de Metascore de la película y su línea HTML correspondiente utilizando inspeccionar y haciendo clic en el número de Metascore.

Este es el título de la imagen

Los datos que necesitamos se pueden encontrar en una etiqueta `` que tiene una clase que dice runtime.

Antes de decidirnos por eso, debe notar que, por supuesto, un 96 para Parasite muestra una calificación favorable, pero ¿son favorables los demás? Si resaltas el Metascore de la siguiente película, verás que JoJo Rabbit tiene una clase que dice container. Dado que estas etiquetas son diferentes, sería seguro decirle al raspador que use solo la clase for al raspar:

|_+_|

Desglosando Metascores:

  • .find() es la variable que usaremos para almacenar los datos de calificación de Metascore que encuentre
  • (‘span’, class_ = ‘runtime’) es lo que usamos en nuestro if container.p.find(‘span’, class_=’runtime’) else ‘-’ bucle: se usa para iterar cada vez
  • .text es un método que usaremos para acceder a esta `` etiqueta
  • time.append(runtime) es la etiqueta distintiva que queremos
  • runtime le dice al raspador que tome ese texto
  • time dice que si hay datos allí, consígalos, pero si faltan datos, coloque un guión allí
  • El ** El método convierte el texto que encontramos en un número entero.
  • ** le dice al raspador que tome lo que encontramos y almacenamos en imdb = float(container.strong.text) imdb_ratings.append(imdb) y agregarlo a nuestra lista vacía llamada imdb (que creamos al principio)

Extraer votos e ingresos brutos

Finalmente llegamos a los dos últimos elementos que necesitamos extraer, pero dejamos los más difíciles para el final.

Aquí es donde las cosas se ponen un poco complicadas. Como se mencionó anteriormente, debería haber notado que cuando miramos la primera película de esta lista, no vemos un número de ingresos brutos. Cuando miramos la segunda película de la lista, podemos ver ambas.

Echemos un vistazo al código HTML de la segunda película y partamos de ahí.

Este es el título de la imagen

Tanto los votos como los brutos están resaltados a la derecha. Después de mirar los votos y los contenedores brutos para la película # 2, ¿qué notas?

Android: barra de calificación

Como puede ver, ambos están en una etiqueta `` que tiene un container atributo que es igual a for y un .strong atributo que contiene los valores del número distintivo que necesitamos para cada uno.

¿Cómo podemos obtener los datos del segundo si los parámetros de búsqueda del primero son los mismos? ¿Cómo le decimos a nuestro raspador que se salte el primero y raspe el segundo?

Este requirió mucho esfuerzo mental, toneladas de café y un par de noches para descubrirlo. Así es como lo hice:

|_+_|

Rompiendo votos y brutos abajo:

  • .text es una variable completamente nueva que usaremos para almacenar tanto los votos como las etiquetas `` brutas ''
  • float() es lo que usamos en nuestro imdb_ratings.append(imdb) bucle para iterar cada vez
  • imdb es el método que usaremos para obtener las dos `` etiquetas
  • imdb_ratings es cómo podemos tomar los atributos de esa etiqueta específica.
  • metascore favorable es la variable que usaremos para almacenar los votos que encontremos en el metascore mixed etiqueta
  • metascore le dice al raspador que entre en m_score = container.find('span', class_='metascore').text if container.find('span', class_='metascore') else '-' metascores.append(m_score) etiqueta y toma los primeros datos de la lista, que son los votos porque m_score viene primero en nuestro código HTML (las computadoras cuentan en binario; comienzan a contar en 0, no en 1)
  • container le dice al raspador que tome ese texto
  • for le dice al raspador que tome lo que encontramos y almacenamos en .find() y agregarlo a nuestra lista vacía llamada (‘span’, class_ = ‘metascore’) (que creamos al principio)
  • .text es la variable que usaremos para almacenar el bruto que encontremos en if container.find(‘span’, class_=’metascore’) else ‘-’ etiqueta
  • int() le dice al raspador que entre en metascores.append(m_score) etiqueta y tome el segundo dato de la lista, que es m_score porque metascores ocupa el segundo lugar en nuestro código HTML
  • name dice si la longitud de nv es mayor que uno, luego busque el segundo dato almacenado. Pero si los datos almacenados en data-value no es mayor que uno, es decir, si falta el valor bruto, coloque un guión allí
  • nv = container.find_all('span', attrs={'name': 'nv'}) vote = nv[0].text votes.append(vote) grosses = nv[1].text if len(nv) > 1 else '-' us_gross.append(grosses) le dice al raspador que tome lo que encontramos y almacenamos en nv y agregarlo a nuestra lista vacía llamada container (que creamos al principio)

Su código ahora debería verse así:

|_+_|

Veamos lo que tenemos hasta ahora

Ahora que le hemos dicho a nuestro raspador qué elementos raspar, usemos el for función para imprimir cada lista a la que hemos enviado nuestros datos extraídos:

|_+_|

Nuestras listas se ven así

|_+_|

Hasta ahora todo va bien, pero todavía no hemos llegado a ese punto. Necesitamos limpiar un poco nuestros datos. Parece que tenemos algunos elementos no deseados en nuestros datos: signos de dólar, find_all() s, (‘span’, attrs = ‘name’ : ’nv’) s, comas, paréntesis y espacio en blanco adicional en los Metascores.

Construyendo un DataFrame con pandas

El siguiente orden del día es construir un vote con pandas para almacenar los datos que tenemos muy bien en una tabla para comprender realmente lo que está sucediendo.

Así es como lo hacemos:

|_+_|

Desglosando nuestro marco de datos:

  • nv es lo que llamaremos nuestro nv[0]
  • nv así es como inicializamos la creación de un votes con pandas
  • Las claves de la izquierda son los nombres de las columnas.
  • Los valores de la derecha son nuestras listas de datos que hemos extraído

Ver nuestro DataFrame

Podemos ver cómo se ve todo simplemente usando el .text función en nuestro votes.append(vote) —Que llamamos vote —Al final de nuestro programa:

|_+_|

Nuestro DataFrame de pandas se ve así

Este es el título de la imagen

Calidad de los datos

Antes de embarcarse en proyectos como este, debe saber cuáles son sus criterios de calidad de datos, es decir, qué reglas o restricciones deben seguir sus datos. Aquí hay unos ejemplos:

  • Restricciones de tipo de datos: Los valores en sus columnas deben ser de un tipo de datos particular: numérico, booleano, fecha, etc.
  • Restricciones obligatorias : Algunas columnas no pueden estar vacías
  • Patrones de expresión regular: T campos ext que tienen que estar en un patrón determinado, como números de teléfono

¿Qué es la limpieza de datos?

Limpieza de datos es el proceso de detección y corrección o eliminación de registros corruptos o inexactos de su conjunto de datos.

Al realizar un análisis de datos, también es importante asegurarse de que estamos usando los tipos de datos correctos.

Comprobación de tipos de datos

Podemos comprobar cómo se ven nuestros tipos de datos ejecutando esto votes función en la parte inferior de nuestro programa:

|_+_|

Resultados de nuestro tipo de datos

Este es el título de la imagen

Analicemos esto: nuestro tipo de datos de películas es un objeto, que es lo mismo que una cadena, lo cual sería correcto considerando que son títulos de películas. Nuestra puntuación de IMDb también es correcta porque tenemos números de punto flotante en esta columna (números decimales).

Pero nuestros grosses, nv, nv[1] y nv muestran que son objetos cuando deberían ser tipos de datos enteros, y nuestro gross es un objeto en lugar de un gross tipo de datos. ¿Cómo pasó esto?

Inicialmente, cuando le decíamos a nuestro raspador que tomara estos valores de cada contenedor HTML, le decíamos que tomara valores específicos de una cadena. Una cadena representa texto en lugar de números; se compone de un conjunto de caracteres que pueden además contienen números.

Por ejemplo, la palabra nv[1].text if len(nv) > 1 else ‘-’ y la frase nv son ambas cadenas. Si tuviéramos que deshacernos de todo excepto de nv de us_gross.append(grosses), sigue siendo una cadena, pero ahora es una que solo dice grosses.

Limpieza de datos con pandas

Ahora que tenemos una idea clara de cómo se ven nuestros datos en este momento, es hora de comenzar a limpiarlos.

Esta puede ser una tarea tediosa, pero es muy importante.

Datos del año de limpieza

Para eliminar los paréntesis de nuestros datos anuales y convertir el objeto en un tipo de datos enteros, haremos lo siguiente:

|_+_|

Desglose de los datos del año de limpieza:

  • us_grosses le dice a los pandas que vayan a la columna import requests from requests import get from bs4 import BeautifulSoup import pandas as pd import numpy as np url = 'https://www.imdb.com/search/title/?groups=top_1000&ref_=adv_prv' headers = {'Accept-Language': 'en-US, en;q=0.5'} results = requests.get(url, headers=headers) soup = BeautifulSoup(results.text, 'html.parser') titles = [] years = [] time = [] imdb_ratings = [] metascores = [] votes = [] us_gross = [] movie_div = soup.find_all('div', class_='lister-item mode-advanced') for container in movie_div: #Name name = container.h3.a.text titles.append(name) #year year = container.h3.find('span', class_='lister-item-year').text years.append(year) #time runtime = container.p.find('span', class_='runtime').text if container.p.find('span', class_='runtime').text else '-' time.append(runtime) #IMDb rating imdb = float(container.strong.text) imdb_ratings.append(imdb) #metascore m_score = container.find('span', class_='metascore').text if container.find('span', class_='metascore') else '-' metascores.append(m_score) #here are two NV containers, grab both of them as they hold both the votes and the grosses nv = container.find_all('span', attrs={'name': 'nv'}) #filter nv for votes vote = nv[0].text votes.append(vote) #filter nv for gross grosses = nv[1].text if len(nv) > 1 else '-' us_gross.append(grosses) en nuestro print
  • print(titles) print(years) print(time) print(imdb_ratings) print(metascores) print(votes) print(us_gross) este método: ['Parasite', 'Jojo Rabbit', '1917', 'Knives Out', 'Uncut Gems', 'Once Upon a Time... in Hollywood', 'Joker', 'The Gentlemen', 'Ford v Ferrari', 'Little Women', 'The Irishman', 'The Lighthouse', 'Toy Story 4', 'Marriage Story', 'Avengers: Endgame', 'The Godfather', 'Blade Runner 2049', 'The Shawshank Redemption', 'The Dark Knight', 'Inglourious Basterds', 'Call Me by Your Name', 'The Two Popes', 'Pulp Fiction', 'Inception', 'Interstellar', 'Green Book', 'Blade Runner', 'The Wolf of Wall Street', 'Gone Girl', 'The Shining', 'The Matrix', 'Titanic', 'The Silence of the Lambs', 'Three Billboards Outside Ebbing, Missouri', 'Harry Potter and the Sorcerer's Stone', 'The Peanut Butter Falcon', 'The Handmaiden', 'Memories of Murder', 'The Lord of the Rings: The Fellowship of the Ring', 'Gladiator', 'The Martian', 'Bohemian Rhapsody', 'Watchmen', 'Forrest Gump', 'Thor: Ragnarok', 'Casino Royale', 'The Breakfast Club', 'The Godfather: Part II', 'Django Unchained', 'Baby Driver'] ['(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(I) (2019)', '(2019)', '(2019)', '(2019)', '(1972)', '(2017)', '(1994)', '(2008)', '(2009)', '(2017)', '(2019)', '(1994)', '(2010)', '(2014)', '(2018)', '(1982)', '(2013)', '(2014)', '(1980)', '(1999)', '(1997)', '(1991)', '(2017)', '(2001)', '(2019)', '(2016)', '(2003)', '(2001)', '(2000)', '(2015)', '(2018)', '(2009)', '(1994)', '(2017)', '(2006)', '(1985)', '(1974)', '(2012)', '(2017)'] ['132 min', '108 min', '119 min', '131 min', '135 min', '161 min', '122 min', '113 min', '152 min', '135 min', '209 min', '109 min', '100 min', '137 min', '181 min', '175 min', '164 min', '142 min', '152 min', '153 min', '132 min', '125 min', '154 min', '148 min', '169 min', '130 min', '117min', '180 min', '149 min', '146 min', '136 min', '194 min', '118 min', '115 min', '152 min', '97 min', '145 min', '132 min', '178 min', '155 min', '144 min', '134 min', '162 min', '142 min', '130 min', '144 min', '97 min', '202 min', '165 min', '113 min'] [8.6, 8.0, 8.5, 8.0, 7.6, 7.7, 8.6, 8.1, 8.2, 8.0, 8.0, 7.7, 7.8, 8.0, 8.5, 9.2, 8.0, 9.3, 9.0, 8.3, 7.9, 7.6, 8.9, 8.8, 8.6, 8.2, 8.1, 8.2, 8.1,8.4, 8.7, 7.8, 8.6, 8.2, 7.6, 7.7, 8.1, 8.1, 8.8, 8.5, 8.0, 8.0, 7.6, 8.8, 7.9, 8.0, 7.9, 9.0, 8.4, 7.6] ['96 ', '58 ', '78 ', '82 ', '90 ', '83 ', '59 ', '51 ', '81 ', '91 ', '94 ', '83 ', '84 ', '93 ', '78 ', '100 ', '81 ', '80 ', '84 ', '69 ', '93 ', '75 ', '94 ', '74 ', '74 ', '69 ', '84 ', '75 ', '79 ', '66 ', '73 ', '75 ', '85 ', '88 ', '64 ', '70 ', '84 ', '82 ', '92 ', '67 ', '80 ', '49 ', '56 ', '82 ', '74 ', '80 ', '62 ', '90 ', '81 ', '86 '] ['282,699', '142,517', '199,638', '195,728', '108,330', '396,071', '695,224', '42,015', '152,661', '65,234', '249,950', '77,453', '160,180', '179,887', '673,115', '1,511,929', '414,992', '2,194,397', '2,176,865', '1,184,882', '178,688', '76,291', '1,724,518', '1,925,684', '1,378,968', '293,695', '656,442', '1,092,063', '799,696', '835,496', '1,580,250', '994,453', '1,191,182', '383,958', '595,613', '34,091', '92,492', '115,125', '1,572,354', '1,267,310', '715,623', '410,199', '479,811', '1,693,344', '535,065', '555,756', '330,308', '1,059,089', '1,271,569', '398,553'] ['-', '

    Construyendo un Web Scraper con Python en 30 minutos

    Mis habilidades en Python son básicas, así que si estás aquí sin muchas habilidades en codificación, espero que esta guía te ayude a adquirir más conocimientos y comprensión.

    El proyecto perfecto para principiantes

    Para obtener datos para proyectos de ML, IA o ciencia de datos, a menudo dependerá de bases de datos, API o conjuntos de datos CSV listos para usar. Pero, ¿qué pasa si no puede encontrar un conjunto de datos que desee utilizar y analizar? Ahí es donde entra en juego un raspador web.

    Trabajar en proyectos es fundamental para consolidar los conocimientos adquiridos. Cuando comencé este proyecto, estaba un poco abrumado porque realmente no sabía nada.

    Seguir con él, encontrar respuestas a mis preguntas en Stack Overflow y muchas pruebas y errores me ayudaron a comprender realmente cómo funciona la programación: cómo funcionan las páginas web, cómo usar bucles y cómo crear funciones y mantener los datos limpios. Hace que la construcción de un raspador web sea el proyecto perfecto para principiantes para cualquiera que se esté iniciando en Python.

    Que cubriremos

    Esta guía lo guiará a través de la comprensión de las páginas web HTML, la creación de un raspador web con Python y la creación de un DataFrame con pandas. Cubrirá la calidad de los datos, la limpieza de datos y la conversión de tipos de datos, completamente paso a paso y con instrucciones, código y explicaciones sobre cómo funciona cada pieza. ¡Espero que codifiques y disfrutes!

    Descargo de responsabilidad

    Los sitios web pueden restringir o prohibir la extracción de datos de su sitio web. Los usuarios pueden estar sujetos a ramificaciones legales dependiendo de dónde y cómo intente recopilar información. Los sitios web suelen describir esto en sus términos de uso y en su robots.txt archivo encontrado en su sitio, que generalmente se parece a esto: [www.example.com/robots.txt](http://www.[site].com/robots.txt.). Así que raspe responsablemente y respete el robots.txt.

    ¿Qué es Web Scraping?

    Raspado web Consiste en recopilar datos disponibles en sitios web. Esto se puede hacer manualmente por un humano o usando un bot.

    A Bot es un programa creado por usted que le ayuda a extraer los datos que necesita mucho más rápido que la mano y los ojos de un ser humano.

    ¿Qué vamos a raspar?

    Es esencial identificar el objetivo de su raspado desde el principio. No queremos extraer ningún dato que en realidad no necesitemos.

    Para este proyecto, extraeremos datos de las 1,000 películas principales de IMDb, específicamente las 50 películas principales de esta página. Aquí está la información que recopilaremos de cada lista de películas:

    • El título
    • El año en que fue lanzado
    • Cuanto dura la pelicula
    • Calificación de IMDb de la película
    • El Metascore de la película
    • ¿Cuántos votos obtuvo la película?
    • Las ganancias brutas de la película en EE. UU.

    ¿Cómo funcionan los Web Scrapers?

    Los web scrapers recopilan datos del sitio web de la misma manera que lo haría un humano: van a una página web del sitio web, obtienen los datos relevantes y pasan a la siguiente página web, solo que mucho más rápido.

    Cada sitio web tiene una estructura diferente. Estas son algunas cosas importantes en las que pensar al crear un raspador web:

    • ¿Cuál es la estructura de la página web que contiene los datos que busca?
    • ¿Cómo llegamos a esas páginas web?
    • ¿Necesitará recopilar más datos de la página siguiente?

    La URL

    Para empezar, veamos la URL de la página que queremos raspar.

    Notamos algunas cosas sobre la URL:

    • ? actúa como un separador: indica el final de la ruta del recurso URL y el inicio de los parámetros
    • groups=top_1000 especifica de qué se tratará la página
    • &ref_adv_prv nos lleva a la página anterior o siguiente. La referencia es la página en la que estamos actualmente. adv_nxt y adv_prv hay dos valores posibles, traducidos a avanzar a la página siguiente y avanzar a la página anterior.

    Cuando navega hacia adelante y hacia atrás por las páginas, notará que solo cambian los parámetros. Tenga en cuenta esta estructura, ya que es útil saberlo mientras construimos el raspador.

    El HTML

    HTML significa Lenguaje de marcado de hipertexto, y la mayoría de las páginas web se escriben con él. Esencialmente, HTML es cómo dos computadoras se comunican entre sí a través de Internet, y los sitios web están qué ellos dicen.

    Cuando accede a una URL, su computadora envía una solicitud al servidor que aloja el sitio. Se puede ejecutar cualquier tecnología en ese servidor (JavaScript, Ruby, Java, etc.) para procesar su solicitud. Finalmente, el servidor devuelve una respuesta a su navegador; a menudo, esa respuesta será en forma de una página HTML para que la muestre su navegador.

    HTML describe la estructura de una página web de forma semántica y originalmente incluía señales para la apariencia del documento.

    Inspeccionar HTML

    Los usuarios de Chrome, Firefox y Safari pueden examinar la estructura HTML de cualquier página haciendo clic con el botón derecho del mouse y presionando la opción Inspeccionar.

    Este es el título de la imagen

    Aparecerá un menú en la parte inferior o en el lado derecho de su página con una lista larga de todas las etiquetas HTML que contienen la información que se muestra en la ventana de su navegador. Si estás en Safari (foto de arriba), querrás presionar el botón a la izquierda de la barra de búsqueda, que parece un objetivo. Si está en Chrome o Firefox, hay un pequeño cuadro con un ícono de flecha en la parte superior izquierda que usará para inspeccionar.

    Una vez que haga clic, si mueve el cursor sobre cualquier elemento de la página, notará que se resaltará junto con las etiquetas HTML en el menú con el que están asociados, como se ve arriba.

    Saber cómo leer la estructura básica de la página HTML de una página es importante para que podamos recurrir a Python para que nos ayude a extraer el HTML de la página.

    Instrumentos

    Las herramientas que vamos a utilizar son:

    • Responder (opcional) es un entorno de programación informática interactivo y sencillo que se utiliza a través de su navegador web. Recomiendo usar esto solo para propósitos de código si aún no tiene un IDE. Si usa Repl, asegúrese de estar usando el entorno Python.
    • Peticiones nos permitirá enviar solicitudes HTTP para obtener archivos HTML
    • Hermosa Sopa nos ayudará a analizar los archivos HTML
    • pandas nos ayudará a reunir los datos en un DataFrame para limpiarlo y analizarlo
    • NumPy agregará soporte para funciones matemáticas y herramientas para trabajar con matrices

    Ahora, codifiquemos

    Puede seguir a continuación dentro de su entorno Repl o IDE, o puede ir directamente a el código completo aquí . ¡Divertirse!

    Importar herramientas

    Primero, importaremos las herramientas que necesitaremos para que podamos usarlas para ayudarnos a construir el raspador y obtener los datos que necesitamos.

    |_+_|

    Películas en inglés

    Es muy probable que cuando ejecutemos nuestro código para extraer algunas de estas películas, obtengamos los nombres de las películas traducidos al idioma principal del país en el que se originó.

    Utilice este código para asegurarse de que obtengamos títulos traducidos al inglés de todas las películas que extraemos:

    |_+_|

    Solicitar contenido de la URL

    Obtenga el contenido de la página que estamos viendo solicitando la URL:

    |_+_|

    Desglose de las solicitudes de URL:

    • import requests from requests import get from bs4 import BeautifulSoup import pandas as pd import numpy as np es la variable que creamos y asignamos la URL a
    • headers = {'Accept-Language': 'en-US, en;q=0.5'} es la variable que creamos para almacenar nuestro url = 'https://www.imdb.com/search/title/?groups=top_1000&ref_=adv_prv' results = requests.get(url, headers=headers) acción
    • url es el método que usamos para capturar el contenido de la URL. El results parte le dice a nuestro raspador que nos traiga inglés, basado en nuestra línea de código anterior.

    Usando BeautifulSoup

    Haga que el contenido que tomamos sea fácil de leer usando request.get:

    |_+_|

    Rompiendo BeautifulSoup Down:

    • requests.get(url, headers=headers) es la variable que creamos para asignar el método headers to, que especifica un formato de resultados deseado utilizando el analizador HTML; esto permite que Python lea los componentes de la página en lugar de tratarla como una cadena larga
    • BeautifulSoup imprimirá lo que hemos tomado en un formato de árbol más estructurado, lo que facilitará su lectura.

    Los resultados de la impresión se verán más ordenados, así:

    |_+_|

    Rotura |_+_| abajo:

    Prepárate para extraer cada artículo

    Este es el título de la imagen

    ¡Nos están perdiendo los ingresos brutos! Si miras la segunda película, la han incluido allí.

    Este es el título de la imagen

    Algo a tener en cuenta siempre al crear un raspador web es la idea de que no toda la información que busca estará disponible para que la recopile.

    En estos casos, debemos asegurarnos de que nuestro raspador web no deje de funcionar o se rompa cuando llegue a los datos faltantes y construyamos en torno a la idea de que simplemente no sabemos si eso sucederá o no.

    Entrar en cada lister-item div

    Cuando tomamos cada uno de los elementos que necesitamos en un solo mode-advanced lister-item mode-advanced contenedor, necesitamos que el raspador pase al siguiente div lister-item mode-advanced contenedor y coge esos elementos de la película también. Y luego debe pasar a la siguiente y así sucesivamente, 50 veces para cada página. Para que esto se ejecute, tendremos que envolver nuestro raspador en un bucle for.

    |_+_|

    Rompiendo el |_+_| círculo:

    • Un bucle lister-item mode-advanced se utiliza para iterar sobre una secuencia. Nuestra secuencia es cada contenedor movie_div = soup.find_all('div', class_='lister-item mode-advanced') div que almacenamos en **find_all**
    • movie_div es el nombre de la variable que ingresa cada div. Puede nombrar esto como quiera (lister-item mode-advanced, find_all(), div, class), y no cambiará la función del bucle.

    Se puede leer así:

    |_+_|

    Extrae el título de la película.

    Comenzando con el nombre de la película, busquemos su línea HTML correspondiente usando inspeccionar y haciendo clic en el título.

    Este es el título de la imagen

    Vemos que el nombre está contenido dentro de una etiqueta de anclaje, lister-item mode-advanced. El lister-item mode-advanced etiqueta. Este `` es el tercero de los lister-item mode-advanced s anidados en el contenedor de la primera película.

    |_+_|

    Desglosando títulos:

    • div es la variable que usaremos para almacenar los datos del título que encontremos
    • lister-item mode-advanced es lo que se usa en nuestro bucle for; se usa para iterar cada vez
    • div y #initiate the for loop #this tells your scraper to iterate through #every div container we stored in move_div for container in movie_div: es notación de atributo y le dice al raspador que acceda a cada una de esas etiquetas
    • **for** le dice al raspador que tome el texto anidado en la etiqueta ``
    • for le dice al raspador que tome lo que encontramos y almacenamos en lister-item mode-advanced y agregarlo a nuestra lista vacía llamada movie_div, que creamos al principio

    Extraer año de lanzamiento

    Busquemos el año de la película y su línea HTML correspondiente usando inspeccionar y haciendo clic en el año.

    Este es el título de la imagen

    Vemos que estos datos se almacenan dentro de container etiqueta que contiene el título de la película. La notación de puntos, que usamos para encontrar los datos del título (div), funcionó porque era la primera x La etiqueta que queremos es la segunda etiqueta, tenemos que usar un método diferente.

    En cambio, podemos decirle a nuestro raspador que busque por la marca distintiva del segundo ''. Usaremos el loop método , que es similar a banana excepto que solo devuelve la primera coincidencia.

    |_+_|

    Desglosando años:

    • cheese es la variable que usaremos para almacenar los datos del año que encontremos
    • for in : OR in our case... for each lister-item mode-advanced div container: scrape these elements es lo que usamos en nuestro . This tag is nested within a header tag, bucle: se usa para iterar cada vez
    • tag is nested within a es la notación de atributo, que le dice al raspador que acceda a esa etiqueta
    • div es un método que usaremos para acceder a esta `` etiqueta
    • name = container.h3.a.text titles.append(name) es la etiqueta distintiva que queremos
    • name le dice al raspador que tome lo que encontramos y almacenamos en container y agregarlo a nuestra lista vacía llamada .h3 (que creamos al principio)

    Extraer la duración de la película

    Busque la duración de la película y su línea HTML correspondiente utilizando inspeccionar y haciendo clic en el total de minutos.

    Este es el título de la imagen

    Los datos que necesitamos se pueden encontrar en una etiqueta con una clase de .a. Como hicimos con el año, podemos hacer algo similar:

    |_+_|

    Rompiendo el tiempo:

    • .text es la variable que usaremos para almacenar los datos de tiempo que encontremos
    • titles.append(name) es lo que usamos en nuestro name bucle: se usa para iterar cada vez
    • titles es un método que usaremos para acceder a esta `` etiqueta
    • tag below the es la etiqueta distintiva que queremos
    • .h3.a dice que si hay datos allí, consígalos, pero si faltan datos, coloque un guión allí
    • tag after the `h3` tag. Since the le dice al raspador que tome ese texto en la etiqueta ``
    • find() le dice al raspador que tome lo que encontramos y almacenamos en find_all() y agregarlo a nuestra lista vacía llamada year = container.h3.find('span', class_='lister-item-year').text years.append(year) (que creamos al principio)

    Extraer calificaciones de IMDb

    Busque la calificación de IMDb de la película y su línea HTML correspondiente utilizando inspeccionar y haciendo clic en la calificación de IMDb.

    Este es el título de la imagen

    Ahora, nos centraremos en extraer la calificación de IMDb. Los datos que necesitamos se pueden encontrar en un year etiqueta. Como no veo ningún otro container etiquetas, podemos usar la notación de atributos (notación de puntos) para capturar estos datos.

    |_+_|

    Desglosando las calificaciones de IMDb:

    • for es la variable que usaremos para almacenar los datos de calificaciones de IMDB que encuentre
    • .h3 es lo que usamos en nuestro .find() bucle: se usa para iterar cada vez
    • (‘span’, class_ = ‘lister-item-year’) es una notación de atributo que le dice al raspador que acceda a esa etiqueta
    • years.append(year) le dice al raspador que tome ese texto
    • El year El método convierte el texto que encontramos en un flotante, que es un decimal
    • years le dice al raspador que tome lo que encontramos y almacenamos en runtime y agregarlo a nuestra lista vacía llamada runtime = container.find('span', class_='runtime').text if container.p.find('span', class_='runtime') else '' time.append(runtime) (que creamos al principio)

    Extraer Metascore

    Busque la calificación de Metascore de la película y su línea HTML correspondiente utilizando inspeccionar y haciendo clic en el número de Metascore.

    Este es el título de la imagen

    Los datos que necesitamos se pueden encontrar en una etiqueta `` que tiene una clase que dice runtime.

    Antes de decidirnos por eso, debe notar que, por supuesto, un 96 para Parasite muestra una calificación favorable, pero ¿son favorables los demás? Si resaltas el Metascore de la siguiente película, verás que JoJo Rabbit tiene una clase que dice container. Dado que estas etiquetas son diferentes, sería seguro decirle al raspador que use solo la clase for al raspar:

    |_+_|

    Desglosando Metascores:

    • .find() es la variable que usaremos para almacenar los datos de calificación de Metascore que encuentre
    • (‘span’, class_ = ‘runtime’) es lo que usamos en nuestro if container.p.find(‘span’, class_=’runtime’) else ‘-’ bucle: se usa para iterar cada vez
    • .text es un método que usaremos para acceder a esta `` etiqueta
    • time.append(runtime) es la etiqueta distintiva que queremos
    • runtime le dice al raspador que tome ese texto
    • time dice que si hay datos allí, consígalos, pero si faltan datos, coloque un guión allí
    • El ** El método convierte el texto que encontramos en un número entero.
    • ** le dice al raspador que tome lo que encontramos y almacenamos en imdb = float(container.strong.text) imdb_ratings.append(imdb) y agregarlo a nuestra lista vacía llamada imdb (que creamos al principio)

    Extraer votos e ingresos brutos

    Finalmente llegamos a los dos últimos elementos que necesitamos extraer, pero dejamos los más difíciles para el final.

    Aquí es donde las cosas se ponen un poco complicadas. Como se mencionó anteriormente, debería haber notado que cuando miramos la primera película de esta lista, no vemos un número de ingresos brutos. Cuando miramos la segunda película de la lista, podemos ver ambas.

    Echemos un vistazo al código HTML de la segunda película y partamos de ahí.

    Este es el título de la imagen

    Tanto los votos como los brutos están resaltados a la derecha. Después de mirar los votos y los contenedores brutos para la película # 2, ¿qué notas?

    Como puede ver, ambos están en una etiqueta `` que tiene un container atributo que es igual a for y un .strong atributo que contiene los valores del número distintivo que necesitamos para cada uno.

    ¿Cómo podemos obtener los datos del segundo si los parámetros de búsqueda del primero son los mismos? ¿Cómo le decimos a nuestro raspador que se salte el primero y raspe el segundo?

    Este requirió mucho esfuerzo mental, toneladas de café y un par de noches para descubrirlo. Así es como lo hice:

    |_+_|

    Rompiendo votos y brutos abajo:

    • .text es una variable completamente nueva que usaremos para almacenar tanto los votos como las etiquetas `` brutas ''
    • float() es lo que usamos en nuestro imdb_ratings.append(imdb) bucle para iterar cada vez
    • imdb es el método que usaremos para obtener las dos `` etiquetas
    • imdb_ratings es cómo podemos tomar los atributos de esa etiqueta específica.
    • metascore favorable es la variable que usaremos para almacenar los votos que encontremos en el metascore mixed etiqueta
    • metascore le dice al raspador que entre en m_score = container.find('span', class_='metascore').text if container.find('span', class_='metascore') else '-' metascores.append(m_score) etiqueta y toma los primeros datos de la lista, que son los votos porque m_score viene primero en nuestro código HTML (las computadoras cuentan en binario; comienzan a contar en 0, no en 1)
    • container le dice al raspador que tome ese texto
    • for le dice al raspador que tome lo que encontramos y almacenamos en .find() y agregarlo a nuestra lista vacía llamada (‘span’, class_ = ‘metascore’) (que creamos al principio)
    • .text es la variable que usaremos para almacenar el bruto que encontremos en if container.find(‘span’, class_=’metascore’) else ‘-’ etiqueta
    • int() le dice al raspador que entre en metascores.append(m_score) etiqueta y tome el segundo dato de la lista, que es m_score porque metascores ocupa el segundo lugar en nuestro código HTML
    • name dice si la longitud de nv es mayor que uno, luego busque el segundo dato almacenado. Pero si los datos almacenados en data-value no es mayor que uno, es decir, si falta el valor bruto, coloque un guión allí
    • nv = container.find_all('span', attrs={'name': 'nv'}) vote = nv[0].text votes.append(vote) grosses = nv[1].text if len(nv) > 1 else '-' us_gross.append(grosses) le dice al raspador que tome lo que encontramos y almacenamos en nv y agregarlo a nuestra lista vacía llamada container (que creamos al principio)

    Su código ahora debería verse así:

    |_+_|

    Veamos lo que tenemos hasta ahora

    Ahora que le hemos dicho a nuestro raspador qué elementos raspar, usemos el for función para imprimir cada lista a la que hemos enviado nuestros datos extraídos:

    |_+_|

    Nuestras listas se ven así

    |_+_|

    Hasta ahora todo va bien, pero todavía no hemos llegado a ese punto. Necesitamos limpiar un poco nuestros datos. Parece que tenemos algunos elementos no deseados en nuestros datos: signos de dólar, find_all() s, (‘span’, attrs = ‘name’ : ’nv’) s, comas, paréntesis y espacio en blanco adicional en los Metascores.

    Construyendo un DataFrame con pandas

    El siguiente orden del día es construir un vote con pandas para almacenar los datos que tenemos muy bien en una tabla para comprender realmente lo que está sucediendo.

    Así es como lo hacemos:

    |_+_|

    Desglosando nuestro marco de datos:

    • nv es lo que llamaremos nuestro nv[0]
    • nv así es como inicializamos la creación de un votes con pandas
    • Las claves de la izquierda son los nombres de las columnas.
    • Los valores de la derecha son nuestras listas de datos que hemos extraído

    Ver nuestro DataFrame

    Podemos ver cómo se ve todo simplemente usando el .text función en nuestro votes.append(vote) —Que llamamos vote —Al final de nuestro programa:

    |_+_|

    Nuestro DataFrame de pandas se ve así

    Este es el título de la imagen

    Calidad de los datos

    Antes de embarcarse en proyectos como este, debe saber cuáles son sus criterios de calidad de datos, es decir, qué reglas o restricciones deben seguir sus datos. Aquí hay unos ejemplos:

    • Restricciones de tipo de datos: Los valores en sus columnas deben ser de un tipo de datos particular: numérico, booleano, fecha, etc.
    • Restricciones obligatorias : Algunas columnas no pueden estar vacías
    • Patrones de expresión regular: T campos ext que tienen que estar en un patrón determinado, como números de teléfono

    ¿Qué es la limpieza de datos?

    Limpieza de datos es el proceso de detección y corrección o eliminación de registros corruptos o inexactos de su conjunto de datos.

    Al realizar un análisis de datos, también es importante asegurarse de que estamos usando los tipos de datos correctos.

    Comprobación de tipos de datos

    Podemos comprobar cómo se ven nuestros tipos de datos ejecutando esto votes función en la parte inferior de nuestro programa:

    |_+_|

    Resultados de nuestro tipo de datos

    Este es el título de la imagen

    Analicemos esto: nuestro tipo de datos de películas es un objeto, que es lo mismo que una cadena, lo cual sería correcto considerando que son títulos de películas. Nuestra puntuación de IMDb también es correcta porque tenemos números de punto flotante en esta columna (números decimales).

    Pero nuestros grosses, nv, nv[1] y nv muestran que son objetos cuando deberían ser tipos de datos enteros, y nuestro gross es un objeto en lugar de un gross tipo de datos. ¿Cómo pasó esto?

    Inicialmente, cuando le decíamos a nuestro raspador que tomara estos valores de cada contenedor HTML, le decíamos que tomara valores específicos de una cadena. Una cadena representa texto en lugar de números; se compone de un conjunto de caracteres que pueden además contienen números.

    Por ejemplo, la palabra nv[1].text if len(nv) > 1 else ‘-’ y la frase nv son ambas cadenas. Si tuviéramos que deshacernos de todo excepto de nv de us_gross.append(grosses), sigue siendo una cadena, pero ahora es una que solo dice grosses.

    Limpieza de datos con pandas

    Ahora que tenemos una idea clara de cómo se ven nuestros datos en este momento, es hora de comenzar a limpiarlos.

    Esta puede ser una tarea tediosa, pero es muy importante.

    Datos del año de limpieza

    Para eliminar los paréntesis de nuestros datos anuales y convertir el objeto en un tipo de datos enteros, haremos lo siguiente:

    |_+_|

    Desglose de los datos del año de limpieza:

    • us_grosses le dice a los pandas que vayan a la columna import requests from requests import get from bs4 import BeautifulSoup import pandas as pd import numpy as np url = 'https://www.imdb.com/search/title/?groups=top_1000&ref_=adv_prv' headers = {'Accept-Language': 'en-US, en;q=0.5'} results = requests.get(url, headers=headers) soup = BeautifulSoup(results.text, 'html.parser') titles = [] years = [] time = [] imdb_ratings = [] metascores = [] votes = [] us_gross = [] movie_div = soup.find_all('div', class_='lister-item mode-advanced') for container in movie_div: #Name name = container.h3.a.text titles.append(name) #year year = container.h3.find('span', class_='lister-item-year').text years.append(year) #time runtime = container.p.find('span', class_='runtime').text if container.p.find('span', class_='runtime').text else '-' time.append(runtime) #IMDb rating imdb = float(container.strong.text) imdb_ratings.append(imdb) #metascore m_score = container.find('span', class_='metascore').text if container.find('span', class_='metascore') else '-' metascores.append(m_score) #here are two NV containers, grab both of them as they hold both the votes and the grosses nv = container.find_all('span', attrs={'name': 'nv'}) #filter nv for votes vote = nv[0].text votes.append(vote) #filter nv for gross grosses = nv[1].text if len(nv) > 1 else '-' us_gross.append(grosses) en nuestro print
    • print(titles) print(years) print(time) print(imdb_ratings) print(metascores) print(votes) print(us_gross) este método: ['Parasite', 'Jojo Rabbit', '1917', 'Knives Out', 'Uncut Gems', 'Once Upon a Time... in Hollywood', 'Joker', 'The Gentlemen', 'Ford v Ferrari', 'Little Women', 'The Irishman', 'The Lighthouse', 'Toy Story 4', 'Marriage Story', 'Avengers: Endgame', 'The Godfather', 'Blade Runner 2049', 'The Shawshank Redemption', 'The Dark Knight', 'Inglourious Basterds', 'Call Me by Your Name', 'The Two Popes', 'Pulp Fiction', 'Inception', 'Interstellar', 'Green Book', 'Blade Runner', 'The Wolf of Wall Street', 'Gone Girl', 'The Shining', 'The Matrix', 'Titanic', 'The Silence of the Lambs', 'Three Billboards Outside Ebbing, Missouri', 'Harry Potter and the Sorcerer's Stone', 'The Peanut Butter Falcon', 'The Handmaiden', 'Memories of Murder', 'The Lord of the Rings: The Fellowship of the Ring', 'Gladiator', 'The Martian', 'Bohemian Rhapsody', 'Watchmen', 'Forrest Gump', 'Thor: Ragnarok', 'Casino Royale', 'The Breakfast Club', 'The Godfather: Part II', 'Django Unchained', 'Baby Driver'] ['(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(I) (2019)', '(2019)', '(2019)', '(2019)', '(1972)', '(2017)', '(1994)', '(2008)', '(2009)', '(2017)', '(2019)', '(1994)', '(2010)', '(2014)', '(2018)', '(1982)', '(2013)', '(2014)', '(1980)', '(1999)', '(1997)', '(1991)', '(2017)', '(2001)', '(2019)', '(2016)', '(2003)', '(2001)', '(2000)', '(2015)', '(2018)', '(2009)', '(1994)', '(2017)', '(2006)', '(1985)', '(1974)', '(2012)', '(2017)'] ['132 min', '108 min', '119 min', '131 min', '135 min', '161 min', '122 min', '113 min', '152 min', '135 min', '209 min', '109 min', '100 min', '137 min', '181 min', '175 min', '164 min', '142 min', '152 min', '153 min', '132 min', '125 min', '154 min', '148 min', '169 min', '130 min', '117min', '180 min', '149 min', '146 min', '136 min', '194 min', '118 min', '115 min', '152 min', '97 min', '145 min', '132 min', '178 min', '155 min', '144 min', '134 min', '162 min', '142 min', '130 min', '144 min', '97 min', '202 min', '165 min', '113 min'] [8.6, 8.0, 8.5, 8.0, 7.6, 7.7, 8.6, 8.1, 8.2, 8.0, 8.0, 7.7, 7.8, 8.0, 8.5, 9.2, 8.0, 9.3, 9.0, 8.3, 7.9, 7.6, 8.9, 8.8, 8.6, 8.2, 8.1, 8.2, 8.1,8.4, 8.7, 7.8, 8.6, 8.2, 7.6, 7.7, 8.1, 8.1, 8.8, 8.5, 8.0, 8.0, 7.6, 8.8, 7.9, 8.0, 7.9, 9.0, 8.4, 7.6] ['96 ', '58 ', '78 ', '82 ', '90 ', '83 ', '59 ', '51 ', '81 ', '91 ', '94 ', '83 ', '84 ', '93 ', '78 ', '100 ', '81 ', '80 ', '84 ', '69 ', '93 ', '75 ', '94 ', '74 ', '74 ', '69 ', '84 ', '75 ', '79 ', '66 ', '73 ', '75 ', '85 ', '88 ', '64 ', '70 ', '84 ', '82 ', '92 ', '67 ', '80 ', '49 ', '56 ', '82 ', '74 ', '80 ', '62 ', '90 ', '81 ', '86 '] ['282,699', '142,517', '199,638', '195,728', '108,330', '396,071', '695,224', '42,015', '152,661', '65,234', '249,950', '77,453', '160,180', '179,887', '673,115', '1,511,929', '414,992', '2,194,397', '2,176,865', '1,184,882', '178,688', '76,291', '1,724,518', '1,925,684', '1,378,968', '293,695', '656,442', '1,092,063', '799,696', '835,496', '1,580,250', '994,453', '1,191,182', '383,958', '595,613', '34,091', '92,492', '115,125', '1,572,354', '1,267,310', '715,623', '410,199', '479,811', '1,693,344', '535,065', '555,756', '330,308', '1,059,089', '1,271,569', '398,553'] ['-', '$0.35M', '-', '-', '-', '$135.37M', '$192.73M', '-', '-', '-', '-', '$0.43M', '$433.03M', '-', '$858.37M', '$134.97M', '$92.05M', '$28.34M', '$534.86M', '$120.54M', '$18.10M', '-', '$107.93M', '$292.58M', '$188.02M', '$85.08M', '$32.87M', '$116.90M', '$167.77M', '$44.02M', '$171.48M', '$659.33M', '$130.74M', '$54.51M', '$317.58M', '$13.12M', '$2.01M', '$0.01M', '$315.54M', '$187.71M', '$228.43M', '$216.43M', '$107.51M', '$330.25M', '$315.06M', '$167.45M', '$45.88M', '$57.30M', '$162.81M', '$107.83M'] dice que extraiga todos los dígitos de la cadena
    • El M El método convierte el resultado en un número entero.

    Ahora, si ejecutamos min en la parte inferior de nuestro programa para ver cómo se ven nuestros datos anuales, este es el resultado:

    Este es el título de la imagen

    Debería ver su lista de años sin paréntesis. Y el tipo de datos que se muestra ahora es un número entero. Nuestros datos anuales se limpian oficialmente.

    Datos de tiempo de limpieza

    Haremos exactamente lo que hicimos al limpiar nuestros datos de años anteriores a nuestros datos de tiempo al tomar solo los dígitos y convertir nuestro tipo de datos en un número entero.

    |_+_|

    Limpieza de datos de Metascore

    La única limpieza que debemos hacer aquí es convertir nuestro tipo de datos de objeto en un número entero:

    |_+_|

    Limpieza de votos

    Con los votos, necesitamos eliminar las comas y convertirlo en un tipo de datos entero:

    |_+_|

    Rompiendo los votos de limpieza en contra:

    • DataFrame son nuestros datos de votos en nuestras películas movies = pd.DataFrame({ 'movie': titles, 'year': years, 'timeMin': time, 'imdb': imdb_ratings, 'metascore': metascores, 'votes': votes, 'us_grossMillions': us_gross, }) . Estamos asignando nuestros nuevos datos limpiados a nuestros votos movies.
    • . DataFrame agarra la cadena y usa el pd.DataFrame método para reemplazar las comas con una cita vacía (nada)
    • El DataFrame El método convierte el resultado en un número entero.

    Limpieza de datos brutos

    Los datos brutos implican algunos obstáculos que superar. Lo que tenemos que hacer es eliminar el signo de dólar y el print s de los datos y convertirlo en un número de punto flotante. A continuación, le indicamos cómo hacerlo:

    |_+_|

    Desglose de la limpieza en bruto:

    Código de limpieza superior:

    • DataFrame son nuestros datos brutos en nuestras películas movies. Asignaremos nuestros nuevos datos limpiados a nuestro print(movies) columna.
    • print le dice a los pandas que vayan a la columna print(movies.dtypes) en nuestro year
    • El timeMin la función llama a la función especificada para cada elemento de un iterable
    • metascore es una función anónima en Python (una sin nombre). Las funciones normales se definen mediante votes palabra clave.
    • us_grossMillions son nuestros argumentos de función. Esto le dice a nuestra función que elimine el float del lado izquierdo y pele el cheese desde el lado derecho.

    Código de conversión inferior:

    • I ate 10 blocks of cheese está despojado de los elementos que no necesitamos, y ahora le asignaremos los datos del código de conversión para terminarlo
    • 10 es un método que podemos usar para cambiar esta columna a un flotante. La razón por la que usamos esto es porque tenemos muchos guiones en esta columna, y no podemos convertirla en un flotante usando I ate 10 blocks of cheese string - esto detectaría un error.
    • 10 transformará los valores no numéricos, nuestros guiones, en valores NaN (no un número) porque tenemos guiones en lugar de los datos que faltan

    Revise el código limpiado y convertido

    Veamos cómo lo hicimos. Ejecute el movies['year'] = movies['year'].str.extract('(d+)').astype(int) función para ver nuestros datos y los tipos de datos que tenemos:

    |_+_|

    El resultado de nuestros datos limpios

    Este es el título de la imagen

    El resultado de nuestros tipos de datos

    Este es el título de la imagen

    ¡Se ve bien!

    Código final terminado

    Aquí está el código final de su raspador web de una sola página:

    |_+_|

    Guardar sus datos en un CSV

    ¿De qué sirven nuestros datos extraídos si no podemos guardarlos para proyectos o análisis futuros? A continuación se muestra el código que puede agregar al final de su programa para guardar sus datos en un archivo CSV:

    |_+_|

    Desglosando el archivo CSV:

    • |_+_|

    Para que este código se ejecute correctamente, deberá crear un archivo vacío y nombrarlo como desee, asegurándose de que tenga la extensión movies[‘year’]. Llamé al mío year, como puede ver arriba, pero siéntase libre de nombrarlo como quiera. Solo asegúrese de cambiar el código anterior para que coincida.

    Si está en Repl, puede crear un archivo CSV vacío colocando el cursor cerca de Archivos y haciendo clic en la opción Agregar archivo. Nómbrelo y guárdelo con un DataFrame extensión. Luego, agregue el código al final de su programa:

    |_+_|

    Todos sus datos deberían aparecer en su CSV. Una vez que lo descargue en su computadora / lo abra, su archivo se verá así:

    Este es el título de la imagen

    Conclusión

    Hemos recorrido un largo camino desde solicitar el contenido HTML de nuestra página web hasta limpiar toda nuestra .str.extract(‘(d+’). Ahora debería saber cómo extraer páginas web con la misma estructura de URL y HTML que le mostré anteriormente. A continuación, se muestra un resumen de lo que hemos logrado:

    |_+_|

    Próximos pasos

    ¡Espero que te hayas divertido haciendo esto!

    Si desea aprovechar lo que ha aprendido, aquí tiene algunas ideas para probar:

    • Obtenga los datos de la película para las 1,000 películas en esa lista
    • Extraiga otros datos sobre cada película, por ejemplo, género, director, protagonista o el resumen de la película.
    • Encuentra un sitio web diferente para raspar que te interese

    En mi próximo artículo, explicaré cómo recorrer todas las páginas de esta lista de IMDb para capturar todas las 1,000 películas, lo que implicará algunas alteraciones en el código final que tenemos aquí.

    ¡Feliz codificación!

    # python # ciencia de datos # aprendizaje automático # programación






    .35M', '-', '-', '-', '5.37M', '2.73M', '-', '-', '-', '-', '

    Construyendo un Web Scraper con Python en 30 minutos

    Mis habilidades en Python son básicas, así que si estás aquí sin muchas habilidades en codificación, espero que esta guía te ayude a adquirir más conocimientos y comprensión.

    El proyecto perfecto para principiantes

    Para obtener datos para proyectos de ML, IA o ciencia de datos, a menudo dependerá de bases de datos, API o conjuntos de datos CSV listos para usar. Pero, ¿qué pasa si no puede encontrar un conjunto de datos que desee utilizar y analizar? Ahí es donde entra en juego un raspador web.

    Trabajar en proyectos es fundamental para consolidar los conocimientos adquiridos. Cuando comencé este proyecto, estaba un poco abrumado porque realmente no sabía nada.

    Seguir con él, encontrar respuestas a mis preguntas en Stack Overflow y muchas pruebas y errores me ayudaron a comprender realmente cómo funciona la programación: cómo funcionan las páginas web, cómo usar bucles y cómo crear funciones y mantener los datos limpios. Hace que la construcción de un raspador web sea el proyecto perfecto para principiantes para cualquiera que se esté iniciando en Python.

    Que cubriremos

    Esta guía lo guiará a través de la comprensión de las páginas web HTML, la creación de un raspador web con Python y la creación de un DataFrame con pandas. Cubrirá la calidad de los datos, la limpieza de datos y la conversión de tipos de datos, completamente paso a paso y con instrucciones, código y explicaciones sobre cómo funciona cada pieza. ¡Espero que codifiques y disfrutes!

    Descargo de responsabilidad

    Los sitios web pueden restringir o prohibir la extracción de datos de su sitio web. Los usuarios pueden estar sujetos a ramificaciones legales dependiendo de dónde y cómo intente recopilar información. Los sitios web suelen describir esto en sus términos de uso y en su robots.txt archivo encontrado en su sitio, que generalmente se parece a esto: [www.example.com/robots.txt](http://www.[site].com/robots.txt.). Así que raspe responsablemente y respete el robots.txt.

    ¿Qué es Web Scraping?

    Raspado web Consiste en recopilar datos disponibles en sitios web. Esto se puede hacer manualmente por un humano o usando un bot.

    A Bot es un programa creado por usted que le ayuda a extraer los datos que necesita mucho más rápido que la mano y los ojos de un ser humano.

    ¿Qué vamos a raspar?

    Es esencial identificar el objetivo de su raspado desde el principio. No queremos extraer ningún dato que en realidad no necesitemos.

    Para este proyecto, extraeremos datos de las 1,000 películas principales de IMDb, específicamente las 50 películas principales de esta página. Aquí está la información que recopilaremos de cada lista de películas:

    • El título
    • El año en que fue lanzado
    • Cuanto dura la pelicula
    • Calificación de IMDb de la película
    • El Metascore de la película
    • ¿Cuántos votos obtuvo la película?
    • Las ganancias brutas de la película en EE. UU.

    ¿Cómo funcionan los Web Scrapers?

    Los web scrapers recopilan datos del sitio web de la misma manera que lo haría un humano: van a una página web del sitio web, obtienen los datos relevantes y pasan a la siguiente página web, solo que mucho más rápido.

    Cada sitio web tiene una estructura diferente. Estas son algunas cosas importantes en las que pensar al crear un raspador web:

    • ¿Cuál es la estructura de la página web que contiene los datos que busca?
    • ¿Cómo llegamos a esas páginas web?
    • ¿Necesitará recopilar más datos de la página siguiente?

    La URL

    Para empezar, veamos la URL de la página que queremos raspar.

    Notamos algunas cosas sobre la URL:

    • ? actúa como un separador: indica el final de la ruta del recurso URL y el inicio de los parámetros
    • groups=top_1000 especifica de qué se tratará la página
    • &ref_adv_prv nos lleva a la página anterior o siguiente. La referencia es la página en la que estamos actualmente. adv_nxt y adv_prv hay dos valores posibles, traducidos a avanzar a la página siguiente y avanzar a la página anterior.

    Cuando navega hacia adelante y hacia atrás por las páginas, notará que solo cambian los parámetros. Tenga en cuenta esta estructura, ya que es útil saberlo mientras construimos el raspador.

    El HTML

    HTML significa Lenguaje de marcado de hipertexto, y la mayoría de las páginas web se escriben con él. Esencialmente, HTML es cómo dos computadoras se comunican entre sí a través de Internet, y los sitios web están qué ellos dicen.

    Cuando accede a una URL, su computadora envía una solicitud al servidor que aloja el sitio. Se puede ejecutar cualquier tecnología en ese servidor (JavaScript, Ruby, Java, etc.) para procesar su solicitud. Finalmente, el servidor devuelve una respuesta a su navegador; a menudo, esa respuesta será en forma de una página HTML para que la muestre su navegador.

    HTML describe la estructura de una página web de forma semántica y originalmente incluía señales para la apariencia del documento.

    Inspeccionar HTML

    Los usuarios de Chrome, Firefox y Safari pueden examinar la estructura HTML de cualquier página haciendo clic con el botón derecho del mouse y presionando la opción Inspeccionar.

    Este es el título de la imagen

    Aparecerá un menú en la parte inferior o en el lado derecho de su página con una lista larga de todas las etiquetas HTML que contienen la información que se muestra en la ventana de su navegador. Si estás en Safari (foto de arriba), querrás presionar el botón a la izquierda de la barra de búsqueda, que parece un objetivo. Si está en Chrome o Firefox, hay un pequeño cuadro con un ícono de flecha en la parte superior izquierda que usará para inspeccionar.

    Una vez que haga clic, si mueve el cursor sobre cualquier elemento de la página, notará que se resaltará junto con las etiquetas HTML en el menú con el que están asociados, como se ve arriba.

    Saber cómo leer la estructura básica de la página HTML de una página es importante para que podamos recurrir a Python para que nos ayude a extraer el HTML de la página.

    Instrumentos

    Las herramientas que vamos a utilizar son:

    • Responder (opcional) es un entorno de programación informática interactivo y sencillo que se utiliza a través de su navegador web. Recomiendo usar esto solo para propósitos de código si aún no tiene un IDE. Si usa Repl, asegúrese de estar usando el entorno Python.
    • Peticiones nos permitirá enviar solicitudes HTTP para obtener archivos HTML
    • Hermosa Sopa nos ayudará a analizar los archivos HTML
    • pandas nos ayudará a reunir los datos en un DataFrame para limpiarlo y analizarlo
    • NumPy agregará soporte para funciones matemáticas y herramientas para trabajar con matrices

    Ahora, codifiquemos

    Puede seguir a continuación dentro de su entorno Repl o IDE, o puede ir directamente a el código completo aquí . ¡Divertirse!

    Importar herramientas

    Primero, importaremos las herramientas que necesitaremos para que podamos usarlas para ayudarnos a construir el raspador y obtener los datos que necesitamos.

    |_+_|

    Películas en inglés

    Es muy probable que cuando ejecutemos nuestro código para extraer algunas de estas películas, obtengamos los nombres de las películas traducidos al idioma principal del país en el que se originó.

    Utilice este código para asegurarse de que obtengamos títulos traducidos al inglés de todas las películas que extraemos:

    |_+_|

    Solicitar contenido de la URL

    Obtenga el contenido de la página que estamos viendo solicitando la URL:

    |_+_|

    Desglose de las solicitudes de URL:

    • import requests from requests import get from bs4 import BeautifulSoup import pandas as pd import numpy as np es la variable que creamos y asignamos la URL a
    • headers = {'Accept-Language': 'en-US, en;q=0.5'} es la variable que creamos para almacenar nuestro url = 'https://www.imdb.com/search/title/?groups=top_1000&ref_=adv_prv' results = requests.get(url, headers=headers) acción
    • url es el método que usamos para capturar el contenido de la URL. El results parte le dice a nuestro raspador que nos traiga inglés, basado en nuestra línea de código anterior.

    Usando BeautifulSoup

    Haga que el contenido que tomamos sea fácil de leer usando request.get:

    |_+_|

    Rompiendo BeautifulSoup Down:

    • requests.get(url, headers=headers) es la variable que creamos para asignar el método headers to, que especifica un formato de resultados deseado utilizando el analizador HTML; esto permite que Python lea los componentes de la página en lugar de tratarla como una cadena larga
    • BeautifulSoup imprimirá lo que hemos tomado en un formato de árbol más estructurado, lo que facilitará su lectura.

    Los resultados de la impresión se verán más ordenados, así:

    |_+_|

    Rotura |_+_| abajo:

    Prepárate para extraer cada artículo

    Este es el título de la imagen

    ¡Nos están perdiendo los ingresos brutos! Si miras la segunda película, la han incluido allí.

    Este es el título de la imagen

    Algo a tener en cuenta siempre al crear un raspador web es la idea de que no toda la información que busca estará disponible para que la recopile.

    En estos casos, debemos asegurarnos de que nuestro raspador web no deje de funcionar o se rompa cuando llegue a los datos faltantes y construyamos en torno a la idea de que simplemente no sabemos si eso sucederá o no.

    Entrar en cada lister-item div

    Cuando tomamos cada uno de los elementos que necesitamos en un solo mode-advanced lister-item mode-advanced contenedor, necesitamos que el raspador pase al siguiente div lister-item mode-advanced contenedor y coge esos elementos de la película también. Y luego debe pasar a la siguiente y así sucesivamente, 50 veces para cada página. Para que esto se ejecute, tendremos que envolver nuestro raspador en un bucle for.

    |_+_|

    Rompiendo el |_+_| círculo:

    • Un bucle lister-item mode-advanced se utiliza para iterar sobre una secuencia. Nuestra secuencia es cada contenedor movie_div = soup.find_all('div', class_='lister-item mode-advanced') div que almacenamos en **find_all**
    • movie_div es el nombre de la variable que ingresa cada div. Puede nombrar esto como quiera (lister-item mode-advanced, find_all(), div, class), y no cambiará la función del bucle.

    Se puede leer así:

    |_+_|

    Extrae el título de la película.

    Comenzando con el nombre de la película, busquemos su línea HTML correspondiente usando inspeccionar y haciendo clic en el título.

    Este es el título de la imagen

    Vemos que el nombre está contenido dentro de una etiqueta de anclaje, lister-item mode-advanced. El lister-item mode-advanced etiqueta. Este `` es el tercero de los lister-item mode-advanced s anidados en el contenedor de la primera película.

    |_+_|

    Desglosando títulos:

    • div es la variable que usaremos para almacenar los datos del título que encontremos
    • lister-item mode-advanced es lo que se usa en nuestro bucle for; se usa para iterar cada vez
    • div y #initiate the for loop #this tells your scraper to iterate through #every div container we stored in move_div for container in movie_div: es notación de atributo y le dice al raspador que acceda a cada una de esas etiquetas
    • **for** le dice al raspador que tome el texto anidado en la etiqueta ``
    • for le dice al raspador que tome lo que encontramos y almacenamos en lister-item mode-advanced y agregarlo a nuestra lista vacía llamada movie_div, que creamos al principio

    Extraer año de lanzamiento

    Busquemos el año de la película y su línea HTML correspondiente usando inspeccionar y haciendo clic en el año.

    Este es el título de la imagen

    Vemos que estos datos se almacenan dentro de container etiqueta que contiene el título de la película. La notación de puntos, que usamos para encontrar los datos del título (div), funcionó porque era la primera x La etiqueta que queremos es la segunda etiqueta, tenemos que usar un método diferente.

    En cambio, podemos decirle a nuestro raspador que busque por la marca distintiva del segundo ''. Usaremos el loop método , que es similar a banana excepto que solo devuelve la primera coincidencia.

    |_+_|

    Desglosando años:

    • cheese es la variable que usaremos para almacenar los datos del año que encontremos
    • for in : OR in our case... for each lister-item mode-advanced div container: scrape these elements es lo que usamos en nuestro . This tag is nested within a header tag, bucle: se usa para iterar cada vez
    • tag is nested within a es la notación de atributo, que le dice al raspador que acceda a esa etiqueta
    • div es un método que usaremos para acceder a esta `` etiqueta
    • name = container.h3.a.text titles.append(name) es la etiqueta distintiva que queremos
    • name le dice al raspador que tome lo que encontramos y almacenamos en container y agregarlo a nuestra lista vacía llamada .h3 (que creamos al principio)

    Extraer la duración de la película

    Busque la duración de la película y su línea HTML correspondiente utilizando inspeccionar y haciendo clic en el total de minutos.

    Este es el título de la imagen

    Los datos que necesitamos se pueden encontrar en una etiqueta con una clase de .a. Como hicimos con el año, podemos hacer algo similar:

    |_+_|

    Rompiendo el tiempo:

    • .text es la variable que usaremos para almacenar los datos de tiempo que encontremos
    • titles.append(name) es lo que usamos en nuestro name bucle: se usa para iterar cada vez
    • titles es un método que usaremos para acceder a esta `` etiqueta
    • tag below the es la etiqueta distintiva que queremos
    • .h3.a dice que si hay datos allí, consígalos, pero si faltan datos, coloque un guión allí
    • tag after the `h3` tag. Since the le dice al raspador que tome ese texto en la etiqueta ``
    • find() le dice al raspador que tome lo que encontramos y almacenamos en find_all() y agregarlo a nuestra lista vacía llamada year = container.h3.find('span', class_='lister-item-year').text years.append(year) (que creamos al principio)

    Extraer calificaciones de IMDb

    Busque la calificación de IMDb de la película y su línea HTML correspondiente utilizando inspeccionar y haciendo clic en la calificación de IMDb.

    Este es el título de la imagen

    Ahora, nos centraremos en extraer la calificación de IMDb. Los datos que necesitamos se pueden encontrar en un year etiqueta. Como no veo ningún otro container etiquetas, podemos usar la notación de atributos (notación de puntos) para capturar estos datos.

    |_+_|

    Desglosando las calificaciones de IMDb:

    • for es la variable que usaremos para almacenar los datos de calificaciones de IMDB que encuentre
    • .h3 es lo que usamos en nuestro .find() bucle: se usa para iterar cada vez
    • (‘span’, class_ = ‘lister-item-year’) es una notación de atributo que le dice al raspador que acceda a esa etiqueta
    • years.append(year) le dice al raspador que tome ese texto
    • El year El método convierte el texto que encontramos en un flotante, que es un decimal
    • years le dice al raspador que tome lo que encontramos y almacenamos en runtime y agregarlo a nuestra lista vacía llamada runtime = container.find('span', class_='runtime').text if container.p.find('span', class_='runtime') else '' time.append(runtime) (que creamos al principio)

    Extraer Metascore

    Busque la calificación de Metascore de la película y su línea HTML correspondiente utilizando inspeccionar y haciendo clic en el número de Metascore.

    Este es el título de la imagen

    Los datos que necesitamos se pueden encontrar en una etiqueta `` que tiene una clase que dice runtime.

    Antes de decidirnos por eso, debe notar que, por supuesto, un 96 para Parasite muestra una calificación favorable, pero ¿son favorables los demás? Si resaltas el Metascore de la siguiente película, verás que JoJo Rabbit tiene una clase que dice container. Dado que estas etiquetas son diferentes, sería seguro decirle al raspador que use solo la clase for al raspar:

    |_+_|

    Desglosando Metascores:

    • .find() es la variable que usaremos para almacenar los datos de calificación de Metascore que encuentre
    • (‘span’, class_ = ‘runtime’) es lo que usamos en nuestro if container.p.find(‘span’, class_=’runtime’) else ‘-’ bucle: se usa para iterar cada vez
    • .text es un método que usaremos para acceder a esta `` etiqueta
    • time.append(runtime) es la etiqueta distintiva que queremos
    • runtime le dice al raspador que tome ese texto
    • time dice que si hay datos allí, consígalos, pero si faltan datos, coloque un guión allí
    • El ** El método convierte el texto que encontramos en un número entero.
    • ** le dice al raspador que tome lo que encontramos y almacenamos en imdb = float(container.strong.text) imdb_ratings.append(imdb) y agregarlo a nuestra lista vacía llamada imdb (que creamos al principio)

    Extraer votos e ingresos brutos

    Finalmente llegamos a los dos últimos elementos que necesitamos extraer, pero dejamos los más difíciles para el final.

    Aquí es donde las cosas se ponen un poco complicadas. Como se mencionó anteriormente, debería haber notado que cuando miramos la primera película de esta lista, no vemos un número de ingresos brutos. Cuando miramos la segunda película de la lista, podemos ver ambas.

    Echemos un vistazo al código HTML de la segunda película y partamos de ahí.

    Este es el título de la imagen

    Tanto los votos como los brutos están resaltados a la derecha. Después de mirar los votos y los contenedores brutos para la película # 2, ¿qué notas?

    Como puede ver, ambos están en una etiqueta `` que tiene un container atributo que es igual a for y un .strong atributo que contiene los valores del número distintivo que necesitamos para cada uno.

    ¿Cómo podemos obtener los datos del segundo si los parámetros de búsqueda del primero son los mismos? ¿Cómo le decimos a nuestro raspador que se salte el primero y raspe el segundo?

    Este requirió mucho esfuerzo mental, toneladas de café y un par de noches para descubrirlo. Así es como lo hice:

    |_+_|

    Rompiendo votos y brutos abajo:

    • .text es una variable completamente nueva que usaremos para almacenar tanto los votos como las etiquetas `` brutas ''
    • float() es lo que usamos en nuestro imdb_ratings.append(imdb) bucle para iterar cada vez
    • imdb es el método que usaremos para obtener las dos `` etiquetas
    • imdb_ratings es cómo podemos tomar los atributos de esa etiqueta específica.
    • metascore favorable es la variable que usaremos para almacenar los votos que encontremos en el metascore mixed etiqueta
    • metascore le dice al raspador que entre en m_score = container.find('span', class_='metascore').text if container.find('span', class_='metascore') else '-' metascores.append(m_score) etiqueta y toma los primeros datos de la lista, que son los votos porque m_score viene primero en nuestro código HTML (las computadoras cuentan en binario; comienzan a contar en 0, no en 1)
    • container le dice al raspador que tome ese texto
    • for le dice al raspador que tome lo que encontramos y almacenamos en .find() y agregarlo a nuestra lista vacía llamada (‘span’, class_ = ‘metascore’) (que creamos al principio)
    • .text es la variable que usaremos para almacenar el bruto que encontremos en if container.find(‘span’, class_=’metascore’) else ‘-’ etiqueta
    • int() le dice al raspador que entre en metascores.append(m_score) etiqueta y tome el segundo dato de la lista, que es m_score porque metascores ocupa el segundo lugar en nuestro código HTML
    • name dice si la longitud de nv es mayor que uno, luego busque el segundo dato almacenado. Pero si los datos almacenados en data-value no es mayor que uno, es decir, si falta el valor bruto, coloque un guión allí
    • nv = container.find_all('span', attrs={'name': 'nv'}) vote = nv[0].text votes.append(vote) grosses = nv[1].text if len(nv) > 1 else '-' us_gross.append(grosses) le dice al raspador que tome lo que encontramos y almacenamos en nv y agregarlo a nuestra lista vacía llamada container (que creamos al principio)

    Su código ahora debería verse así:

    |_+_|

    Veamos lo que tenemos hasta ahora

    Ahora que le hemos dicho a nuestro raspador qué elementos raspar, usemos el for función para imprimir cada lista a la que hemos enviado nuestros datos extraídos:

    |_+_|

    Nuestras listas se ven así

    |_+_|

    Hasta ahora todo va bien, pero todavía no hemos llegado a ese punto. Necesitamos limpiar un poco nuestros datos. Parece que tenemos algunos elementos no deseados en nuestros datos: signos de dólar, find_all() s, (‘span’, attrs = ‘name’ : ’nv’) s, comas, paréntesis y espacio en blanco adicional en los Metascores.

    Construyendo un DataFrame con pandas

    El siguiente orden del día es construir un vote con pandas para almacenar los datos que tenemos muy bien en una tabla para comprender realmente lo que está sucediendo.

    Así es como lo hacemos:

    |_+_|

    Desglosando nuestro marco de datos:

    • nv es lo que llamaremos nuestro nv[0]
    • nv así es como inicializamos la creación de un votes con pandas
    • Las claves de la izquierda son los nombres de las columnas.
    • Los valores de la derecha son nuestras listas de datos que hemos extraído

    Ver nuestro DataFrame

    Podemos ver cómo se ve todo simplemente usando el .text función en nuestro votes.append(vote) —Que llamamos vote —Al final de nuestro programa:

    |_+_|

    Nuestro DataFrame de pandas se ve así

    Este es el título de la imagen

    Calidad de los datos

    Antes de embarcarse en proyectos como este, debe saber cuáles son sus criterios de calidad de datos, es decir, qué reglas o restricciones deben seguir sus datos. Aquí hay unos ejemplos:

    • Restricciones de tipo de datos: Los valores en sus columnas deben ser de un tipo de datos particular: numérico, booleano, fecha, etc.
    • Restricciones obligatorias : Algunas columnas no pueden estar vacías
    • Patrones de expresión regular: T campos ext que tienen que estar en un patrón determinado, como números de teléfono

    ¿Qué es la limpieza de datos?

    Limpieza de datos es el proceso de detección y corrección o eliminación de registros corruptos o inexactos de su conjunto de datos.

    Al realizar un análisis de datos, también es importante asegurarse de que estamos usando los tipos de datos correctos.

    Comprobación de tipos de datos

    Podemos comprobar cómo se ven nuestros tipos de datos ejecutando esto votes función en la parte inferior de nuestro programa:

    |_+_|

    Resultados de nuestro tipo de datos

    Este es el título de la imagen

    Analicemos esto: nuestro tipo de datos de películas es un objeto, que es lo mismo que una cadena, lo cual sería correcto considerando que son títulos de películas. Nuestra puntuación de IMDb también es correcta porque tenemos números de punto flotante en esta columna (números decimales).

    Pero nuestros grosses, nv, nv[1] y nv muestran que son objetos cuando deberían ser tipos de datos enteros, y nuestro gross es un objeto en lugar de un gross tipo de datos. ¿Cómo pasó esto?

    Inicialmente, cuando le decíamos a nuestro raspador que tomara estos valores de cada contenedor HTML, le decíamos que tomara valores específicos de una cadena. Una cadena representa texto en lugar de números; se compone de un conjunto de caracteres que pueden además contienen números.

    Por ejemplo, la palabra nv[1].text if len(nv) > 1 else ‘-’ y la frase nv son ambas cadenas. Si tuviéramos que deshacernos de todo excepto de nv de us_gross.append(grosses), sigue siendo una cadena, pero ahora es una que solo dice grosses.

    Limpieza de datos con pandas

    Ahora que tenemos una idea clara de cómo se ven nuestros datos en este momento, es hora de comenzar a limpiarlos.

    Esta puede ser una tarea tediosa, pero es muy importante.

    Datos del año de limpieza

    Para eliminar los paréntesis de nuestros datos anuales y convertir el objeto en un tipo de datos enteros, haremos lo siguiente:

    |_+_|

    Desglose de los datos del año de limpieza:

    • us_grosses le dice a los pandas que vayan a la columna import requests from requests import get from bs4 import BeautifulSoup import pandas as pd import numpy as np url = 'https://www.imdb.com/search/title/?groups=top_1000&ref_=adv_prv' headers = {'Accept-Language': 'en-US, en;q=0.5'} results = requests.get(url, headers=headers) soup = BeautifulSoup(results.text, 'html.parser') titles = [] years = [] time = [] imdb_ratings = [] metascores = [] votes = [] us_gross = [] movie_div = soup.find_all('div', class_='lister-item mode-advanced') for container in movie_div: #Name name = container.h3.a.text titles.append(name) #year year = container.h3.find('span', class_='lister-item-year').text years.append(year) #time runtime = container.p.find('span', class_='runtime').text if container.p.find('span', class_='runtime').text else '-' time.append(runtime) #IMDb rating imdb = float(container.strong.text) imdb_ratings.append(imdb) #metascore m_score = container.find('span', class_='metascore').text if container.find('span', class_='metascore') else '-' metascores.append(m_score) #here are two NV containers, grab both of them as they hold both the votes and the grosses nv = container.find_all('span', attrs={'name': 'nv'}) #filter nv for votes vote = nv[0].text votes.append(vote) #filter nv for gross grosses = nv[1].text if len(nv) > 1 else '-' us_gross.append(grosses) en nuestro print
    • print(titles) print(years) print(time) print(imdb_ratings) print(metascores) print(votes) print(us_gross) este método: ['Parasite', 'Jojo Rabbit', '1917', 'Knives Out', 'Uncut Gems', 'Once Upon a Time... in Hollywood', 'Joker', 'The Gentlemen', 'Ford v Ferrari', 'Little Women', 'The Irishman', 'The Lighthouse', 'Toy Story 4', 'Marriage Story', 'Avengers: Endgame', 'The Godfather', 'Blade Runner 2049', 'The Shawshank Redemption', 'The Dark Knight', 'Inglourious Basterds', 'Call Me by Your Name', 'The Two Popes', 'Pulp Fiction', 'Inception', 'Interstellar', 'Green Book', 'Blade Runner', 'The Wolf of Wall Street', 'Gone Girl', 'The Shining', 'The Matrix', 'Titanic', 'The Silence of the Lambs', 'Three Billboards Outside Ebbing, Missouri', 'Harry Potter and the Sorcerer's Stone', 'The Peanut Butter Falcon', 'The Handmaiden', 'Memories of Murder', 'The Lord of the Rings: The Fellowship of the Ring', 'Gladiator', 'The Martian', 'Bohemian Rhapsody', 'Watchmen', 'Forrest Gump', 'Thor: Ragnarok', 'Casino Royale', 'The Breakfast Club', 'The Godfather: Part II', 'Django Unchained', 'Baby Driver'] ['(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(I) (2019)', '(2019)', '(2019)', '(2019)', '(1972)', '(2017)', '(1994)', '(2008)', '(2009)', '(2017)', '(2019)', '(1994)', '(2010)', '(2014)', '(2018)', '(1982)', '(2013)', '(2014)', '(1980)', '(1999)', '(1997)', '(1991)', '(2017)', '(2001)', '(2019)', '(2016)', '(2003)', '(2001)', '(2000)', '(2015)', '(2018)', '(2009)', '(1994)', '(2017)', '(2006)', '(1985)', '(1974)', '(2012)', '(2017)'] ['132 min', '108 min', '119 min', '131 min', '135 min', '161 min', '122 min', '113 min', '152 min', '135 min', '209 min', '109 min', '100 min', '137 min', '181 min', '175 min', '164 min', '142 min', '152 min', '153 min', '132 min', '125 min', '154 min', '148 min', '169 min', '130 min', '117min', '180 min', '149 min', '146 min', '136 min', '194 min', '118 min', '115 min', '152 min', '97 min', '145 min', '132 min', '178 min', '155 min', '144 min', '134 min', '162 min', '142 min', '130 min', '144 min', '97 min', '202 min', '165 min', '113 min'] [8.6, 8.0, 8.5, 8.0, 7.6, 7.7, 8.6, 8.1, 8.2, 8.0, 8.0, 7.7, 7.8, 8.0, 8.5, 9.2, 8.0, 9.3, 9.0, 8.3, 7.9, 7.6, 8.9, 8.8, 8.6, 8.2, 8.1, 8.2, 8.1,8.4, 8.7, 7.8, 8.6, 8.2, 7.6, 7.7, 8.1, 8.1, 8.8, 8.5, 8.0, 8.0, 7.6, 8.8, 7.9, 8.0, 7.9, 9.0, 8.4, 7.6] ['96 ', '58 ', '78 ', '82 ', '90 ', '83 ', '59 ', '51 ', '81 ', '91 ', '94 ', '83 ', '84 ', '93 ', '78 ', '100 ', '81 ', '80 ', '84 ', '69 ', '93 ', '75 ', '94 ', '74 ', '74 ', '69 ', '84 ', '75 ', '79 ', '66 ', '73 ', '75 ', '85 ', '88 ', '64 ', '70 ', '84 ', '82 ', '92 ', '67 ', '80 ', '49 ', '56 ', '82 ', '74 ', '80 ', '62 ', '90 ', '81 ', '86 '] ['282,699', '142,517', '199,638', '195,728', '108,330', '396,071', '695,224', '42,015', '152,661', '65,234', '249,950', '77,453', '160,180', '179,887', '673,115', '1,511,929', '414,992', '2,194,397', '2,176,865', '1,184,882', '178,688', '76,291', '1,724,518', '1,925,684', '1,378,968', '293,695', '656,442', '1,092,063', '799,696', '835,496', '1,580,250', '994,453', '1,191,182', '383,958', '595,613', '34,091', '92,492', '115,125', '1,572,354', '1,267,310', '715,623', '410,199', '479,811', '1,693,344', '535,065', '555,756', '330,308', '1,059,089', '1,271,569', '398,553'] ['-', '$0.35M', '-', '-', '-', '$135.37M', '$192.73M', '-', '-', '-', '-', '$0.43M', '$433.03M', '-', '$858.37M', '$134.97M', '$92.05M', '$28.34M', '$534.86M', '$120.54M', '$18.10M', '-', '$107.93M', '$292.58M', '$188.02M', '$85.08M', '$32.87M', '$116.90M', '$167.77M', '$44.02M', '$171.48M', '$659.33M', '$130.74M', '$54.51M', '$317.58M', '$13.12M', '$2.01M', '$0.01M', '$315.54M', '$187.71M', '$228.43M', '$216.43M', '$107.51M', '$330.25M', '$315.06M', '$167.45M', '$45.88M', '$57.30M', '$162.81M', '$107.83M'] dice que extraiga todos los dígitos de la cadena
    • El M El método convierte el resultado en un número entero.

    Ahora, si ejecutamos min en la parte inferior de nuestro programa para ver cómo se ven nuestros datos anuales, este es el resultado:

    Este es el título de la imagen

    Debería ver su lista de años sin paréntesis. Y el tipo de datos que se muestra ahora es un número entero. Nuestros datos anuales se limpian oficialmente.

    Datos de tiempo de limpieza

    Haremos exactamente lo que hicimos al limpiar nuestros datos de años anteriores a nuestros datos de tiempo al tomar solo los dígitos y convertir nuestro tipo de datos en un número entero.

    |_+_|

    Limpieza de datos de Metascore

    La única limpieza que debemos hacer aquí es convertir nuestro tipo de datos de objeto en un número entero:

    |_+_|

    Limpieza de votos

    Con los votos, necesitamos eliminar las comas y convertirlo en un tipo de datos entero:

    |_+_|

    Rompiendo los votos de limpieza en contra:

    • DataFrame son nuestros datos de votos en nuestras películas movies = pd.DataFrame({ 'movie': titles, 'year': years, 'timeMin': time, 'imdb': imdb_ratings, 'metascore': metascores, 'votes': votes, 'us_grossMillions': us_gross, }) . Estamos asignando nuestros nuevos datos limpiados a nuestros votos movies.
    • . DataFrame agarra la cadena y usa el pd.DataFrame método para reemplazar las comas con una cita vacía (nada)
    • El DataFrame El método convierte el resultado en un número entero.

    Limpieza de datos brutos

    Los datos brutos implican algunos obstáculos que superar. Lo que tenemos que hacer es eliminar el signo de dólar y el print s de los datos y convertirlo en un número de punto flotante. A continuación, le indicamos cómo hacerlo:

    |_+_|

    Desglose de la limpieza en bruto:

    Código de limpieza superior:

    • DataFrame son nuestros datos brutos en nuestras películas movies. Asignaremos nuestros nuevos datos limpiados a nuestro print(movies) columna.
    • print le dice a los pandas que vayan a la columna print(movies.dtypes) en nuestro year
    • El timeMin la función llama a la función especificada para cada elemento de un iterable
    • metascore es una función anónima en Python (una sin nombre). Las funciones normales se definen mediante votes palabra clave.
    • us_grossMillions son nuestros argumentos de función. Esto le dice a nuestra función que elimine el float del lado izquierdo y pele el cheese desde el lado derecho.

    Código de conversión inferior:

    • I ate 10 blocks of cheese está despojado de los elementos que no necesitamos, y ahora le asignaremos los datos del código de conversión para terminarlo
    • 10 es un método que podemos usar para cambiar esta columna a un flotante. La razón por la que usamos esto es porque tenemos muchos guiones en esta columna, y no podemos convertirla en un flotante usando I ate 10 blocks of cheese string - esto detectaría un error.
    • 10 transformará los valores no numéricos, nuestros guiones, en valores NaN (no un número) porque tenemos guiones en lugar de los datos que faltan

    Revise el código limpiado y convertido

    Veamos cómo lo hicimos. Ejecute el movies['year'] = movies['year'].str.extract('(d+)').astype(int) función para ver nuestros datos y los tipos de datos que tenemos:

    |_+_|

    El resultado de nuestros datos limpios

    Este es el título de la imagen

    El resultado de nuestros tipos de datos

    Este es el título de la imagen

    ¡Se ve bien!

    Código final terminado

    Aquí está el código final de su raspador web de una sola página:

    |_+_|

    Guardar sus datos en un CSV

    ¿De qué sirven nuestros datos extraídos si no podemos guardarlos para proyectos o análisis futuros? A continuación se muestra el código que puede agregar al final de su programa para guardar sus datos en un archivo CSV:

    |_+_|

    Desglosando el archivo CSV:

    • |_+_|

    Para que este código se ejecute correctamente, deberá crear un archivo vacío y nombrarlo como desee, asegurándose de que tenga la extensión movies[‘year’]. Llamé al mío year, como puede ver arriba, pero siéntase libre de nombrarlo como quiera. Solo asegúrese de cambiar el código anterior para que coincida.

    Si está en Repl, puede crear un archivo CSV vacío colocando el cursor cerca de Archivos y haciendo clic en la opción Agregar archivo. Nómbrelo y guárdelo con un DataFrame extensión. Luego, agregue el código al final de su programa:

    |_+_|

    Todos sus datos deberían aparecer en su CSV. Una vez que lo descargue en su computadora / lo abra, su archivo se verá así:

    Este es el título de la imagen

    Conclusión

    Hemos recorrido un largo camino desde solicitar el contenido HTML de nuestra página web hasta limpiar toda nuestra .str.extract(‘(d+’). Ahora debería saber cómo extraer páginas web con la misma estructura de URL y HTML que le mostré anteriormente. A continuación, se muestra un resumen de lo que hemos logrado:

    |_+_|

    Próximos pasos

    ¡Espero que te hayas divertido haciendo esto!

    Si desea aprovechar lo que ha aprendido, aquí tiene algunas ideas para probar:

    • Obtenga los datos de la película para las 1,000 películas en esa lista
    • Extraiga otros datos sobre cada película, por ejemplo, género, director, protagonista o el resumen de la película.
    • Encuentra un sitio web diferente para raspar que te interese

    En mi próximo artículo, explicaré cómo recorrer todas las páginas de esta lista de IMDb para capturar todas las 1,000 películas, lo que implicará algunas alteraciones en el código final que tenemos aquí.

    ¡Feliz codificación!

    # python # ciencia de datos # aprendizaje automático # programación






    .43M', '3.03M', '-', '8.37M', '4.97M', '.05M', '.34M', '4.86M', '0.54M', '.10M', '-', '7.93M', '2.58M', '8.02M', '.08M', '.87M', '6.90M', '7.77M', '.02M', '1.48M', '9.33M', '0.74M', '.51M', '7.58M', '.12M', '.01M', '

    Construyendo un Web Scraper con Python en 30 minutos

    Mis habilidades en Python son básicas, así que si estás aquí sin muchas habilidades en codificación, espero que esta guía te ayude a adquirir más conocimientos y comprensión.

    El proyecto perfecto para principiantes

    Para obtener datos para proyectos de ML, IA o ciencia de datos, a menudo dependerá de bases de datos, API o conjuntos de datos CSV listos para usar. Pero, ¿qué pasa si no puede encontrar un conjunto de datos que desee utilizar y analizar? Ahí es donde entra en juego un raspador web.

    Trabajar en proyectos es fundamental para consolidar los conocimientos adquiridos. Cuando comencé este proyecto, estaba un poco abrumado porque realmente no sabía nada.

    Seguir con él, encontrar respuestas a mis preguntas en Stack Overflow y muchas pruebas y errores me ayudaron a comprender realmente cómo funciona la programación: cómo funcionan las páginas web, cómo usar bucles y cómo crear funciones y mantener los datos limpios. Hace que la construcción de un raspador web sea el proyecto perfecto para principiantes para cualquiera que se esté iniciando en Python.

    Que cubriremos

    Esta guía lo guiará a través de la comprensión de las páginas web HTML, la creación de un raspador web con Python y la creación de un DataFrame con pandas. Cubrirá la calidad de los datos, la limpieza de datos y la conversión de tipos de datos, completamente paso a paso y con instrucciones, código y explicaciones sobre cómo funciona cada pieza. ¡Espero que codifiques y disfrutes!

    Descargo de responsabilidad

    Los sitios web pueden restringir o prohibir la extracción de datos de su sitio web. Los usuarios pueden estar sujetos a ramificaciones legales dependiendo de dónde y cómo intente recopilar información. Los sitios web suelen describir esto en sus términos de uso y en su robots.txt archivo encontrado en su sitio, que generalmente se parece a esto: [www.example.com/robots.txt](http://www.[site].com/robots.txt.). Así que raspe responsablemente y respete el robots.txt.

    ¿Qué es Web Scraping?

    Raspado web Consiste en recopilar datos disponibles en sitios web. Esto se puede hacer manualmente por un humano o usando un bot.

    A Bot es un programa creado por usted que le ayuda a extraer los datos que necesita mucho más rápido que la mano y los ojos de un ser humano.

    ¿Qué vamos a raspar?

    Es esencial identificar el objetivo de su raspado desde el principio. No queremos extraer ningún dato que en realidad no necesitemos.

    Para este proyecto, extraeremos datos de las 1,000 películas principales de IMDb, específicamente las 50 películas principales de esta página. Aquí está la información que recopilaremos de cada lista de películas:

    • El título
    • El año en que fue lanzado
    • Cuanto dura la pelicula
    • Calificación de IMDb de la película
    • El Metascore de la película
    • ¿Cuántos votos obtuvo la película?
    • Las ganancias brutas de la película en EE. UU.

    ¿Cómo funcionan los Web Scrapers?

    Los web scrapers recopilan datos del sitio web de la misma manera que lo haría un humano: van a una página web del sitio web, obtienen los datos relevantes y pasan a la siguiente página web, solo que mucho más rápido.

    Cada sitio web tiene una estructura diferente. Estas son algunas cosas importantes en las que pensar al crear un raspador web:

    • ¿Cuál es la estructura de la página web que contiene los datos que busca?
    • ¿Cómo llegamos a esas páginas web?
    • ¿Necesitará recopilar más datos de la página siguiente?

    La URL

    Para empezar, veamos la URL de la página que queremos raspar.

    Notamos algunas cosas sobre la URL:

    • ? actúa como un separador: indica el final de la ruta del recurso URL y el inicio de los parámetros
    • groups=top_1000 especifica de qué se tratará la página
    • &ref_adv_prv nos lleva a la página anterior o siguiente. La referencia es la página en la que estamos actualmente. adv_nxt y adv_prv hay dos valores posibles, traducidos a avanzar a la página siguiente y avanzar a la página anterior.

    Cuando navega hacia adelante y hacia atrás por las páginas, notará que solo cambian los parámetros. Tenga en cuenta esta estructura, ya que es útil saberlo mientras construimos el raspador.

    El HTML

    HTML significa Lenguaje de marcado de hipertexto, y la mayoría de las páginas web se escriben con él. Esencialmente, HTML es cómo dos computadoras se comunican entre sí a través de Internet, y los sitios web están qué ellos dicen.

    Cuando accede a una URL, su computadora envía una solicitud al servidor que aloja el sitio. Se puede ejecutar cualquier tecnología en ese servidor (JavaScript, Ruby, Java, etc.) para procesar su solicitud. Finalmente, el servidor devuelve una respuesta a su navegador; a menudo, esa respuesta será en forma de una página HTML para que la muestre su navegador.

    HTML describe la estructura de una página web de forma semántica y originalmente incluía señales para la apariencia del documento.

    Inspeccionar HTML

    Los usuarios de Chrome, Firefox y Safari pueden examinar la estructura HTML de cualquier página haciendo clic con el botón derecho del mouse y presionando la opción Inspeccionar.

    Este es el título de la imagen

    Aparecerá un menú en la parte inferior o en el lado derecho de su página con una lista larga de todas las etiquetas HTML que contienen la información que se muestra en la ventana de su navegador. Si estás en Safari (foto de arriba), querrás presionar el botón a la izquierda de la barra de búsqueda, que parece un objetivo. Si está en Chrome o Firefox, hay un pequeño cuadro con un ícono de flecha en la parte superior izquierda que usará para inspeccionar.

    Una vez que haga clic, si mueve el cursor sobre cualquier elemento de la página, notará que se resaltará junto con las etiquetas HTML en el menú con el que están asociados, como se ve arriba.

    Saber cómo leer la estructura básica de la página HTML de una página es importante para que podamos recurrir a Python para que nos ayude a extraer el HTML de la página.

    Instrumentos

    Las herramientas que vamos a utilizar son:

    • Responder (opcional) es un entorno de programación informática interactivo y sencillo que se utiliza a través de su navegador web. Recomiendo usar esto solo para propósitos de código si aún no tiene un IDE. Si usa Repl, asegúrese de estar usando el entorno Python.
    • Peticiones nos permitirá enviar solicitudes HTTP para obtener archivos HTML
    • Hermosa Sopa nos ayudará a analizar los archivos HTML
    • pandas nos ayudará a reunir los datos en un DataFrame para limpiarlo y analizarlo
    • NumPy agregará soporte para funciones matemáticas y herramientas para trabajar con matrices

    Ahora, codifiquemos

    Puede seguir a continuación dentro de su entorno Repl o IDE, o puede ir directamente a el código completo aquí . ¡Divertirse!

    Importar herramientas

    Primero, importaremos las herramientas que necesitaremos para que podamos usarlas para ayudarnos a construir el raspador y obtener los datos que necesitamos.

    |_+_|

    Películas en inglés

    Es muy probable que cuando ejecutemos nuestro código para extraer algunas de estas películas, obtengamos los nombres de las películas traducidos al idioma principal del país en el que se originó.

    Utilice este código para asegurarse de que obtengamos títulos traducidos al inglés de todas las películas que extraemos:

    |_+_|

    Solicitar contenido de la URL

    Obtenga el contenido de la página que estamos viendo solicitando la URL:

    |_+_|

    Desglose de las solicitudes de URL:

    • import requests from requests import get from bs4 import BeautifulSoup import pandas as pd import numpy as np es la variable que creamos y asignamos la URL a
    • headers = {'Accept-Language': 'en-US, en;q=0.5'} es la variable que creamos para almacenar nuestro url = 'https://www.imdb.com/search/title/?groups=top_1000&ref_=adv_prv' results = requests.get(url, headers=headers) acción
    • url es el método que usamos para capturar el contenido de la URL. El results parte le dice a nuestro raspador que nos traiga inglés, basado en nuestra línea de código anterior.

    Usando BeautifulSoup

    Haga que el contenido que tomamos sea fácil de leer usando request.get:

    |_+_|

    Rompiendo BeautifulSoup Down:

    • requests.get(url, headers=headers) es la variable que creamos para asignar el método headers to, que especifica un formato de resultados deseado utilizando el analizador HTML; esto permite que Python lea los componentes de la página en lugar de tratarla como una cadena larga
    • BeautifulSoup imprimirá lo que hemos tomado en un formato de árbol más estructurado, lo que facilitará su lectura.

    Los resultados de la impresión se verán más ordenados, así:

    |_+_|

    Rotura |_+_| abajo:

    Prepárate para extraer cada artículo

    Este es el título de la imagen

    ¡Nos están perdiendo los ingresos brutos! Si miras la segunda película, la han incluido allí.

    Este es el título de la imagen

    Algo a tener en cuenta siempre al crear un raspador web es la idea de que no toda la información que busca estará disponible para que la recopile.

    En estos casos, debemos asegurarnos de que nuestro raspador web no deje de funcionar o se rompa cuando llegue a los datos faltantes y construyamos en torno a la idea de que simplemente no sabemos si eso sucederá o no.

    Entrar en cada lister-item div

    Cuando tomamos cada uno de los elementos que necesitamos en un solo mode-advanced lister-item mode-advanced contenedor, necesitamos que el raspador pase al siguiente div lister-item mode-advanced contenedor y coge esos elementos de la película también. Y luego debe pasar a la siguiente y así sucesivamente, 50 veces para cada página. Para que esto se ejecute, tendremos que envolver nuestro raspador en un bucle for.

    |_+_|

    Rompiendo el |_+_| círculo:

    • Un bucle lister-item mode-advanced se utiliza para iterar sobre una secuencia. Nuestra secuencia es cada contenedor movie_div = soup.find_all('div', class_='lister-item mode-advanced') div que almacenamos en **find_all**
    • movie_div es el nombre de la variable que ingresa cada div. Puede nombrar esto como quiera (lister-item mode-advanced, find_all(), div, class), y no cambiará la función del bucle.

    Se puede leer así:

    |_+_|

    Extrae el título de la película.

    Comenzando con el nombre de la película, busquemos su línea HTML correspondiente usando inspeccionar y haciendo clic en el título.

    Este es el título de la imagen

    Vemos que el nombre está contenido dentro de una etiqueta de anclaje, lister-item mode-advanced. El lister-item mode-advanced etiqueta. Este `` es el tercero de los lister-item mode-advanced s anidados en el contenedor de la primera película.

    |_+_|

    Desglosando títulos:

    • div es la variable que usaremos para almacenar los datos del título que encontremos
    • lister-item mode-advanced es lo que se usa en nuestro bucle for; se usa para iterar cada vez
    • div y #initiate the for loop #this tells your scraper to iterate through #every div container we stored in move_div for container in movie_div: es notación de atributo y le dice al raspador que acceda a cada una de esas etiquetas
    • **for** le dice al raspador que tome el texto anidado en la etiqueta ``
    • for le dice al raspador que tome lo que encontramos y almacenamos en lister-item mode-advanced y agregarlo a nuestra lista vacía llamada movie_div, que creamos al principio

    Extraer año de lanzamiento

    Busquemos el año de la película y su línea HTML correspondiente usando inspeccionar y haciendo clic en el año.

    Este es el título de la imagen

    Vemos que estos datos se almacenan dentro de container etiqueta que contiene el título de la película. La notación de puntos, que usamos para encontrar los datos del título (div), funcionó porque era la primera x La etiqueta que queremos es la segunda etiqueta, tenemos que usar un método diferente.

    En cambio, podemos decirle a nuestro raspador que busque por la marca distintiva del segundo ''. Usaremos el loop método , que es similar a banana excepto que solo devuelve la primera coincidencia.

    |_+_|

    Desglosando años:

    • cheese es la variable que usaremos para almacenar los datos del año que encontremos
    • for in : OR in our case... for each lister-item mode-advanced div container: scrape these elements es lo que usamos en nuestro . This tag is nested within a header tag, bucle: se usa para iterar cada vez
    • tag is nested within a es la notación de atributo, que le dice al raspador que acceda a esa etiqueta
    • div es un método que usaremos para acceder a esta `` etiqueta
    • name = container.h3.a.text titles.append(name) es la etiqueta distintiva que queremos
    • name le dice al raspador que tome lo que encontramos y almacenamos en container y agregarlo a nuestra lista vacía llamada .h3 (que creamos al principio)

    Extraer la duración de la película

    Busque la duración de la película y su línea HTML correspondiente utilizando inspeccionar y haciendo clic en el total de minutos.

    Este es el título de la imagen

    Los datos que necesitamos se pueden encontrar en una etiqueta con una clase de .a. Como hicimos con el año, podemos hacer algo similar:

    |_+_|

    Rompiendo el tiempo:

    • .text es la variable que usaremos para almacenar los datos de tiempo que encontremos
    • titles.append(name) es lo que usamos en nuestro name bucle: se usa para iterar cada vez
    • titles es un método que usaremos para acceder a esta `` etiqueta
    • tag below the es la etiqueta distintiva que queremos
    • .h3.a dice que si hay datos allí, consígalos, pero si faltan datos, coloque un guión allí
    • tag after the `h3` tag. Since the le dice al raspador que tome ese texto en la etiqueta ``
    • find() le dice al raspador que tome lo que encontramos y almacenamos en find_all() y agregarlo a nuestra lista vacía llamada year = container.h3.find('span', class_='lister-item-year').text years.append(year) (que creamos al principio)

    Extraer calificaciones de IMDb

    Busque la calificación de IMDb de la película y su línea HTML correspondiente utilizando inspeccionar y haciendo clic en la calificación de IMDb.

    Este es el título de la imagen

    Ahora, nos centraremos en extraer la calificación de IMDb. Los datos que necesitamos se pueden encontrar en un year etiqueta. Como no veo ningún otro container etiquetas, podemos usar la notación de atributos (notación de puntos) para capturar estos datos.

    |_+_|

    Desglosando las calificaciones de IMDb:

    • for es la variable que usaremos para almacenar los datos de calificaciones de IMDB que encuentre
    • .h3 es lo que usamos en nuestro .find() bucle: se usa para iterar cada vez
    • (‘span’, class_ = ‘lister-item-year’) es una notación de atributo que le dice al raspador que acceda a esa etiqueta
    • years.append(year) le dice al raspador que tome ese texto
    • El year El método convierte el texto que encontramos en un flotante, que es un decimal
    • years le dice al raspador que tome lo que encontramos y almacenamos en runtime y agregarlo a nuestra lista vacía llamada runtime = container.find('span', class_='runtime').text if container.p.find('span', class_='runtime') else '' time.append(runtime) (que creamos al principio)

    Extraer Metascore

    Busque la calificación de Metascore de la película y su línea HTML correspondiente utilizando inspeccionar y haciendo clic en el número de Metascore.

    Este es el título de la imagen

    Los datos que necesitamos se pueden encontrar en una etiqueta `` que tiene una clase que dice runtime.

    Antes de decidirnos por eso, debe notar que, por supuesto, un 96 para Parasite muestra una calificación favorable, pero ¿son favorables los demás? Si resaltas el Metascore de la siguiente película, verás que JoJo Rabbit tiene una clase que dice container. Dado que estas etiquetas son diferentes, sería seguro decirle al raspador que use solo la clase for al raspar:

    |_+_|

    Desglosando Metascores:

    • .find() es la variable que usaremos para almacenar los datos de calificación de Metascore que encuentre
    • (‘span’, class_ = ‘runtime’) es lo que usamos en nuestro if container.p.find(‘span’, class_=’runtime’) else ‘-’ bucle: se usa para iterar cada vez
    • .text es un método que usaremos para acceder a esta `` etiqueta
    • time.append(runtime) es la etiqueta distintiva que queremos
    • runtime le dice al raspador que tome ese texto
    • time dice que si hay datos allí, consígalos, pero si faltan datos, coloque un guión allí
    • El ** El método convierte el texto que encontramos en un número entero.
    • ** le dice al raspador que tome lo que encontramos y almacenamos en imdb = float(container.strong.text) imdb_ratings.append(imdb) y agregarlo a nuestra lista vacía llamada imdb (que creamos al principio)

    Extraer votos e ingresos brutos

    Finalmente llegamos a los dos últimos elementos que necesitamos extraer, pero dejamos los más difíciles para el final.

    Aquí es donde las cosas se ponen un poco complicadas. Como se mencionó anteriormente, debería haber notado que cuando miramos la primera película de esta lista, no vemos un número de ingresos brutos. Cuando miramos la segunda película de la lista, podemos ver ambas.

    Echemos un vistazo al código HTML de la segunda película y partamos de ahí.

    Este es el título de la imagen

    Tanto los votos como los brutos están resaltados a la derecha. Después de mirar los votos y los contenedores brutos para la película # 2, ¿qué notas?

    Como puede ver, ambos están en una etiqueta `` que tiene un container atributo que es igual a for y un .strong atributo que contiene los valores del número distintivo que necesitamos para cada uno.

    ¿Cómo podemos obtener los datos del segundo si los parámetros de búsqueda del primero son los mismos? ¿Cómo le decimos a nuestro raspador que se salte el primero y raspe el segundo?

    Este requirió mucho esfuerzo mental, toneladas de café y un par de noches para descubrirlo. Así es como lo hice:

    |_+_|

    Rompiendo votos y brutos abajo:

    • .text es una variable completamente nueva que usaremos para almacenar tanto los votos como las etiquetas `` brutas ''
    • float() es lo que usamos en nuestro imdb_ratings.append(imdb) bucle para iterar cada vez
    • imdb es el método que usaremos para obtener las dos `` etiquetas
    • imdb_ratings es cómo podemos tomar los atributos de esa etiqueta específica.
    • metascore favorable es la variable que usaremos para almacenar los votos que encontremos en el metascore mixed etiqueta
    • metascore le dice al raspador que entre en m_score = container.find('span', class_='metascore').text if container.find('span', class_='metascore') else '-' metascores.append(m_score) etiqueta y toma los primeros datos de la lista, que son los votos porque m_score viene primero en nuestro código HTML (las computadoras cuentan en binario; comienzan a contar en 0, no en 1)
    • container le dice al raspador que tome ese texto
    • for le dice al raspador que tome lo que encontramos y almacenamos en .find() y agregarlo a nuestra lista vacía llamada (‘span’, class_ = ‘metascore’) (que creamos al principio)
    • .text es la variable que usaremos para almacenar el bruto que encontremos en if container.find(‘span’, class_=’metascore’) else ‘-’ etiqueta
    • int() le dice al raspador que entre en metascores.append(m_score) etiqueta y tome el segundo dato de la lista, que es m_score porque metascores ocupa el segundo lugar en nuestro código HTML
    • name dice si la longitud de nv es mayor que uno, luego busque el segundo dato almacenado. Pero si los datos almacenados en data-value no es mayor que uno, es decir, si falta el valor bruto, coloque un guión allí
    • nv = container.find_all('span', attrs={'name': 'nv'}) vote = nv[0].text votes.append(vote) grosses = nv[1].text if len(nv) > 1 else '-' us_gross.append(grosses) le dice al raspador que tome lo que encontramos y almacenamos en nv y agregarlo a nuestra lista vacía llamada container (que creamos al principio)

    Su código ahora debería verse así:

    |_+_|

    Veamos lo que tenemos hasta ahora

    Ahora que le hemos dicho a nuestro raspador qué elementos raspar, usemos el for función para imprimir cada lista a la que hemos enviado nuestros datos extraídos:

    |_+_|

    Nuestras listas se ven así

    |_+_|

    Hasta ahora todo va bien, pero todavía no hemos llegado a ese punto. Necesitamos limpiar un poco nuestros datos. Parece que tenemos algunos elementos no deseados en nuestros datos: signos de dólar, find_all() s, (‘span’, attrs = ‘name’ : ’nv’) s, comas, paréntesis y espacio en blanco adicional en los Metascores.

    Construyendo un DataFrame con pandas

    El siguiente orden del día es construir un vote con pandas para almacenar los datos que tenemos muy bien en una tabla para comprender realmente lo que está sucediendo.

    Así es como lo hacemos:

    |_+_|

    Desglosando nuestro marco de datos:

    • nv es lo que llamaremos nuestro nv[0]
    • nv así es como inicializamos la creación de un votes con pandas
    • Las claves de la izquierda son los nombres de las columnas.
    • Los valores de la derecha son nuestras listas de datos que hemos extraído

    Ver nuestro DataFrame

    Podemos ver cómo se ve todo simplemente usando el .text función en nuestro votes.append(vote) —Que llamamos vote —Al final de nuestro programa:

    |_+_|

    Nuestro DataFrame de pandas se ve así

    Este es el título de la imagen

    Calidad de los datos

    Antes de embarcarse en proyectos como este, debe saber cuáles son sus criterios de calidad de datos, es decir, qué reglas o restricciones deben seguir sus datos. Aquí hay unos ejemplos:

    • Restricciones de tipo de datos: Los valores en sus columnas deben ser de un tipo de datos particular: numérico, booleano, fecha, etc.
    • Restricciones obligatorias : Algunas columnas no pueden estar vacías
    • Patrones de expresión regular: T campos ext que tienen que estar en un patrón determinado, como números de teléfono

    ¿Qué es la limpieza de datos?

    Limpieza de datos es el proceso de detección y corrección o eliminación de registros corruptos o inexactos de su conjunto de datos.

    Al realizar un análisis de datos, también es importante asegurarse de que estamos usando los tipos de datos correctos.

    Comprobación de tipos de datos

    Podemos comprobar cómo se ven nuestros tipos de datos ejecutando esto votes función en la parte inferior de nuestro programa:

    |_+_|

    Resultados de nuestro tipo de datos

    Este es el título de la imagen

    Analicemos esto: nuestro tipo de datos de películas es un objeto, que es lo mismo que una cadena, lo cual sería correcto considerando que son títulos de películas. Nuestra puntuación de IMDb también es correcta porque tenemos números de punto flotante en esta columna (números decimales).

    Pero nuestros grosses, nv, nv[1] y nv muestran que son objetos cuando deberían ser tipos de datos enteros, y nuestro gross es un objeto en lugar de un gross tipo de datos. ¿Cómo pasó esto?

    Inicialmente, cuando le decíamos a nuestro raspador que tomara estos valores de cada contenedor HTML, le decíamos que tomara valores específicos de una cadena. Una cadena representa texto en lugar de números; se compone de un conjunto de caracteres que pueden además contienen números.

    Por ejemplo, la palabra nv[1].text if len(nv) > 1 else ‘-’ y la frase nv son ambas cadenas. Si tuviéramos que deshacernos de todo excepto de nv de us_gross.append(grosses), sigue siendo una cadena, pero ahora es una que solo dice grosses.

    Limpieza de datos con pandas

    Ahora que tenemos una idea clara de cómo se ven nuestros datos en este momento, es hora de comenzar a limpiarlos.

    Esta puede ser una tarea tediosa, pero es muy importante.

    Datos del año de limpieza

    Para eliminar los paréntesis de nuestros datos anuales y convertir el objeto en un tipo de datos enteros, haremos lo siguiente:

    |_+_|

    Desglose de los datos del año de limpieza:

    • us_grosses le dice a los pandas que vayan a la columna import requests from requests import get from bs4 import BeautifulSoup import pandas as pd import numpy as np url = 'https://www.imdb.com/search/title/?groups=top_1000&ref_=adv_prv' headers = {'Accept-Language': 'en-US, en;q=0.5'} results = requests.get(url, headers=headers) soup = BeautifulSoup(results.text, 'html.parser') titles = [] years = [] time = [] imdb_ratings = [] metascores = [] votes = [] us_gross = [] movie_div = soup.find_all('div', class_='lister-item mode-advanced') for container in movie_div: #Name name = container.h3.a.text titles.append(name) #year year = container.h3.find('span', class_='lister-item-year').text years.append(year) #time runtime = container.p.find('span', class_='runtime').text if container.p.find('span', class_='runtime').text else '-' time.append(runtime) #IMDb rating imdb = float(container.strong.text) imdb_ratings.append(imdb) #metascore m_score = container.find('span', class_='metascore').text if container.find('span', class_='metascore') else '-' metascores.append(m_score) #here are two NV containers, grab both of them as they hold both the votes and the grosses nv = container.find_all('span', attrs={'name': 'nv'}) #filter nv for votes vote = nv[0].text votes.append(vote) #filter nv for gross grosses = nv[1].text if len(nv) > 1 else '-' us_gross.append(grosses) en nuestro print
    • print(titles) print(years) print(time) print(imdb_ratings) print(metascores) print(votes) print(us_gross) este método: ['Parasite', 'Jojo Rabbit', '1917', 'Knives Out', 'Uncut Gems', 'Once Upon a Time... in Hollywood', 'Joker', 'The Gentlemen', 'Ford v Ferrari', 'Little Women', 'The Irishman', 'The Lighthouse', 'Toy Story 4', 'Marriage Story', 'Avengers: Endgame', 'The Godfather', 'Blade Runner 2049', 'The Shawshank Redemption', 'The Dark Knight', 'Inglourious Basterds', 'Call Me by Your Name', 'The Two Popes', 'Pulp Fiction', 'Inception', 'Interstellar', 'Green Book', 'Blade Runner', 'The Wolf of Wall Street', 'Gone Girl', 'The Shining', 'The Matrix', 'Titanic', 'The Silence of the Lambs', 'Three Billboards Outside Ebbing, Missouri', 'Harry Potter and the Sorcerer's Stone', 'The Peanut Butter Falcon', 'The Handmaiden', 'Memories of Murder', 'The Lord of the Rings: The Fellowship of the Ring', 'Gladiator', 'The Martian', 'Bohemian Rhapsody', 'Watchmen', 'Forrest Gump', 'Thor: Ragnarok', 'Casino Royale', 'The Breakfast Club', 'The Godfather: Part II', 'Django Unchained', 'Baby Driver'] ['(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(2019)', '(I) (2019)', '(2019)', '(2019)', '(2019)', '(1972)', '(2017)', '(1994)', '(2008)', '(2009)', '(2017)', '(2019)', '(1994)', '(2010)', '(2014)', '(2018)', '(1982)', '(2013)', '(2014)', '(1980)', '(1999)', '(1997)', '(1991)', '(2017)', '(2001)', '(2019)', '(2016)', '(2003)', '(2001)', '(2000)', '(2015)', '(2018)', '(2009)', '(1994)', '(2017)', '(2006)', '(1985)', '(1974)', '(2012)', '(2017)'] ['132 min', '108 min', '119 min', '131 min', '135 min', '161 min', '122 min', '113 min', '152 min', '135 min', '209 min', '109 min', '100 min', '137 min', '181 min', '175 min', '164 min', '142 min', '152 min', '153 min', '132 min', '125 min', '154 min', '148 min', '169 min', '130 min', '117min', '180 min', '149 min', '146 min', '136 min', '194 min', '118 min', '115 min', '152 min', '97 min', '145 min', '132 min', '178 min', '155 min', '144 min', '134 min', '162 min', '142 min', '130 min', '144 min', '97 min', '202 min', '165 min', '113 min'] [8.6, 8.0, 8.5, 8.0, 7.6, 7.7, 8.6, 8.1, 8.2, 8.0, 8.0, 7.7, 7.8, 8.0, 8.5, 9.2, 8.0, 9.3, 9.0, 8.3, 7.9, 7.6, 8.9, 8.8, 8.6, 8.2, 8.1, 8.2, 8.1,8.4, 8.7, 7.8, 8.6, 8.2, 7.6, 7.7, 8.1, 8.1, 8.8, 8.5, 8.0, 8.0, 7.6, 8.8, 7.9, 8.0, 7.9, 9.0, 8.4, 7.6] ['96 ', '58 ', '78 ', '82 ', '90 ', '83 ', '59 ', '51 ', '81 ', '91 ', '94 ', '83 ', '84 ', '93 ', '78 ', '100 ', '81 ', '80 ', '84 ', '69 ', '93 ', '75 ', '94 ', '74 ', '74 ', '69 ', '84 ', '75 ', '79 ', '66 ', '73 ', '75 ', '85 ', '88 ', '64 ', '70 ', '84 ', '82 ', '92 ', '67 ', '80 ', '49 ', '56 ', '82 ', '74 ', '80 ', '62 ', '90 ', '81 ', '86 '] ['282,699', '142,517', '199,638', '195,728', '108,330', '396,071', '695,224', '42,015', '152,661', '65,234', '249,950', '77,453', '160,180', '179,887', '673,115', '1,511,929', '414,992', '2,194,397', '2,176,865', '1,184,882', '178,688', '76,291', '1,724,518', '1,925,684', '1,378,968', '293,695', '656,442', '1,092,063', '799,696', '835,496', '1,580,250', '994,453', '1,191,182', '383,958', '595,613', '34,091', '92,492', '115,125', '1,572,354', '1,267,310', '715,623', '410,199', '479,811', '1,693,344', '535,065', '555,756', '330,308', '1,059,089', '1,271,569', '398,553'] ['-', '$0.35M', '-', '-', '-', '$135.37M', '$192.73M', '-', '-', '-', '-', '$0.43M', '$433.03M', '-', '$858.37M', '$134.97M', '$92.05M', '$28.34M', '$534.86M', '$120.54M', '$18.10M', '-', '$107.93M', '$292.58M', '$188.02M', '$85.08M', '$32.87M', '$116.90M', '$167.77M', '$44.02M', '$171.48M', '$659.33M', '$130.74M', '$54.51M', '$317.58M', '$13.12M', '$2.01M', '$0.01M', '$315.54M', '$187.71M', '$228.43M', '$216.43M', '$107.51M', '$330.25M', '$315.06M', '$167.45M', '$45.88M', '$57.30M', '$162.81M', '$107.83M'] dice que extraiga todos los dígitos de la cadena
    • El M El método convierte el resultado en un número entero.

    Ahora, si ejecutamos min en la parte inferior de nuestro programa para ver cómo se ven nuestros datos anuales, este es el resultado:

    Este es el título de la imagen

    Debería ver su lista de años sin paréntesis. Y el tipo de datos que se muestra ahora es un número entero. Nuestros datos anuales se limpian oficialmente.

    Datos de tiempo de limpieza

    Haremos exactamente lo que hicimos al limpiar nuestros datos de años anteriores a nuestros datos de tiempo al tomar solo los dígitos y convertir nuestro tipo de datos en un número entero.

    |_+_|

    Limpieza de datos de Metascore

    La única limpieza que debemos hacer aquí es convertir nuestro tipo de datos de objeto en un número entero:

    |_+_|

    Limpieza de votos

    Con los votos, necesitamos eliminar las comas y convertirlo en un tipo de datos entero:

    |_+_|

    Rompiendo los votos de limpieza en contra:

    • DataFrame son nuestros datos de votos en nuestras películas movies = pd.DataFrame({ 'movie': titles, 'year': years, 'timeMin': time, 'imdb': imdb_ratings, 'metascore': metascores, 'votes': votes, 'us_grossMillions': us_gross, }) . Estamos asignando nuestros nuevos datos limpiados a nuestros votos movies.
    • . DataFrame agarra la cadena y usa el pd.DataFrame método para reemplazar las comas con una cita vacía (nada)
    • El DataFrame El método convierte el resultado en un número entero.

    Limpieza de datos brutos

    Los datos brutos implican algunos obstáculos que superar. Lo que tenemos que hacer es eliminar el signo de dólar y el print s de los datos y convertirlo en un número de punto flotante. A continuación, le indicamos cómo hacerlo:

    |_+_|

    Desglose de la limpieza en bruto:

    Código de limpieza superior:

    • DataFrame son nuestros datos brutos en nuestras películas movies. Asignaremos nuestros nuevos datos limpiados a nuestro print(movies) columna.
    • print le dice a los pandas que vayan a la columna print(movies.dtypes) en nuestro year
    • El timeMin la función llama a la función especificada para cada elemento de un iterable
    • metascore es una función anónima en Python (una sin nombre). Las funciones normales se definen mediante votes palabra clave.
    • us_grossMillions son nuestros argumentos de función. Esto le dice a nuestra función que elimine el float del lado izquierdo y pele el cheese desde el lado derecho.

    Código de conversión inferior:

    • I ate 10 blocks of cheese está despojado de los elementos que no necesitamos, y ahora le asignaremos los datos del código de conversión para terminarlo
    • 10 es un método que podemos usar para cambiar esta columna a un flotante. La razón por la que usamos esto es porque tenemos muchos guiones en esta columna, y no podemos convertirla en un flotante usando I ate 10 blocks of cheese string - esto detectaría un error.
    • 10 transformará los valores no numéricos, nuestros guiones, en valores NaN (no un número) porque tenemos guiones en lugar de los datos que faltan

    Revise el código limpiado y convertido

    Veamos cómo lo hicimos. Ejecute el movies['year'] = movies['year'].str.extract('(d+)').astype(int) función para ver nuestros datos y los tipos de datos que tenemos:

    |_+_|

    El resultado de nuestros datos limpios

    Este es el título de la imagen

    El resultado de nuestros tipos de datos

    Este es el título de la imagen

    ¡Se ve bien!

    Código final terminado

    Aquí está el código final de su raspador web de una sola página:

    |_+_|

    Guardar sus datos en un CSV

    ¿De qué sirven nuestros datos extraídos si no podemos guardarlos para proyectos o análisis futuros? A continuación se muestra el código que puede agregar al final de su programa para guardar sus datos en un archivo CSV:

    |_+_|

    Desglosando el archivo CSV:

    • |_+_|

    Para que este código se ejecute correctamente, deberá crear un archivo vacío y nombrarlo como desee, asegurándose de que tenga la extensión movies[‘year’]. Llamé al mío year, como puede ver arriba, pero siéntase libre de nombrarlo como quiera. Solo asegúrese de cambiar el código anterior para que coincida.

    Si está en Repl, puede crear un archivo CSV vacío colocando el cursor cerca de Archivos y haciendo clic en la opción Agregar archivo. Nómbrelo y guárdelo con un DataFrame extensión. Luego, agregue el código al final de su programa:

    |_+_|

    Todos sus datos deberían aparecer en su CSV. Una vez que lo descargue en su computadora / lo abra, su archivo se verá así:

    Este es el título de la imagen

    Conclusión

    Hemos recorrido un largo camino desde solicitar el contenido HTML de nuestra página web hasta limpiar toda nuestra .str.extract(‘(d+’). Ahora debería saber cómo extraer páginas web con la misma estructura de URL y HTML que le mostré anteriormente. A continuación, se muestra un resumen de lo que hemos logrado:

    |_+_|

    Próximos pasos

    ¡Espero que te hayas divertido haciendo esto!

    Si desea aprovechar lo que ha aprendido, aquí tiene algunas ideas para probar:

    • Obtenga los datos de la película para las 1,000 películas en esa lista
    • Extraiga otros datos sobre cada película, por ejemplo, género, director, protagonista o el resumen de la película.
    • Encuentra un sitio web diferente para raspar que te interese

    En mi próximo artículo, explicaré cómo recorrer todas las páginas de esta lista de IMDb para capturar todas las 1,000 películas, lo que implicará algunas alteraciones en el código final que tenemos aquí.

    ¡Feliz codificación!

    # python # ciencia de datos # aprendizaje automático # programación






    .01M', '5.54M', '7.71M', '8.43M', '6.43M', '7.51M', '0.25M', '5.06M', '7.45M', '.88M', '.30M', '2.81M', '7.83M']
    dice que extraiga todos los dígitos de la cadena
  • El M El método convierte el resultado en un número entero.

Ahora, si ejecutamos min en la parte inferior de nuestro programa para ver cómo se ven nuestros datos anuales, este es el resultado:

Este es el título de la imagen

Debería ver su lista de años sin paréntesis. Y el tipo de datos que se muestra ahora es un número entero. Nuestros datos anuales se limpian oficialmente.

Datos de tiempo de limpieza

Haremos exactamente lo que hicimos al limpiar nuestros datos de años anteriores a nuestros datos de tiempo al tomar solo los dígitos y convertir nuestro tipo de datos en un número entero.

|_+_|

Limpieza de datos de Metascore

La única limpieza que debemos hacer aquí es convertir nuestro tipo de datos de objeto en un número entero:

|_+_|

Limpieza de votos

Con los votos, necesitamos eliminar las comas y convertirlo en un tipo de datos entero:

|_+_|

Rompiendo los votos de limpieza en contra:

  • DataFrame son nuestros datos de votos en nuestras películas movies = pd.DataFrame({ 'movie': titles, 'year': years, 'timeMin': time, 'imdb': imdb_ratings, 'metascore': metascores, 'votes': votes, 'us_grossMillions': us_gross, }) . Estamos asignando nuestros nuevos datos limpiados a nuestros votos movies.
  • . DataFrame agarra la cadena y usa el pd.DataFrame método para reemplazar las comas con una cita vacía (nada)
  • El DataFrame El método convierte el resultado en un número entero.

Limpieza de datos brutos

Los datos brutos implican algunos obstáculos que superar. Lo que tenemos que hacer es eliminar el signo de dólar y el print s de los datos y convertirlo en un número de punto flotante. A continuación, le indicamos cómo hacerlo:

|_+_|

Desglose de la limpieza en bruto:

Código de limpieza superior:

  • DataFrame son nuestros datos brutos en nuestras películas movies. Asignaremos nuestros nuevos datos limpiados a nuestro print(movies) columna.
  • print le dice a los pandas que vayan a la columna print(movies.dtypes) en nuestro year
  • El timeMin la función llama a la función especificada para cada elemento de un iterable
  • metascore es una función anónima en Python (una sin nombre). Las funciones normales se definen mediante votes palabra clave.
  • us_grossMillions son nuestros argumentos de función. Esto le dice a nuestra función que elimine el float del lado izquierdo y pele el cheese desde el lado derecho.

Código de conversión inferior:

  • I ate 10 blocks of cheese está despojado de los elementos que no necesitamos, y ahora le asignaremos los datos del código de conversión para terminarlo
  • 10 es un método que podemos usar para cambiar esta columna a un flotante. La razón por la que usamos esto es porque tenemos muchos guiones en esta columna, y no podemos convertirla en un flotante usando I ate 10 blocks of cheese string - esto detectaría un error.
  • 10 transformará los valores no numéricos, nuestros guiones, en valores NaN (no un número) porque tenemos guiones en lugar de los datos que faltan

Revise el código limpiado y convertido

Veamos cómo lo hicimos. Ejecute el movies['year'] = movies['year'].str.extract('(d+)').astype(int) función para ver nuestros datos y los tipos de datos que tenemos:

|_+_|

El resultado de nuestros datos limpios

Este es el título de la imagen

El resultado de nuestros tipos de datos

Este es el título de la imagen

¡Se ve bien!

Código final terminado

Aquí está el código final de su raspador web de una sola página:

|_+_|

Guardar sus datos en un CSV

¿De qué sirven nuestros datos extraídos si no podemos guardarlos para proyectos o análisis futuros? A continuación se muestra el código que puede agregar al final de su programa para guardar sus datos en un archivo CSV:

|_+_|

Desglosando el archivo CSV:

  • |_+_|

Para que este código se ejecute correctamente, deberá crear un archivo vacío y nombrarlo como desee, asegurándose de que tenga la extensión movies[‘year’]. Llamé al mío year, como puede ver arriba, pero siéntase libre de nombrarlo como quiera. Solo asegúrese de cambiar el código anterior para que coincida.

crear un sitio web de cartera con reaccionar

Si está en Repl, puede crear un archivo CSV vacío colocando el cursor cerca de Archivos y haciendo clic en la opción Agregar archivo. Nómbrelo y guárdelo con un DataFrame extensión. Luego, agregue el código al final de su programa:

|_+_|

Todos sus datos deberían aparecer en su CSV. Una vez que lo descargue en su computadora / lo abra, su archivo se verá así:

Este es el título de la imagen

Conclusión

Hemos recorrido un largo camino desde solicitar el contenido HTML de nuestra página web hasta limpiar toda nuestra .str.extract(‘(d+’). Ahora debería saber cómo extraer páginas web con la misma estructura de URL y HTML que le mostré anteriormente. A continuación, se muestra un resumen de lo que hemos logrado:

|_+_|

Próximos pasos

¡Espero que te hayas divertido haciendo esto!

Si desea aprovechar lo que ha aprendido, aquí tiene algunas ideas para probar:

  • Obtenga los datos de la película para las 1,000 películas en esa lista
  • Extraiga otros datos sobre cada película, por ejemplo, género, director, protagonista o el resumen de la película.
  • Encuentra un sitio web diferente para raspar que te interese

En mi próximo artículo, explicaré cómo recorrer todas las páginas de esta lista de IMDb para capturar todas las 1,000 películas, lo que implicará algunas alteraciones en el código final que tenemos aquí.

¡Feliz codificación!

# python # ciencia de datos # aprendizaje automático # programación