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 `