diff --git a/lessons/02_web_scraping.ipynb b/lessons/02_web_scraping.ipynb index 696e0b0..2102e07 100644 --- a/lessons/02_web_scraping.ipynb +++ b/lessons/02_web_scraping.ipynb @@ -8,6 +8,15 @@ "\n", "* * *\n", "\n", + "### Iconos utilizados en este notebook\n", + "🔔 **Preguntas**: Una pregunta rápida para ayudarte a entender qué está pasando.
\n", + "🥊 **Desafío**: Ejercicio interactivo. Lo trabajaremos en el taller.!
\n", + "⚠️ **Advertencia**: Aviso sobre cuestiones complicadas o errores comunes.
\n", + "💡 **Tip**:Cómo hacer algo de forma un poco más eficiente o efectiva.
\n", + "🎬 **Demo**: Mostrando algo más avanzado: ¡para que sepas para qué se puede usar Python!
\n", + "\n", + "### Objetivos de aprendizaje\n", + "1. [Objetivos de aprendizaje](#when)\n", "### Íconos usados ​​en este cuaderno\n", "🔔 **Pregunta**: Una pregunta rápida para ayudarte a entender qué está pasando.
\n", "🥊 **Desafío**: Ejercicio interactivo. ¡Lo resolveremos en el taller!
\n", @@ -27,6 +36,13 @@ "source": [ "\n", "\n", + "# “¿Hacer scraping o no hacerlo?”\n", + "\n", + "Cuando queremos acceder a datos de la web, primero debemos asegurarnos de que el sitio web que nos interesa ofrezca una API web. Plataformas como Twitter, Reddit y The New York Times ofrecen API. **Echa un vistazo a D-Lab [Python Web APIs](https://github.com/dlab-berkeley/Python-Web-APIs) Taller si quieres aprender a utilizar las API.**\n", + "\n", + "Sin embargo, a menudo no existe una API web. En estos casos, podemos recurrir al web scraping, donde extraemos el HTML subyacente de una página web y obtenemos directamente la información deseada. Existen varios paquetes en Python que podemos usar para realizar estas tareas. Nos centraremos en dos paquetes: Requests y Beautiful Soup.\n", + "\n", + "Nuestro estudio de caso consistirá en extraer información sobre el [Senadores estatales de Illinois](http://www.ilga.gov/senate), así como el [lista de facturas](http://www.ilga.gov/senate/SenatorBills.asp?MemberID=1911&GA=98&Primary=True) Cada senador ha patrocinado. Antes de empezar, revise estos sitios web para conocer su estructura." "# Scraping o no scraping\n", "\n", "Para acceder a datos de la web, primero debemos asegurarnos de que el sitio web que nos interesa ofrezca una API web. Plataformas como Twitter, Reddit y el New York Times ofrecen API. **Consulta el taller de D-Lab sobre [API web de Python](https://github.com/dlab-berkeley/Python-Web-APIs) si quieres aprender a usar las API.**\n", @@ -34,6 +50,7 @@ "Sin embargo, a menudo no existe una API web. En estos casos, podemos recurrir al web scraping, donde extraemos el HTML subyacente de una página web y obtenemos directamente la información que buscamos. Existen varios paquetes en Python que podemos usar para realizar estas tareas. Nos centraremos en dos paquetes: Requests y Beautiful Soup.\n", "\n", "Nuestro estudio de caso recopilará información sobre los senadores estatales de Illinois (http://www.ilga.gov/senate), así como la lista de proyectos de ley patrocinados por cada senador. Antes de comenzar, revise estos sitios web para conocer su estructura." + ] }, { @@ -42,7 +59,11 @@ "source": [ "## Instalación\n", "\n", + + "Utilizaremos dos paquetes principales: [Solicitudes](http://docs.python-requests.org/en/latest/user/quickstart/) y [Beautiful Soup](http://www.crummy.com/software/BeautifulSoup/bs4/doc/). Continúe e instale estos paquetes, si aún no lo ha hecho:" + "Usaremos dos paquetes principales: [Requests](http://docs.python-requests.org/en/latest/user/quickstart/) y [Beautiful Soup](http://www.crummy.com/software/BeautifulSoup/bs4/doc/). Continúe instalando estos paquetes, si aún no lo ha hecho:" + ] }, { @@ -156,6 +177,11 @@ "\n", "# Extracción y análisis de HTML\n", "\n", + "Para extraer y analizar HTML correctamente, seguiremos los siguientes 4 pasos:\n", + "1. Realizar una solicitud GET\n", + "2. Analizar la página con Beautiful Soup\n", + "3. Buscar elementos HTML\n", + "4. Obtener los atributos y el texto de estos elementos" "Para extraer y analizar correctamente HTML, seguiremos los siguientes 4 pasos:\n", "1. Realizar una solicitud GET\n", "2. Analizar la página con Beautiful Soup\n", @@ -167,6 +193,15 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "## Paso 1: Realizar una solicitud GET para obtener el HTML de una página\n", + "\n", + "Podemos usar la biblioteca Requests para:\n", + "\n", + "1. Realizar una solicitud GET a la página y\n", + "2. Leer el código HTML de la página web.\n", + "\n", + "El proceso de realizar una solicitud y obtener un resultado es similar al del flujo de trabajo de la API web. Sin embargo, ahora realizamos una solicitud directamente al sitio web y tendremos que analizar el HTML nosotros mismos. Esto contrasta con recibir datos organizados en una salida JSON o XML más sencilla." +======= "## Paso 1: Realiza una solicitud GET para obtener el HTML de una página\n", "\n", "Podemos usar la librería Requests para:\n", @@ -374,7 +409,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ + + "¿Cuántos enlaces obtuvimos?" + "¿Cuantos enlaces obtuvimos?" + ] }, { @@ -466,7 +505,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ + + "## 🥊Desafío: Encontrar todo\n", + "## 🥊 Desafío: Encontrar todo\n", + "\n", "Usa BeautifulSoup para encontrar todos los elementos `a` con la clase `mainmenu`." ] @@ -484,7 +527,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ + + "Paso 4: Obtener los atributos y el texto de los elementos\n", + "## Paso 4: Obtener los atributos y el texto de los elementos\n", + "\n", "Una vez identificados los elementos, necesitamos la información de acceso de cada uno. Normalmente, esto implica dos cosas:\n", "\n", @@ -976,6 +1023,19 @@ "\n", "`http://www.ilga.gov/senate/SenatorBills.asp?MemberID=1911&GA=98&Primary=True`\n", "\n", + + "donde `MEMBER_ID=1911`.\n", + "\n", + "Deberías poder ver que, lamentablemente, `MEMBER_ID` no se extrae actualmente en nuestro código de extracción.\n", + "\n", + "Tu tarea inicial es modificar el código anterior para que también **recuperemos la URL completa que apunta a la página correspondiente de los proyectos de ley patrocinados por las primarias** de cada miembro, y la devolvamos junto con su nombre, distrito y partido.\n", + "\n", + "Consejos:\n", + "\n", + "* Para ello, deberá obtener el elemento de anclaje correspondiente (``) en la fila de cada legislador de la tabla. Puede usar el método `.select()` en el objeto `row` del bucle para hacerlo, de forma similar al comando que busca todas las celdas `td.detail` de la fila. Recuerde que solo necesitamos el enlace a los proyectos de ley del legislador, no a los comités ni a su página de perfil.\n", + "* El HTML de los elementos de anclaje se verá como `Proyectos de ley`. La cadena del atributo `href` contiene el enlace **relativo** que buscamos. Puede acceder a un atributo de un objeto `Tag` de BeatifulSoup de la misma manera que accede a un diccionario de Python: `anchor['attributeName']`. Consulta la documentación para obtener más detalles.\n", + "* Hay muchas maneras diferentes de usar BeautifulSoup. Puedes usar cualquier método para extraer el `href`.\n", + "en el cual `MEMBER_ID=1911`. \n", "\n", "Deberías poder ver que, lamentablemente, `MEMBER_ID` no se extrae actualmente en nuestro código de extracción.\n", @@ -987,6 +1047,7 @@ "* Para ello, deberás obtener el elemento de anclaje apropiado (``) en la fila de la tabla de cada legislador. Puedes usar el método `.select()` en el objeto `row` del bucle para hacerlo, similar al comando que encuentra todas las celdas `td.detail` de la fila. Recuerda que solo queremos el enlace a los proyectos de ley del legislador, no a los comités ni a su página de perfil.\n", "* El HTML de los elementos de anclaje se verá como `Proyectos de ley`. La cadena del atributo `href` contiene el enlace **relativo** que buscamos. Puedes acceder a un atributo de un objeto `Tag` de BeatifulSoup de la misma manera que accedes a un diccionario de Python: `anchor['attributeName']`. Consulta la documentación para más detalles.\n", "* Hay muchas maneras diferentes de usar BeautifulSoup. Puedes hacer lo que necesites para extraer el `href`.\n", + "\n", "El código se ha completado parcialmente. Complétalo donde dice `#TU CÓDIGO AQUÍ`. Guarda la ruta en un objeto llamado `full_path`." ] @@ -1051,7 +1112,11 @@ "source": [ "## 🥊 Desafío: Modulariza tu código\n", "\n", + + "Convierte el código anterior en una función que acepte una URL, rastree la URL para encontrar sus senadores y devuelva una lista de tuplas con información sobre cada senador. " + "Convierte el código anterior en una función que acepte una URL, rastree la URL para encontrar sus senadores y devuelva una lista de tuplas con información sobre cada senador." + ] }, { @@ -1085,6 +1150,22 @@ "cell_type": "markdown", "metadata": {}, "source": [ + + "## 🥊 Desafío práctico: Escribir una función de scraping\n", + "\n", + "Queremos scraping las páginas web correspondientes a los proyectos de ley patrocinados por cada proyecto de ley.\n", + "\n", + "Escribir una función llamada `get_bills(url)` para analizar la URL de un proyecto de ley. Esto implica:\n", + "\n", + "- Solicitar la URL mediante la biblioteca `requests`\n", + "- Usar las funciones de la biblioteca `BeautifulSoup` para encontrar todos los elementos `` con la clase `billlist`\n", + "- Devolver una _lista_ de tuplas, cada una con:\n", + "- Descripción (2.ª columna)\n", + "- Cámara (S o H) (3.ª columna)\n", + "- La última acción (4.ª columna)\n", + "- La fecha de la última acción (5.ª columna)\n", + "\n", + "## 🥊Desafío práctico: Escribir una función de scraping\n", "\n", "Queremos scraping las páginas web correspondientes a los proyectos de ley patrocinados por cada proyecto de ley.\n", @@ -1099,6 +1180,7 @@ "- La última acción (4.ª columna)\n", "- La fecha de la última acción (5.ª columna)\n", "\n", + "Esta función se ha completado parcialmente. Complete el resto." ] }, @@ -1117,7 +1199,11 @@ " bills = []\n", " for row in rows:\n", " # YOUR CODE HERE\n", + + " #bill_id =\n", + " # bill_id =\n", + " #description =\n", " #chamber =\n", " #last_action =\n",