paint-brush
Cómo construir un Web Scraper con Python [Guía paso a paso]por@angelica-dietzel
40,953 lecturas
40,953 lecturas

Cómo construir un Web Scraper con Python [Guía paso a paso]

por Angelica Dietzel20m2020/03/04
Read on Terminal Reader
Read this story w/o Javascript

Demasiado Largo; Para Leer

Cómo construir un Web Scraper con Python [Guía paso a paso] La guía lo guiará a través de la comprensión de las páginas web HTML, la construcción de un Web Scraper 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 parte. No queremos raspar ningún dato que en realidad no necesitemos.

People Mentioned

Mention Thumbnail

Companies Mentioned

Mention Thumbnail
Mention Thumbnail

Coin Mentioned

Mention Thumbnail
featured image - Cómo construir un Web Scraper con Python [Guía paso a paso]
Angelica Dietzel HackerNoon profile picture

En mi viaje de programación autodidacta , mis intereses se encuentran en el aprendizaje automático (ML) y la inteligencia artificial (IA), y el lenguaje que elegí dominar es Python.

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 obtener más conocimiento 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é sucede si no puede encontrar un conjunto de datos que desea usar y analizar? Ahí es donde entra en juego un web scraper.

Trabajar en proyectos es crucial para solidificar el conocimiento que obtienes. Cuando comencé este proyecto, estaba un poco abrumado porque realmente no sabía nada.

Cumplir con eso, encontrar respuestas a mis preguntas sobre 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 comience en Python.

lo 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 web scraper 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 parte. ¡Espero que codifiques y disfrutes!

Descargo de responsabilidad

Los sitios web pueden restringir o prohibir el raspado de datos de su sitio web. Los usuarios pueden estar sujetos a ramificaciones legales dependiendo de dónde y cómo intente obtener información. Los sitios web generalmente describen esto en sus términos de uso y en su archivo robots.txt que se encuentra en su sitio, que generalmente se parece a esto: www.example.com/robots.txt . Así que raspe de manera responsable y respete el archivo robots.txt.

¿Qué es Web Scraping?

El web scraping consiste en recopilar datos disponibles en sitios web. Esto se puede hacer manualmente por un ser humano o mediante el uso de un bot.

Un bot es un programa que creas que te ayuda a extraer los datos que necesitas mucho más rápido de lo que pueden hacerlo 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 raspar ningún dato que en realidad no necesitemos.

Para este proyecto, recopilaremos datos de las "1000 mejores" películas de IMDb , específicamente las 50 mejores películas 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
  • Clasificación de IMDb de la película
  • El Metascore de la película
  • cuantos votos obtuvo la pelicula
  • Las ganancias brutas de la película en EE. UU.

¿Cómo funcionan los raspadores web?

Los rastreadores web recopilan datos del sitio web de la misma manera que lo haría un ser 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 a tener en cuenta al construir un raspador web:

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

la dirección URL

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

Esto es lo que vemos en la URL:

Notamos algunas cosas sobre la URL:

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

Cuando navegue de un lado a otro por las páginas, notará que solo cambian los parámetros. Tenga en cuenta esta estructura, ya que es útil conocerla 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 la forma en que dos computadoras se comunican entre sí a través de Internet, y los sitios web son lo que dicen.

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

HTML describe la estructura de una página web semánticamente y originalmente incluía pistas 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.

Aparecerá un menú en la parte inferior o en el lado derecho de su página con una larga lista 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 haya hecho clic, si mueve el cursor sobre cualquier elemento de la página, notará que se resaltará junto con las etiquetas HTML en el menú al que están asociadas, 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 ayudarnos a extraer el HTML de la página.

Instrumentos

Las herramientas que vamos a utilizar son:

  • Reemplazo   (opcional)   es un entorno de programación de computadora simple e interactivo que se utiliza a través de su navegador web. Recomiendo usar esto solo para fines de código si aún no tiene un IDE. Si usa Repl, asegúrese de estar usando el entorno de Python.
  • Las solicitudes nos permitirán enviar solicitudes HTTP para obtener archivos HTML
  • HermosaSopa   nos ayudará a analizar los archivos HTML
  • pandas nos ayudará a ensamblar los datos en un DataFrame para limpiarlos y analizarlos
  • NumPy agregará soporte para funciones matemáticas y herramientas para trabajar con matrices

Ahora, vamos a codificar

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

Herramientas de importación

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

peliculas en ingles

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

Usa este código para asegurarte de obtener títulos traducidos al inglés de todas las películas que raspamos:

Solicitar contenido de la URL

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

Desglose de las solicitudes de URL:

  •  url
      es la variable que creamos y le asignamos la URL
  •  results
    es la variable que creamos para almacenar nuestra acción request.get
  •  requests.get(url, headers=headers)
    es el método que usamos para captar el contenido de la URL.
  • los
     headers
    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 capturamos sea fácil de leer usando BeautifulSoup:

Rompiendo BeautifulSoup abajo:

  •  soup
    es la variable que creamos para asignar el método BeatifulSoup, que especifica un formato deseado de resultados utilizando el analizador HTML; esto permite que Python lea los componentes de la página en lugar de tratarlos como una cadena larga
  •  print(soup.prettify())
      imprimirá   lo que hemos agarrado   en un formato de árbol más estructurado, lo que facilita la lectura

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

Inicialice su almacenamiento

Cuando escribimos código para extraer nuestros datos, necesitamos un lugar para almacenar esos datos. Cree variables para cada tipo de datos que extraerá y asígnele una lista vacía, indicada por corchetes

 []
. Recuerde la lista de información que queríamos obtener de cada película anterior:

Tu código ahora debería verse así. Tenga en cuenta que podemos eliminar nuestra

 print
función hasta que necesitemos usarla de nuevo.

Encuentre el contenedor div correcto

Es hora de revisar el código HTML en nuestra página web.

Vaya a la página web que estamos raspando, inspecciónela y desplace el cursor sobre una sola película en su totalidad, como se muestra a continuación:

Necesitamos descubrir qué distingue a cada uno de estos de otros contenedores div que vemos.

Notarás la lista de

 div
elementos a la derecha con un
 class
atributo que tiene dos valores:
 lister-item
y
 mode-advanced
.

Si hace clic en cada uno de ellos, notará que resaltará cada contenedor de película a la izquierda de la página, como arriba.

Si hacemos una búsqueda rápida dentro de inspeccionar (presionamos Ctrl+F y escribimos

 lister-item mode-advanced
), veremos 50 coincidencias que representan las 50 películas que se muestran en una sola página. Ahora sabemos que toda la información que buscamos se encuentra dentro de este
 div
etiqueta.

Encuentra todos
 lister-item mode-advanced
divisiones

Nuestro próximo paso es decirle a nuestro raspador que encuentre todos estos divs avanzados en modo lister-item:

Rotura

 find_all
abajo:

  •  movie_div
    es la variable que usaremos para almacenar todos los contenedores div con una clase de
     lister-item mode-advanced
  • la
     find_all()
    El método extrae todos los contenedores div que tienen un atributo de clase de modo de elemento de listado avanzado de lo que hemos almacenado en nuestra sopa de variables.

Prepárate para extraer cada elemento

Si nos fijamos en la primera película de nuestra lista:

¡Nos faltan las ganancias brutas! Si miras la segunda película, la han incluido allí.

Algo que siempre debe considerar al construir un web scraper 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 construir alrededor de la idea de que simplemente no sabemos si eso sucederá o no.

Entrar en cada
 lister-item mode-advanced
división

Cuando tomamos cada uno de los elementos que necesitamos en un solo

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

Desglosando el bucle for:

  • A
     for
      círculo   se utiliza para iterar sobre una secuencia. Nuestra secuencia es cada
     lister-item mode-advanced
     div
    contenedor en el que almacenamos
     movie_div
  • container
      es el nombre de la variable que entra en cada div. Puedes nombrar esto como quieras (
     x
    ,
     loop
    ,
     banana
    ,
     cheese
    ), y no cambiará la función del ciclo.

Se puede leer así:

Extraer el título de la película.

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

Vemos que el nombre está contenido dentro de una etiqueta de anclaje,

 <a>
. Esta etiqueta está anidada dentro de una etiqueta de encabezado,
 <h3>
. los
 <h3>
la etiqueta está anidada dentro de un
 <div>
etiqueta. Este
 <div>
es el tercero de los
 div
Está anidado en el contenedor de la primera película.

Desglosando los títulos:

  •  name
    es la variable que usaremos para almacenar los datos del título que encontremos
  •  container
    es lo que usamos en nuestro
     for
    bucle: se usa para iterar cada vez.
  •  h3
    y
     .a
    es una notación de atributo y le dice al raspador que acceda a cada una de esas etiquetas.
  •  text
    le dice al raspador que tome el texto anidado en la etiqueta <a>
  •  titles.append(name)
    le dice al raspador que tome lo que encontramos y almacenó en el nombre y lo agregue a nuestra lista vacía llamada títulos, que creamos al principio

Extraer año de lanzamiento

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

Vemos que estos datos se almacenan dentro del

 <span>
etiqueta debajo de la
 <a>
etiqueta que contiene el título de la película. La notación de puntos, que usamos para encontrar los datos del título (
 .h3.a
), funcionó porque fue el primero
 <a>
etiqueta después de la
 h3
etiqueta. Desde el
 <span>
la etiqueta que queremos es la segunda
 <span>
etiqueta, tenemos que usar un método diferente.

En cambio, podemos decirle a nuestro raspador que busque por la marca distintiva del segundo

 <span>
. Usaremos el
 find()
método , que es similar a
 find_all()
excepto que solo devuelve el primer partido.

Desglosando los años:

  •  year
    es la variable que usaremos para almacenar los datos del año que encontremos
  •  container
    es lo que usamos en nuestro bucle for: se usa para iterar cada vez.
  •  h3
    es una notación de atributo, que le dice al raspador que acceda a esa etiqueta.
  •  find()
    es un método que usaremos para acceder a este particular
     <span>
    etiqueta
  • (
     'span', class_ = 'lister-item-year'
    ) es el distintivo
     <span>
    etiqueta que queremos
  •  years.append(year)
    le dice al raspador que tome lo que encontramos y almacenamos en el año y lo agregue a nuestra lista vacía llamada años (que creamos al principio)

Extraer la duración de la película

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

Los datos que necesitamos se pueden encontrar en un

 <span>
etiqueta con una clase de tiempo de ejecución. Como hicimos con el año, podemos hacer algo similar:

Desglosando el tiempo:

 runtime
es la variable que usaremos para almacenar los datos de tiempo que encontremos

  •  container
      es lo que usamos en nuestro bucle for: se usa para iterar cada vez.
  •  find()
    es un método que usaremos para acceder a este particular
     <span>
    etiqueta
  • ( 'span', class_ = 'runtime' ) es el distintivo
     <span>
    etiqueta que queremos
  •  if container.p.find('span', class_='runtime') else '-'
      dice que si hay datos allí, agárralos, pero si faltan datos, entonces coloca un guión allí.
  •  text
    le dice al raspador que tome ese texto en el
     <span>
    etiqueta
  •  time.append(runtime)
    le dice al raspador que tome lo que encontramos y almacenó en tiempo de ejecución y lo agregue a nuestra lista vacía llamada tiempo (que creamos al principio)

Extraer calificaciones de IMDb

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

Ahora, nos centraremos en extraer la calificación de IMDb. Los datos que necesitamos se pueden encontrar en un

 <strong>
etiqueta. Como no veo ninguna otra
 <strong>
etiquetas, podemos usar la notación de atributos (notación de puntos) para capturar estos datos.

Desglosando las calificaciones de IMDb:

  •  imdb
    es la variable que usaremos para almacenar los datos de calificaciones de IMDB que encuentre
  •  container
    es lo que usamos en nuestro
     for
    bucle: se usa para iterar cada vez.
  •  strong
    es una notación de atributo que le dice al raspador que acceda a esa etiqueta.
  •  text
    le dice al raspador que tome ese texto
  • los
     float()
    convierte el texto que encontramos en un flotante, que es un decimal
  •  imdb_ratings.append(imdb)
    le dice al raspador que tome lo que encontramos y almacenamos en
     imdb
    y para agregarlo a nuestra lista vacía llamada
     imdb_ratings
    (que creamos al principio).

Extraer metapuntuación

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

Los datos que necesitamos se pueden encontrar en un

 <span>
etiqueta que tiene una clase que dice
 metascore favorable
.

Antes de decidirnos por eso, debes notar que, por supuesto, un 96 para “Parasite” muestra una calificación favorable, pero ¿los demás son favorables? Si resalta el Metascore de la próxima película, verá que "JoJo Rabbit" tiene una clase que dice

 metascore mixed
. Dado que estas etiquetas son diferentes, sería seguro decirle al raspador que use solo la clase
 metascore
al raspar:

Desglosando Metascores:

  •  m_score
    es la variable que usaremos para almacenar los datos de clasificación Metascore que encuentra
  •  container
    es lo que usamos en nuestro
     for
    bucle: se usa para iterar cada vez.
  •  find()
    es un método que usaremos para acceder a este particular
     <span>
    etiqueta
  • (
     'span', class_ = 'metascore'
    ) es el distintivo
     <span>
    etiqueta que queremos.
  •  text
    le dice al raspador que tome ese texto
  •  if container.find('span', class_='metascore') else '-'
    dice que si hay datos allí, agárralos, pero si faltan, entonces coloca un guión allí
  • los
     int()
    método convierte el texto que encontramos en un número entero
  •  metascores.append(m_score)
    le dice al raspador que tome lo que encontramos y almacenamos en
     m_score
    y para agregarlo a nuestra lista vacía llamada
     metascores
    (que creamos al principio)

Extraer votos y ganancias brutas

Finalmente llegamos a los dos elementos finales que necesitamos extraer, pero dejamos lo más difícil 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 en esta lista, no vemos un número de ganancias brutas. 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í.

Tanto los votos como el bruto se destacan a la derecha. Después de ver los votos y los contenedores brutos de la película n.° 2, ¿qué notas?

Como puede ver, ambos están en una

 <span>
etiqueta que tiene un
 name
atributo que equivale
 nv
y un
 data-value
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?

Esto requirió mucha flexión del cerebro, toneladas de café y un par de noches para descubrirlo. Así es como lo hice:

Desglose de votos y bruto:

  •  nv
    es una variable completamente nueva que usaremos para mantener tanto los votos como el bruto
     <span>
    etiquetas
  •  container
    es lo que usamos en nuestro
     for
    bucle para iterar cada vez
  •  find_all()
    es el método que usaremos para capturar ambos
     <span>
    etiquetas
  • (
     'span', attrs = 'name' : 'nv'
    ) es cómo podemos obtener atributos de esa etiqueta específica.
  •  vote
    es la variable que usaremos para almacenar los votos que encontremos en el
     nv
    etiqueta
  •  nv[0]
    le dice al raspador que entre en el
     nv
    etiquete y tome los primeros datos en la lista, que son los votos porque los votos son lo primero en nuestro código HTML (las computadoras cuentan en binario, comienzan a contar en 0, no en 1).
  •  text
    le dice al raspador que tome ese texto
  •  votes.append(vote)
    le dice al raspador que tome lo que encontramos y almacenamos en
     vote
    y para agregarlo a nuestra lista vacía llamada
     votes
    (que creamos al principio)
  •  grosses
    es la variable que usaremos para almacenar el bruto que encontramos en el
     nv
    etiqueta
  •  nv[1]
    le dice al raspador que entre en el
     nv
    etiquete y obtenga los segundos datos de la lista, lo cual es bruto porque el bruto ocupa el segundo lugar en nuestro código HTML
  •  nv[1].text if len(nv) > 1 else '-'
    dice si la longitud de
     nv
    es mayor que uno, luego encuentre el segundo dato que está almacenado. Pero si los datos que están almacenados en
     nv
    no es mayor que uno, es decir, si falta el bruto, entonces coloque un guión allí.
  •  us_gross.append(grosses)
    le dice al raspador que tome lo que encontramos y almacenamos en
     grosses
    y para agregarlo a nuestra lista vacía llamada
     us_grosses
    (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 la función de impresión para imprimir cada lista a la que enviamos nuestros datos raspados:

Nuestras listas se ven así

 ['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', ' 117 min', ' 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.35 M', '-', '-', '-', '$ 135.37 M', '$ 192.73 M', '-', '-', '-', '-', '$ 0.43 M', '$ 433.03 M', '-', '$ 858.37 M', '$ 134.97 M', '$ 92.05 M', '$ 28.34 M', '$ 534.86 M', '$ 120.54 M', '$ 18.10 M', '-', '$ 107.93 M', '$ 292.58 M', '$ 188.02 M', '$ 85.08 M', '$ 32.87 M', '$ 116.90 M', '$ 167.77 M', '$ 44.02 M', '$ 171.48 M', '$ 659.33 M', '$ 130.74 M', '$ 54.51 M', '$ 317.58 M', '$ 13.12 M', '$ 2.01 M', '$ 0.01 M', '$ 315.54 M', '$ 187.71 M', '$ 228.43 M', '$ 216.43 M', '$ 107.51 M', '$ 330.25 M', '$ 315.06 M', '$ 167.45 M', '$ 45.88 M', '$ 57.30 M', '$ 162.81 M', '$ 107.83 M']

Hasta aquí todo bien, pero aún 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, Ms, mins, comas, paréntesis y espacios en blanco adicionales en Metascores.

Construyendo un marco de datos con pandas

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

Así es como lo hacemos:

Desglosando nuestro marco de datos:

  •  movies
    es lo que llamaremos nuestro DataFrame
  •  pd.DataFrame
    es como inicializamos la creación de un DataFrame con pandas
  • Las teclas de la izquierda son los nombres de las columnas.
  • Los valores a la derecha son nuestras listas de datos que hemos recopilado

Ver nuestro marco de datos

Podemos ver cómo se ve todo simplemente usando la función de impresión en nuestro DataFrame, al que llamamos películas, en la parte inferior de nuestro programa:

Nuestro marco de datos de pandas se ve así

Calidad de 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 : Ciertas columnas no pueden estar vacías
  • Patrones de expresiones regulares: campos de texto que deben tener un patrón determinado, como números de teléfono

¿Qué es la limpieza de datos?

La limpieza de datos es el proceso de detectar y corregir o eliminar registros corruptos o inexactos de su conjunto de datos.

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

Comprobación de tipos de datos

Podemos verificar cómo se ven nuestros tipos de datos ejecutando esta función de impresión en la parte inferior de nuestro programa:

Nuestros resultados de tipos de datos

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. Nuestro puntaje de IMDb también es correcto porque tenemos números de coma flotante en esta columna (números decimales).

Pero nuestro

 year
,
 timeMin
,
 metascore
, y
 votes
muestran que son objetos cuando deberían ser tipos de datos enteros, y nuestro
 us_grossMillions
  es un objeto en lugar de un
 float
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 también pueden contener números.

Por ejemplo, la palabra

 cheese
y el
 phrase I ate 10 blocks of cheese
son ambas cadenas. Si tuviéramos que deshacernos de todo excepto del
 10
desde el
 I ate 10 blocks of cheese
cadena, sigue siendo una cadena, pero ahora es una que solo dice
 10
.

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 los datos de nuestro año y convertir el objeto en un tipo de datos entero, haremos lo siguiente:

Desglose de los datos del año de limpieza:

  •  movies['year']
    le dice a los pandas que vayan a la columna año en nuestro
     DataFrame
  •  .str.extract('(\d+')
    este método:
     ('(\d+')
    dice que extraiga todos los dígitos en la cadena
  • los
     .astype(int)
    método convierte el resultado a un número entero

Ahora, si corremos

 print(movies['year'])
en la parte inferior de nuestro programa para ver cómo se ven los datos de nuestro año, este es el resultado:

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. Los datos de nuestro año se limpian oficialmente.

Datos de tiempo de limpieza

Haremos exactamente lo que hicimos limpiando los datos de nuestro año anterior a nuestros datos de tiempo tomando solo los dígitos y convirtiendo nuestro tipo de datos a un número entero.

Limpieza de datos Metascore

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

Votos de limpieza

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

Desglosando los votos de limpieza:

  •  movies['votes']
    son nuestros datos de votos en nuestras películas
     DataFrame
    . Estamos asignando nuestros nuevos datos limpios a nuestros votos.
     DataFrame
    .
  •  .str.replace(' , ' , '')
    agarra la cuerda y usa el
     replace
    método para reemplazar las comas con una comilla vacía (nada)
  • los
     .astype(int)
    método convierte el resultado en un número entero


Limpieza de datos brutos

Los datos brutos implican algunos obstáculos para saltar. Lo que debemos hacer es eliminar el signo de dólar y la M de los datos y convertirlos en un número de coma flotante. Aquí está cómo hacerlo:

Desglosando la limpieza bruta:

Código de limpieza superior:

  •  movies['us_grossMillions']
    son nuestros datos brutos en nuestras películas
     DataFrame
    . Asignaremos nuestros nuevos datos limpios a nuestro
     us_grossMillions
    columna.
  •  movies['us_grossMillions']
    le dice a los pandas que vayan al
     column us_grossMillions
    en nuestro
     DataFrame
  • los
     .map()
    función llama a la función especificada para cada elemento de un iterable
  •  lambda x: x
    es una función anónima en Python (una sin nombre). Las funciones normales se definen usando el
     def
    palabra clave.
  •  lstrip('$').rstrip('M')
    son los argumentos de nuestra función. Esto le dice a nuestra función que elimine el
     $
    desde el lado izquierdo y pelar el
     M
    desde el lado derecho.

Código de conversión inferior:

  •  movies['us_grossMillions']
    está despojado de los elementos que no necesitamos, y ahora le asignaremos los datos del código de conversión para terminarlo
  •  pd.to_numeric
    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 simplemente convertirlo en un flotante usando .astype(float) — esto detectaría un error.
  •  errors='coerce'
    transformará los valores no numéricos, nuestros guiones, en NaN   (no-un-número) valores   porque tenemos guiones en lugar de los datos que faltan

Revise el código limpio y convertido

Veamos cómo lo hicimos. Ejecute la función de impresión para ver nuestros datos y los tipos de datos que tenemos:

El resultado de nuestros datos limpios

El resultado de nuestros tipos de datos

¡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

¿Cuál es el uso de nuestros datos raspados si no podemos guardarlos para ningún proyecto o análisis futuro? 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:

  •  movies.to_csv('movies.csv')

Para que este código se ejecute correctamente, deberá crear un archivo vacío y nombrarlo como desee, asegurándose de que tenga el

 .csv
  extensión. nombré a la mía
 movies.csv
,   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 pasando el mouse cerca de Archivos y haciendo clic en la opción "Agregar archivo". Nómbrelo y guárdelo con un

 .csv
extensión. Luego, agregue el código al final de su programa:

 movies.to_csv('the_name_of_your_csv_here.csv')

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

Conclusión

Hemos recorrido un largo camino desde solicitar el contenido HTML de nuestra página web hasta limpiar todo nuestro DataFrame. Ahora debería saber cómo raspar páginas web con la misma estructura HTML y URL que le mostré anteriormente. Este es 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í hay algunas ideas para probar:

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

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

¡Feliz codificación!

Publicado anteriormente en https://medium.com/better-programming/the-only-step-by-step-guide-youll-need-to-build-a-web-scraper-with-python-e79066bd895a