|
8 | 8 | "\n", |
9 | 9 | "* * *\n", |
10 | 10 | "\n", |
| 11 | + "### Iconos utilizados en este notebook\n", |
| 12 | + "🔔 **Preguntas**: Una pregunta rápida para ayudarte a entender qué está pasando.<br>\n", |
| 13 | + "🥊 **Desafío**: Ejercicio interactivo. Lo trabajaremos en el taller.!<br>\n", |
| 14 | + "⚠️ **Advertencia**: Aviso sobre cuestiones complicadas o errores comunes.<br>\n", |
| 15 | + "💡 **Tip**:Cómo hacer algo de forma un poco más eficiente o efectiva.<br>\n", |
| 16 | + "🎬 **Demo**: Mostrando algo más avanzado: ¡para que sepas para qué se puede usar Python!<br>\n", |
| 17 | + "\n", |
| 18 | + "### Objetivos de aprendizaje\n", |
| 19 | + "1. [Objetivos de aprendizaje](#when)\n", |
11 | 20 | "### Íconos usados en este cuaderno\n", |
12 | 21 | "🔔 **Pregunta**: Una pregunta rápida para ayudarte a entender qué está pasando.<br>\n", |
13 | 22 | "🥊 **Desafío**: Ejercicio interactivo. ¡Lo resolveremos en el taller!<br>\n", |
|
27 | 36 | "source": [ |
28 | 37 | "<a id='when'></a>\n", |
29 | 38 | "\n", |
| 39 | + "# “¿Hacer scraping o no hacerlo?”\n", |
| 40 | + "\n", |
| 41 | + "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", |
| 42 | + "\n", |
| 43 | + "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", |
| 44 | + "\n", |
| 45 | + "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." |
30 | 46 | "# Scraping o no scraping\n", |
31 | 47 | "\n", |
32 | 48 | "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", |
33 | 49 | "\n", |
34 | 50 | "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", |
35 | 51 | "\n", |
36 | 52 | "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." |
| 53 | + |
37 | 54 | ] |
38 | 55 | }, |
39 | 56 | { |
|
42 | 59 | "source": [ |
43 | 60 | "## Instalación\n", |
44 | 61 | "\n", |
| 62 | + |
| 63 | + "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:" |
| 64 | + |
45 | 65 | "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:" |
| 66 | + |
46 | 67 | ] |
47 | 68 | }, |
48 | 69 | { |
|
156 | 177 | "\n", |
157 | 178 | "# Extracción y análisis de HTML\n", |
158 | 179 | "\n", |
| 180 | + "Para extraer y analizar HTML correctamente, seguiremos los siguientes 4 pasos:\n", |
| 181 | + "1. Realizar una solicitud GET\n", |
| 182 | + "2. Analizar la página con Beautiful Soup\n", |
| 183 | + "3. Buscar elementos HTML\n", |
| 184 | + "4. Obtener los atributos y el texto de estos elementos" |
159 | 185 | "Para extraer y analizar correctamente HTML, seguiremos los siguientes 4 pasos:\n", |
160 | 186 | "1. Realizar una solicitud GET\n", |
161 | 187 | "2. Analizar la página con Beautiful Soup\n", |
|
167 | 193 | "cell_type": "markdown", |
168 | 194 | "metadata": {}, |
169 | 195 | "source": [ |
| 196 | + "## Paso 1: Realizar una solicitud GET para obtener el HTML de una página\n", |
| 197 | + "\n", |
| 198 | + "Podemos usar la biblioteca Requests para:\n", |
| 199 | + "\n", |
| 200 | + "1. Realizar una solicitud GET a la página y\n", |
| 201 | + "2. Leer el código HTML de la página web.\n", |
| 202 | + "\n", |
| 203 | + "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." |
| 204 | +======= |
170 | 205 | "## Paso 1: Realiza una solicitud GET para obtener el HTML de una página\n", |
171 | 206 | "\n", |
172 | 207 | "Podemos usar la librería Requests para:\n", |
|
374 | 409 | "cell_type": "markdown", |
375 | 410 | "metadata": {}, |
376 | 411 | "source": [ |
| 412 | + |
| 413 | + "¿Cuántos enlaces obtuvimos?" |
| 414 | + |
377 | 415 | "¿Cuantos enlaces obtuvimos?" |
| 416 | + |
378 | 417 | ] |
379 | 418 | }, |
380 | 419 | { |
|
466 | 505 | "cell_type": "markdown", |
467 | 506 | "metadata": {}, |
468 | 507 | "source": [ |
| 508 | + |
| 509 | + "## 🥊Desafío: Encontrar todo\n", |
| 510 | + |
469 | 511 | "## 🥊 Desafío: Encontrar todo\n", |
| 512 | + |
470 | 513 | "\n", |
471 | 514 | "Usa BeautifulSoup para encontrar todos los elementos `a` con la clase `mainmenu`." |
472 | 515 | ] |
|
484 | 527 | "cell_type": "markdown", |
485 | 528 | "metadata": {}, |
486 | 529 | "source": [ |
| 530 | + |
| 531 | + "Paso 4: Obtener los atributos y el texto de los elementos\n", |
| 532 | + |
487 | 533 | "## Paso 4: Obtener los atributos y el texto de los elementos\n", |
| 534 | + |
488 | 535 | "\n", |
489 | 536 | "Una vez identificados los elementos, necesitamos la información de acceso de cada uno. Normalmente, esto implica dos cosas:\n", |
490 | 537 | "\n", |
|
976 | 1023 | "\n", |
977 | 1024 | "`http://www.ilga.gov/senate/SenatorBills.asp?MemberID=1911&GA=98&Primary=True`\n", |
978 | 1025 | "\n", |
| 1026 | + |
| 1027 | + "donde `MEMBER_ID=1911`.\n", |
| 1028 | + "\n", |
| 1029 | + "Deberías poder ver que, lamentablemente, `MEMBER_ID` no se extrae actualmente en nuestro código de extracción.\n", |
| 1030 | + "\n", |
| 1031 | + "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", |
| 1032 | + "\n", |
| 1033 | + "Consejos:\n", |
| 1034 | + "\n", |
| 1035 | + "* Para ello, deberá obtener el elemento de anclaje correspondiente (`<a>`) 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", |
| 1036 | + "* El HTML de los elementos de anclaje se verá como `<a href=\"/senate/Senator.asp/...\">Proyectos de ley</a>`. 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 <a href=\"http://www.crummy.com/software/BeautifulSoup/bs4/doc/#tag\">documentación</a> para obtener más detalles.\n", |
| 1037 | + "* Hay muchas maneras diferentes de usar BeautifulSoup. Puedes usar cualquier método para extraer el `href`.\n", |
| 1038 | + |
979 | 1039 | "en el cual `MEMBER_ID=1911`. \n", |
980 | 1040 | "\n", |
981 | 1041 | "Deberías poder ver que, lamentablemente, `MEMBER_ID` no se extrae actualmente en nuestro código de extracción.\n", |
|
987 | 1047 | "* Para ello, deberás obtener el elemento de anclaje apropiado (`<a>`) 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", |
988 | 1048 | "* El HTML de los elementos de anclaje se verá como `<a href=\"/senate/Senator.asp/...\">Proyectos de ley</a>`. 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 <a href=\"http://www.crummy.com/software/BeautifulSoup/bs4/doc/#tag\">documentación</a> para más detalles.\n", |
989 | 1049 | "* Hay muchas maneras diferentes de usar BeautifulSoup. Puedes hacer lo que necesites para extraer el `href`.\n", |
| 1050 | + |
990 | 1051 | "\n", |
991 | 1052 | "El código se ha completado parcialmente. Complétalo donde dice `#TU CÓDIGO AQUÍ`. Guarda la ruta en un objeto llamado `full_path`." |
992 | 1053 | ] |
|
1051 | 1112 | "source": [ |
1052 | 1113 | "## 🥊 Desafío: Modulariza tu código\n", |
1053 | 1114 | "\n", |
| 1115 | + |
| 1116 | + "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. " |
| 1117 | + |
1054 | 1118 | "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." |
| 1119 | + |
1055 | 1120 | ] |
1056 | 1121 | }, |
1057 | 1122 | { |
|
1085 | 1150 | "cell_type": "markdown", |
1086 | 1151 | "metadata": {}, |
1087 | 1152 | "source": [ |
| 1153 | + |
| 1154 | + "## 🥊 Desafío práctico: Escribir una función de scraping\n", |
| 1155 | + "\n", |
| 1156 | + "Queremos scraping las páginas web correspondientes a los proyectos de ley patrocinados por cada proyecto de ley.\n", |
| 1157 | + "\n", |
| 1158 | + "Escribir una función llamada `get_bills(url)` para analizar la URL de un proyecto de ley. Esto implica:\n", |
| 1159 | + "\n", |
| 1160 | + "- Solicitar la URL mediante la biblioteca <a href=\"http://docs.python-requests.org/en/latest/\">`requests`</a>\n", |
| 1161 | + "- Usar las funciones de la biblioteca `BeautifulSoup` para encontrar todos los elementos `<td>` con la clase `billlist`\n", |
| 1162 | + "- Devolver una _lista_ de tuplas, cada una con:\n", |
| 1163 | + "- Descripción (2.ª columna)\n", |
| 1164 | + "- Cámara (S o H) (3.ª columna)\n", |
| 1165 | + "- La última acción (4.ª columna)\n", |
| 1166 | + "- La fecha de la última acción (5.ª columna)\n", |
| 1167 | + "\n", |
| 1168 | + |
1088 | 1169 | "## 🥊Desafío práctico: Escribir una función de scraping\n", |
1089 | 1170 | "\n", |
1090 | 1171 | "Queremos scraping las páginas web correspondientes a los proyectos de ley patrocinados por cada proyecto de ley.\n", |
|
1099 | 1180 | "- La última acción (4.ª columna)\n", |
1100 | 1181 | "- La fecha de la última acción (5.ª columna)\n", |
1101 | 1182 | "\n", |
| 1183 | + |
1102 | 1184 | "Esta función se ha completado parcialmente. Complete el resto." |
1103 | 1185 | ] |
1104 | 1186 | }, |
|
1117 | 1199 | " bills = []\n", |
1118 | 1200 | " for row in rows:\n", |
1119 | 1201 | " # YOUR CODE HERE\n", |
| 1202 | + |
| 1203 | + " #bill_id =\n", |
| 1204 | + |
1120 | 1205 | " # bill_id =\n", |
| 1206 | + |
1121 | 1207 | " #description =\n", |
1122 | 1208 | " #chamber =\n", |
1123 | 1209 | " #last_action =\n", |
|
0 commit comments