{
"cells": [
{
"cell_type": "markdown",
"id": "49ee5ba2-38d8-4bdc-af42-69de0cfe999f",
"metadata": {},
"source": [
"# D: Web Scraping\n",
"\n",
"Para introducir este tema haremos uso de [una presentación (PDF)](./ficherosAuxiliares/webScrapingAstronomia.pdf).\n",
"\n",
"[](./ficherosAuxiliares/webScrapingAstronomia.pdf)"
]
},
{
"cell_type": "markdown",
"id": "317c5c04-3c84-42e1-bd81-2cdca7d21042",
"metadata": {},
"source": [
"## Scraping Básico\n",
"### Descargando páginas web\n",
"\n",
"El primer paso antes de hacer cualquier tipo de scraping es decidir que página queremos descargar y analizar. En nuestro caso vamos a obtener datos de la página del Instituto Carlos III sobre la evolución del COVID-19:\n",
"\n",
"https://covid19.isciii.es/ - La reemplazamos por https://zerjio.com/temp/covid19.html\n",
"\n",
"Lo primero que deberíamos hacer sería visualizar la página en nuestro navegador favorito (¿Firefox?) para comprobar el aspecto que tiene y la información que podemos descargar.\n",
"\n",
"A continuación tendremos que emular el comportamiento del navegador para obtener la página: tendremos que hacer una petición HTTP para recuperar la página web. Lo haremos usando la biblioteca \"requests\".\n",
"\n",
"Información y ejemplos sobre dicho módulo: https://www.w3schools.com/python/module_requests.asp"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "6de1e7fa-7552-463b-9b79-0b1ba5b11aa2",
"metadata": {},
"outputs": [],
"source": [
"import requests\n",
"from pprint import pprint\n",
"\n",
"#respuesta = requests.get(\"https://covid19.isciii.es/\") # Utilizamo el metodo GET del protocolor HTTP\n",
"respuesta = requests.get(\"https://zerjio.com/temp/covid19.html\") "
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "5d4ed4e5-1ad7-4788-a830-5eec835a4eca",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'_content': b' \\n
\\n \\n '\n",
" b' \\n\\n \\n P\\xc3\\xa1gina del COVID 19 para solv'\n",
" b'entar problema en el curso de Python, m\\xc3\\xb3dulo de web-scr'\n",
" b'apping\\n \\n \\n \\n
Esta p\\xc3\\xa1gina \"simula\" una p'\n",
" b'\\xc3\\xa1gina que hab\\xc3\\xada en el direcci\\xc3\\xb3n https://c'\n",
" b'ovid19.isciii.es/ . Aunque no se parece est\\xc3\\xa9ticamente t'\n",
" b'iene los mismos elementos para que los ejemplos funcionen igual.'\n",
" b'
\\n \\n
\\xc3\\x9altima actualizaci\\xc3\\xb3n 10 de Marzo de 2020 a las\\n 10:10
\\n \\n \\n
\\n \\n
Dato 1<'\n",
" b'/td>
33
\\n
Dato 2
666
'\n",
" b'
\\n
Dato 3
7777
\\n '\n",
" b'
Dato 4
99
\\n \\n \\n '\n",
" b'
\\n \\n
La que viene a continuaci\\xc3\\xb3n '\n",
" b'es la tabla de datos de verdad.
\\n \\n \\n
\\n
\\n
\\n
Comunidad
\\n '\n",
" b'
Contagiados
\\n
Fallecidos
\\n '\n",
" b'
Curados
\\n
\\n \\n \\n '\n",
" b' \\n
\\n
Andaluc\\xc3\\xada\\n
80
\\n
\\n \\n
\\n \\n
\\n
'\n",
" b'Arag\\xc3\\xb3n
\\n
50
\\n
'\n",
" b'\\n
\\n
\\n \\n \\n
Principado de Asturias
\\n
30
\\n
\\n
\\n <'\n",
" b'/tr>\\n \\n
\\n
Islas Baleares\\n
10
\\n
\\n \\n
\\n \\n
\\n
'\n",
" b'Canarias
\\n
35
\\n
\\n '\n",
" b'
\\n
\\n \\n
\\n '\n",
" b'
Cantabria
\\n
12
\\n '\n",
" b'
\\n
\\n
\\n \\n '\n",
" b'
\\n
Castilla y Le\\xc3\\xb3n
\\n '\n",
" b'
60
\\n
\\n
\\n '\n",
" b'
\\n \\n
\\n
Catalu'\n",
" b'\\xc3\\xb1a
\\n
110
\\n
\\n
\\n
\\n \\n <'\n",
" b'tr>\\n
Galicia
\\n
20
\\n '\n",
" b'
\\n
\\n \\n \\n'\n",
" b'
\\n
C. Valenciana
\\n <'\n",
" b'td>62\\n
\\n
\\n '\n",
" b'
\\n \\n
\\n
Extremadura
\\n
7
\\n
\\n
'\n",
" b'
\\n
\\n \\n
\\n
Co'\n",
" b'munidad de Madrid
\\n
760
\\n \\n
\\n
\\n \\n '\n",
" b'
\\n
Regi\\xc3\\xb3n de Murcia
\\n <'\n",
" b'td>7\\n
\\n
\\n '\n",
" b'
\\n \\n
\\n
Comunidad Foral '\n",
" b'de Navarra
\\n
9
\\n
\\n '\n",
" b'
\\n
\\n \\n
\\n '\n",
" b'
Pa\\xc3\\xads Vasco
\\n
190
\\n '\n",
" b'
\\n
\\n
\\n '\n",
" b' \\n
\\n
La Rioja
\\n
'\n",
" b'130
\\n
\\n
\\n <'\n",
" b'/tr>\\n \\n
\\n
Ceuta
\\n '\n",
" b'
0
\\n
\\n
\\n '\n",
" b'
\\n \\n
\\n
Melilla\\n
0
\\n
\\n
\\n
\\n \\n \\n
\\n \\n
Vaya faena nos han hecho los de la p\\xc3\\xa1gina...
\\n \\n \\n \\n \\n \\n \\n',\n",
" '_content_consumed': True,\n",
" '_next': None,\n",
" 'connection': ,\n",
" 'cookies': ,\n",
" 'elapsed': datetime.timedelta(microseconds=188306),\n",
" 'encoding': 'ISO-8859-1',\n",
" 'headers': {'Date': 'Thu, 20 Apr 2023 10:29:30 GMT', 'Server': 'Apache/2.4.18 (Ubuntu)', 'Last-Modified': 'Mon, 11 May 2020 10:04:22 GMT', 'ETag': '\"1079-5a55c78929580-gzip\"', 'Accept-Ranges': 'bytes', 'Vary': 'Accept-Encoding', 'Content-Encoding': 'gzip', 'Content-Length': '1086', 'Keep-Alive': 'timeout=5, max=100', 'Connection': 'Keep-Alive', 'Content-Type': 'text/html'},\n",
" 'history': [],\n",
" 'raw': ,\n",
" 'reason': 'OK',\n",
" 'request': ,\n",
" 'status_code': 200,\n",
" 'url': 'https://zerjio.com/temp/covid19.html'}\n"
]
}
],
"source": [
"# Hemos obtenido un objeto de tipo \"Response\", donde estará toda la información que hemos obtenido de la página\n",
"# https://www.w3schools.com/python/ref_requests_response.asp\n",
"\n",
"pprint(vars(respuesta)) # Podemos inspeccionar el objeto y ver que campos nos interesan. Particularmente:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "a9d0cfa2-10b3-4648-9e76-53b058ab2e3b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"200\n",
"OK\n",
"0:00:00.188306\n",
"ISO-8859-1\n"
]
}
],
"source": [
"print(respuesta.status_code) # El código de estado: 200 Es el código de que todo ha ido bien. \n",
" # Lista de códigos de estados posibles: https://www.restapitutorial.com/httpstatuscodes.html\n",
" \n",
"print(respuesta.reason) # Una descripción textual del código de respuesta \n",
"\n",
"\n",
"print(respuesta.elapsed) # Tiempo que se ha tardado desde que se hizo la petición hasta que se obtuvo la respuesta\n",
"\n",
"\n",
"print(respuesta.encoding) # La codificación del documento (juego de caracteres usado)\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "feb9cbcb-a76b-438d-8307-30210d0fe76d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b' \\n \\n \\n \\n\\n \\n P\\xc3\\xa1gina del COVID 19 para solventar problema en el curso de Python, m\\xc3\\xb3dulo de web-scrapping\\n \\n \\n \\n
Esta p\\xc3\\xa1gina \"simula\" una p\\xc3\\xa1gina que hab\\xc3\\xada en el direcci\\xc3\\xb3n https://covid19.isciii.es/ . Aunque no se parece est\\xc3\\xa9ticamente tiene los mismos elementos para que los ejemplos funcionen igual.
\\n \\n
\\xc3\\x9altima actualizaci\\xc3\\xb3n 10 de Marzo de 2020 a las\\n 10:10
\\n \\n \\n
\\n \\n
Dato 1
33
\\n
Dato 2
666
\\n
Dato 3
7777
\\n
Dato 4
99
\\n \\n \\n
\\n \\n
La que viene a continuaci\\xc3\\xb3n es la tabla de datos de verdad.
\\n \\n \\n
\\n \\n
\\n
Comunidad
\\n
Contagiados
\\n
Fallecidos
\\n
Curados
\\n
\\n \\n \\n \\n
\\n
Andaluc\\xc3\\xada
\\n
80
\\n
\\n
\\n
\\n \\n
\\n
Arag\\xc3\\xb3n
\\n
50
\\n
\\n
\\n
\\n \\n
\\n
Principado de Asturias
\\n
30
\\n
\\n
\\n
\\n \\n
\\n
Islas Baleares
\\n
10
\\n
\\n
\\n
\\n \\n
\\n
Canarias
\\n
35
\\n
\\n
\\n
\\n \\n
\\n
Cantabria
\\n
12
\\n
\\n
\\n
\\n \\n
\\n
Castilla y Le\\xc3\\xb3n
\\n
60
\\n
\\n
\\n
\\n \\n
\\n
Catalu\\xc3\\xb1a
\\n
110
\\n
\\n
\\n
\\n \\n
\\n
Galicia
\\n
20
\\n
\\n
\\n
\\n \\n
\\n
C. Valenciana
\\n
62
\\n
\\n
\\n
\\n \\n
\\n
Extremadura
\\n
7
\\n
\\n
\\n
\\n \\n
\\n
Comunidad de Madrid
\\n
760
\\n
\\n
\\n
\\n \\n
\\n
Regi\\xc3\\xb3n de Murcia
\\n
7
\\n
\\n
\\n
\\n \\n
\\n
Comunidad Foral de Navarra
\\n
9
\\n
\\n
\\n
\\n \\n
\\n
Pa\\xc3\\xads Vasco
\\n
190
\\n
\\n
\\n
\\n \\n
\\n
La Rioja
\\n
130
\\n
\\n
\\n
\\n \\n
\\n
Ceuta
\\n
0
\\n
\\n
\\n
\\n \\n
\\n
Melilla
\\n
0
\\n
\\n
\\n
\\n \\n \\n
\\n \\n
Vaya faena nos han hecho los de la p\\xc3\\xa1gina...
\\n \\n \\n \\n \\n \\n \\n'\n"
]
}
],
"source": [
"print(respuesta.content) # Y lo que probablemente nos interesa más: el CONTENIDO de la página.\n",
" # El \"problema\" es que es una cadena \"binaria\"."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "a7fb1f60-f2fe-4775-a9a1-208bc1ac0008",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" \n",
" \n",
" \n",
" \n",
"\n",
" \n",
" Página del COVID 19 para solventar problema en el curso de Python, módulo de web-scrapping\n",
" \n",
" \n",
" \n",
"
Esta página \"simula\" una página que había en el dirección https://covid19.isciii.es/ . Aunque no se parece estéticamente tiene los mismos elementos para que los ejemplos funcionen igual.
\n",
" \n",
"
Última actualización 10 de Marzo de 2020 a las\n",
" 10:10
\n",
" \n",
" \n",
"
\n",
" \n",
"
Dato 1
33
\n",
"
Dato 2
666
\n",
"
Dato 3
7777
\n",
"
Dato 4
99
\n",
" \n",
" \n",
"
\n",
" \n",
"
La que viene a continuación es la tabla de datos de verdad.
\n",
" \n",
" \n",
"
\n",
" \n",
"
\n",
"
Comunidad
\n",
"
Contagiados
\n",
"
Fallecidos
\n",
"
Curados
\n",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
Andalucía
\n",
"
80
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Aragón
\n",
"
50
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Principado de Asturias
\n",
"
30
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Islas Baleares
\n",
"
10
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Canarias
\n",
"
35
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Cantabria
\n",
"
12
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Castilla y León
\n",
"
60
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Cataluña
\n",
"
110
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Galicia
\n",
"
20
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
C. Valenciana
\n",
"
62
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Extremadura
\n",
"
7
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Comunidad de Madrid
\n",
"
760
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Región de Murcia
\n",
"
7
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Comunidad Foral de Navarra
\n",
"
9
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
País Vasco
\n",
"
190
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
La Rioja
\n",
"
130
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Ceuta
\n",
"
0
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Melilla
\n",
"
0
\n",
"
\n",
"
\n",
"
\n",
" \n",
" \n",
"
\n",
" \n",
"
Vaya faena nos han hecho los de la página...
\n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
"\n"
]
}
],
"source": [
"html = respuesta.content.decode(\"UTF-8\") # Lo podemos codificar a una cadena \"normal\"\n",
"\n",
"print(html)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "ae8dc804-6631-4fac-ae6b-d4aefa8f90a0",
"metadata": {},
"outputs": [],
"source": [
"# Podemos guardar el código HTML a un fichero local para poder inspeccionarlo con más tranquilidad\n",
"\n",
"text_file = open(\"salidas/covid-19.html\", \"w\")\n",
"text_file.write(html)\n",
"text_file.close()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "f26646fc-95ad-4f58-992a-dbbe5f0bee3e",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Línea 1: \n",
"Línea 2: \n",
"Línea 3: \n",
"Línea 4: \n",
"Línea 5: \n",
"Línea 6: \n",
"Línea 21: Página del COVID 19 para solventar problema en el curso de Python, módulo de web-scrapping\n",
"Línea 22: \n",
"Línea 23: \n",
"Línea 24: \n",
"Línea 25:
Esta página \"simula\" una página que había en el dirección https://covid19.isciii.es/ . Aunque no se parece estéticamente tiene los mismos elementos para que los ejemplos funcionen igual.
\n",
"Línea 26: \n",
"Línea 27:
Última actualización 10 de Marzo de 2020 a las\n",
"Línea 28: 10:10
\n",
"Línea 29: \n",
"Línea 30: \n",
"Línea 31:
\n",
"Línea 32: \n",
"Línea 33:
Dato 1
33
\n",
"Línea 34:
Dato 2
666
\n",
"Línea 35:
Dato 3
7777
\n",
"Línea 36:
Dato 4
99
\n",
"Línea 37: \n",
"Línea 38: \n",
"Línea 39:
\n",
"Línea 40: \n",
"Línea 41:
La que viene a continuación es la tabla de datos de verdad.
\n",
"Línea 185: \n",
"Línea 186: \n",
"Línea 187: \n",
"Línea 188: \n",
"Línea 189: \n",
"Línea 190: \n"
]
}
],
"source": [
"# También puede ser interesante usar el iterador que te permite recorrer el contenido obtenido línea a línea\n",
"for num, linea in enumerate(respuesta.iter_lines(), start=1):\n",
" print(\"Línea %d: %s\" % (num, linea.decode(\"UTF-8\")) )"
]
},
{
"cell_type": "markdown",
"id": "26ed47a0-ed53-4bfd-ae99-bc9bc0746800",
"metadata": {},
"source": [
"### Bajando ficheros binarios\n",
"\n",
"Normalmente las páginas web están escritas en ```HTML``` que es tipo de fichero de texto (string) fácil de manejar. Sin embargo en ocasiones querremos bajar ficheros que estén en otros formatos que no sean texto (binarios), como son los formatos ```PDF```, ```EXE```, ```ZIP```, ```JPG```.\n",
"\n",
"En una sección anterior del curso se planteó un script para bajar el BOP de Granada y luego sacar información del ```PDF```. A continuación vamos a \"refinar\" el script que se creó simplificando y aprovechando alguna información que nos ofrece el protocolo ```HTTP```.\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "339a6d34-fbff-4278-a1d6-a07cac4b3fcf",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2023-04-20 12:29:30.915929\n",
"20/04/2023\n",
"https://bop2.dipgra.es/opencms/opencms/portal/DescargaPDFBoletin?fecha=20/04/2023\n"
]
}
],
"source": [
"import datetime\n",
"import requests\n",
"\n",
"baseURL=\"https://bop2.dipgra.es/opencms/opencms/portal/DescargaPDFBoletin?fecha=\"\n",
"\n",
"fecha = datetime.datetime.now()\n",
"#fecha = datetime.datetime(2020, 5, 6) # Año, mes, día, para una fecha que no sea hoy\n",
"print(fecha)\n",
"\n",
"fechaFormateada = fecha.strftime(\"%d/%m/%Y\") # Formateamos la fecha, https://www.programiz.com/python-programming/datetime/strftime\n",
"print(fechaFormateada)\n",
"\n",
"url = baseURL + fechaFormateada\n",
"print(url)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "245f7b13-06fc-4839-99e2-33eb5d1fe353",
"metadata": {},
"outputs": [],
"source": [
"respuesta = requests.get(url) # hacemos la petición y se descargan los contenidos"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "6e4f30b9-1e9c-4167-aad6-a9a67c52f6d7",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Cabeceras recibidas: {'Date': 'Thu, 20 Apr 2023 10:25:00 GMT', 'Content-disposition': 'attachment;filename=Boletin_20230420.pdf', 'Content-Type': 'application/pdf', 'Keep-Alive': 'timeout=5, max=100', 'Connection': 'Keep-Alive', 'Transfer-Encoding': 'chunked'}\n",
"\n",
"Tipo de información descargada: application/pdf\n",
"\n",
"Tamaño descargado: 563625 bytes\n",
"\n",
"Campo que nos sugiere el nombre del fichero descargado: attachment;filename=Boletin_20230420.pdf\n",
"\n",
"Fichero salidas/Boletin_20230420.pdf grabado en disco.\n",
"\n"
]
}
],
"source": [
"print(\"Cabeceras recibidas: \" + str(respuesta.headers) + \"\\n\") # Inspeccionamos las cabeceras que hemos recibido\n",
"\n",
"# Nos interesa ver que \"Content-Type\" ya nos indica que es un fichero que puede abrirse con una aplicación \n",
"# que maneje PDFs\n",
"# Además en alguna ocasión podemos recibir que el tamaño del contenido descargado: \"Content-Length\"\n",
"\n",
"print(\"Tipo de información descargada: \" + respuesta.headers['Content-Type'] + \"\\n\")\n",
"\n",
"tamanioDescargado = 0\n",
"if \"Content-Length\" in respuesta.headers:\n",
" tamanioDescargado = int(respuesta.headers['Content-Length'])\n",
"else:\n",
" tamanioDescargado = len(respuesta.content) # Si no nos lo dice la cabecera podemos mirar el tamaño del\n",
" # contenido descargado\n",
" \n",
" \n",
"print(\"Tamaño descargado: \" + str(tamanioDescargado) + \" bytes\\n\")\n",
"\n",
"# Además nos damos cuenta que la aplicación web nos sugiere un nombre para el fichero que vamos a descargar:\n",
"\n",
"print(\"Campo que nos sugiere el nombre del fichero descargado: \" + respuesta.headers['Content-disposition'] + \"\\n\")\n",
"\n",
"# En la aplicación web que sirve los BOP de Granada siempre devuelve una respuesta válida (código 200)\n",
"# aunque no exista el PDF de la fecha pedida. En una aplicación bien hecha devolvería un codigo de error distinto\n",
"# (NOT FOUND o similar). En cualquier caso nosotros nos hemos dado cuenta que si el contenido devuelto es 0 bytes\n",
"# es que ese día no hay BOP.\n",
"\n",
"if tamanioDescargado == 0:\n",
" print(\"En la fecha indicada no hay BOP (o es una fecha incorrecta).\\n\")\n",
"else:\n",
" \n",
" filename = \"salidas/\" + respuesta.headers['Content-disposition'][20:] # Saco el nombre del fichero truncando la cadena\n",
" \n",
" myfile = open(filename,'wb')\n",
" myfile.write(respuesta.content)\n",
" myfile.close()\n",
" \n",
" print(\"Fichero \" + filename + \" grabado en disco.\\n\")"
]
},
{
"cell_type": "markdown",
"id": "1413256a-6905-404f-a9e8-9c8b69d85998",
"metadata": {},
"source": [
"### Solucionando un problema común: requests.exceptions.SSLError \n",
"\n",
"Al intentar hacer scraping a algunas páginas web puede que nos salte una excepción del tipo ```requests.exceptions.SSLError```. Ese problema viene derivado de una mala configuración del servidor web (no es problema nuestro): Básicamente no tiene actualizado el certificado digital necesario para establecer una conexión segura. En realidad la explicación es más técnica, pero basta con saber eso para reconocer el error. La solución es \"fácil\": solo tenemos que decirle al módulo ```requests``` que no haga comprobaciones del certificado digital. Con eso podremos proceder con la descarga, aunque en teoría es \"peligroso\", porque no podemos tener certeza de que el contenido que bajemos sea legítimo (podrían haber crackeado la web que consultamos, cosa no muy común). Para conseguir solucionar esto solo hay que añadir el parámetro ```verify=False``` en nuestra llamada ```requests.get(...)```. Eso sí, cuando desactivemos la comprobación de certificados nos aparecerá un ```Warning``` avisándonos de los \"peligros\" de no poder comprobarlos. Por ejemplo:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "faee6c23-e99d-4455-9764-7d0a6a7bd5f9",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/zerjillo/anaconda3/envs/cursoAstronomia2/lib/python3.8/site-packages/urllib3/connectionpool.py:1045: InsecureRequestWarning: Unverified HTTPS request is being made to host 'zerjio.com'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings\n",
" warnings.warn(\n"
]
}
],
"source": [
"respuesta = requests.get(\"https://zerjio.com/temp/covid19.html\", verify=False) "
]
},
{
"cell_type": "markdown",
"id": "7defbdc7-953e-4584-9971-63d4076aea11",
"metadata": {},
"source": [
"## Parseando páginas web: trabajar con el ```HTML```\n",
"\n",
"Dentro de la cadena del código HTML podemos buscar la información que nos interese recuperar. Podemos hacerlo de múltiples maneras. Empezaremos con algunas muy básicas y rudimentarias e iremos poco a poco mejorando la manera de acceder.\n",
"\n",
"### Opción 1: Buscaremos a lo \"bestia\" con las funciones de búsqueda de cadenas básicas: ```str.find()```\n",
"\n",
"https://www.journaldev.com/23666/python-string-find\n",
"\n",
"Revisando el código de la página encontramos la fecha de actualización de la misma:\n",
"\n",
" ...\n",
" [Actualizado a 10 de Marzo de 2020 a las 10:10 horas] Basada en la notificación diaria de casos agregados de COVID-19 al Ministerio de Sanidad\n",
" ...\n",
" \n",
"Y nos percatamos que la fecha en formato texto va encerrada entre: `````` y ``````. Busquémosla\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "f47d7547-4a0e-42fe-a3be-d09a2a1b32e8",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"10 de Marzo de 2020\n",
"10:10\n"
]
}
],
"source": [
"import requests # Estas lineas las hemos copiado del anterior Notebook\n",
"respuesta = requests.get(\"https://zerjio.com/temp/covid19.html\") # Esta página reemplaza la anterior\n",
"html = respuesta.content.decode(\"UTF-8\") # https://covid19.isciii.es/\n",
"\n",
"\n",
"cadenaBuscada = ''\n",
"posicionInicio = html.find(cadenaBuscada) + len(cadenaBuscada)\n",
"posicionFinal = html.find('', posicionInicio) # El segundo parámetro de find() es la posición desde\n",
" # donde empezar a buscar el primer parámetro\n",
"\n",
"fecha = html[posicionInicio:posicionFinal]\n",
"\n",
"print(fecha)\n",
"\n",
"# Vamos a hacer lo mismo con la hora\n",
"\n",
"cadenaBuscada = ''\n",
"posicionInicio = html.find(cadenaBuscada) + len(cadenaBuscada)\n",
"posicionFinal = html.find('', posicionInicio)\n",
"\n",
"hora = html[posicionInicio:posicionFinal]\n",
"\n",
"print(hora)"
]
},
{
"cell_type": "markdown",
"id": "b4e3e14f-637b-40f2-b4d3-f4271586a0e8",
"metadata": {},
"source": [
"### Opción 2: Usando expresiones regulares\n",
"\n",
"Las expresiones regulares nos permiten mucha expresividad para localizar elementos dentro de una cadena. Sin embargo en ocasiones su uso puede ser complejo en un documento ```HTML```. Información interesante sobre las expresiones regulares:\n",
"\n",
"https://docs.python.org/3/library/re.html\n",
"\n",
"https://www.w3schools.com/python/python_regex.asp\n",
"\n",
"https://www.guru99.com/python-regular-expressions-complete-tutorial.html\n",
"\n",
"https://www.programiz.com/python-programming/regex\n",
"\n",
"Herramienta online para testear expresiones regulares (seleccionar lenguaje ```Python```):\n",
"\n",
"https://regex101.com/"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "c89001ef-17fb-43e0-abf4-93fd17b4a594",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"10 de Marzo de 2020 - 10:10\n"
]
}
],
"source": [
"# Recuperemos la fecha y hora con expresiones regulares.\n",
"# Usaremos el módulo \"regex\":\n",
"# > conda install -c conda-forge regex\n",
"\n",
"import regex as re\n",
"\n",
"fecha = re.search(r'(.*)', html).group(1)\n",
"hora = re.search(r'(.*)', html).group(1)\n",
"\n",
"print(\"%s - %s\" % (fecha, hora))\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "dfa16370-2ee6-442f-94ef-5766aa82f283",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"10 de Marzo de 2020 a las\n",
" 10:10\n",
" \n",
" \n",
"
\n",
" \n",
"
Dato 1
33
\n",
"
Dato 2
666
\n",
"
Dato 3
7777
\n",
"
Dato 4
99
\n",
" \n",
" \n",
"
\n",
" \n",
"
La que viene a continuación es la tabla de datos de verdad.
\n",
" \n",
" \n",
"
\n",
" \n",
"
\n",
"
Comunidad
\n",
"
Contagiados
\n",
"
Fallecidos
\n",
"
Curados
\n",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"
Andalucía
\n",
"
80
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Aragón
\n",
"
50
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Principado de Asturias
\n",
"
30
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Islas Baleares
\n",
"
10
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Canarias
\n",
"
35
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Cantabria
\n",
"
12
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Castilla y León
\n",
"
60
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Cataluña
\n",
"
110
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Galicia
\n",
"
20
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
C. Valenciana
\n",
"
62
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Extremadura
\n",
"
7
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Comunidad de Madrid
\n",
"
760
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Región de Murcia
\n",
"
7
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Comunidad Foral de Navarra
\n",
"
9
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
País Vasco
\n",
"
190
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
La Rioja
\n",
"
130
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Ceuta
\n",
"
0
\n",
"
\n",
"
\n",
"
\n",
" \n",
"
\n",
"
Melilla
\n",
"
0
\n",
"
\n",
"
\n",
"
\n",
" \n",
" \n",
"
\n",
" \n",
"
Vaya faena nos han hecho los de la página\n"
]
}
],
"source": [
"# Cuidado con las busquedas \"exhaustivas\". \n",
"# Por ejemplo, podemos estar tentados a hacer una búsqueda de todas las fechas, por si hay más de una:\n",
"\n",
"fecha = re.search(r'(.*)', html, re.DOTALL).group(1)\n",
"\n",
"print(fecha)"
]
},
{
"cell_type": "markdown",
"id": "55595a0f-aac3-42ed-a234-55cedc431726",
"metadata": {},
"source": [
"### Opción 3: Usando un parser DOM\n",
"\n",
"_**D**ocument **O**bject **M**odel_ es una interfaz que permite manejar ficheros ```XML``` (y derivados, como ```HTML```) mediante objetos que se encuentran en memoria formando una estructura de árbol (replicando la estructura de las etiquetas). Las interfaces ```DOM``` son normalmente mucho más cómodas e intuitivas de usar que otras alternativas, aunque no funcionan bien para ficheros muy grandes. A continuación veremos unos pocos ejemplos de bibliotecas y herramientas que funcionan con este tipo de interfaz."
]
},
{
"cell_type": "markdown",
"id": "e54f24ad-ecfc-4924-9b5d-49ed34e12469",
"metadata": {},
"source": [
"#### MiniDOM\n",
"Ejemplo de uso de minidom (no es bueno para ```HTML``` que suele no estar bien formado, solo para ```XML```). Por eso vamos a usar un fichero ```RSS``` de noticias\n",
"\n",
"Documentacion de la biblioteca: https://docs.python.org/3.3/library/xml.dom.minidom.html"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "9c5e2165-799c-4e8f-8496-00e6bc5016e8",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" + Un periodista que viajó a Milán para cubrir el Valencia-Atalanta, positivo por coronavirus\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582795523_075914_1582795972_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582795523_075914_1582795972_noticia_normal.jpg\n",
" + Mapa de la expansión y claves para entender el coronavirus de Wuhan\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582712658_011286_1582742390_miniatura_normal.png\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582712658_011286_1583145456_portadilla_normal.png\n",
" + El turismo italiano se resiente; España mira expectante\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582751511_964259_1582759340_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582751511_964259_1582759340_noticia_normal.jpg\n",
" - https://elpaisfs.prisasd.com/elpaistop/multimedia/20202/27/f6f986136f7d70e226ac5f38df9fa88a_video_1800.mp4\n",
" + “La magnitud del problema del coronavirus no será diferente a una gripe”\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582744701_468958_1582744844_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582744701_468958_1582797813_noticia_normal.jpg\n",
" + Seis italianos encerrados por partida doble\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582745125_354016_1582747646_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582745125_354016_1582747646_noticia_normal.jpg\n",
" + Trump nombra al vicepresidente Pence a cargo de la crisis del coronavirus\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582762594_400436_1582763694_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582762594_400436_1582763694_noticia_normal.jpg\n",
" - https://elpaisfs.prisasd.com/elpaistop/multimedia/20202/27/202002279361360_1582792664_video_1800.mp4\n",
" + El coronavirus de Wuhan | Japón cerrará todos sus centros escolares hasta fin de marzo\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582772469_101682_1582773414_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582772469_101682_1582786463_noticia_normal.jpg\n",
" + El Gobierno salva el primer escollo de los Presupuestos gracias a ERC\n",
" - https://ep00.epimg.net/politica/imagenes/2020/02/27/actualidad/1582790343_062149_1582797637_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/politica/imagenes/2020/02/27/actualidad/1582790343_062149_1582807919_noticia_normal.jpg\n",
" - https://elpaisfs.prisasd.com/elpaistop/multimedia/20202/27/bd6f863b8c606b83aa4a190909cad1d2_video_1800.mp4\n",
" + La mesa de diálogo se reunirá mensualmente y los acuerdos serán “en el marco de la seguridad jurídica”\n",
" - https://ep00.epimg.net/politica/imagenes/2020/02/26/actualidad/1582729437_069559_1582743257_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/politica/imagenes/2020/02/26/actualidad/1582729437_069559_1582743257_noticia_normal.jpg\n",
" - https://elpaisfs.prisasd.com/elpaistop/multimedia/20202/27/9265b903ba4c44f3771b64a42fe06095_video_1800.mp4\n",
" + Así avanzan las encuestas en Galicia y País Vasco\n",
" - https://ep00.epimg.net/politica/imagenes/2020/02/26/actualidad/1582705222_037590_1582705381_noticia_normal.jpg\n",
" + Ciudadanos pagaba un sueldo a un vocal de la Junta Electoral Central que resolvió recursos del partido\n",
" - https://ep00.epimg.net/politica/imagenes/2019/11/17/actualidad/1574018167_006384_1574018434_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/politica/imagenes/2019/11/17/actualidad/1574018167_006384_1574018434_noticia_normal.jpg\n",
" - https://elpaisfs.prisasd.com/elpaistop/multimedia/20202/27/20200227164217541_1582818245_video_1800.mp4\n",
" + 50 antiguos ministros y dirigentes europeos se pronuncian contra el plan de Trump para Palestina\n",
" - https://ep00.epimg.net/internacional/imagenes/2020/02/26/actualidad/1582750435_447092_1582751809_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/internacional/imagenes/2020/02/26/actualidad/1582750435_447092_1582751809_noticia_normal.jpg\n",
" + Plácido Domingo anula sus representaciones en el Real antes de que el teatro las cancelara\n",
" - https://ep00.epimg.net/cultura/imagenes/2020/02/27/actualidad/1582789321_585769_1582794632_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/cultura/imagenes/2020/02/27/actualidad/1582789321_585769_1582790092_noticia_normal.jpg\n",
" - https://elpaisfs.prisasd.com/elpaistop/multimedia/20202/27/86e4da93f1d390d4fd81392d9f903c91_video_1800.mp4\n",
" + Así gestionan nuestros vecinos europeos la expansión de Airbnb\n",
" - https://ep00.epimg.net/internacional/imagenes/2020/02/21/sonar_europe/1582302332_702790_1582307413_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/internacional/imagenes/2020/02/21/sonar_europe/1582302332_702790_1582307413_noticia_normal.jpg\n",
" + La Fiscalía se querella contra una mujer por tuitear un vídeo falso de menores migrantes\n",
" - https://ep00.epimg.net/ccaa/imagenes/2018/11/24/madrid/1543077391_578679_1543078301_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/ccaa/imagenes/2018/11/24/madrid/1543077391_578679_1543078301_noticia_normal.jpg\n",
" + China desvela de qué está hecha la cara oculta de la Luna\n",
" - https://ep00.epimg.net/elpais/imagenes/2020/02/25/ciencia/1582651238_235155_1582741504_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/elpais/imagenes/2020/02/25/ciencia/1582651238_235155_1582741504_noticia_normal.jpg\n",
" + Especial EL PAÍS en Arco | Muntadas: “La sociedad ha degradado las palabras”\n",
" - https://ep00.epimg.net/elpais/imagenes/2020/02/27/actualidad/1582803771_531979_1582803808_portada_normal.jpg\n",
" + La historia de Duralex, una vajilla tan irrompible como nuestra nostalgia\n",
" - https://ep00.epimg.net/elpais/imagenes/2020/02/27/portada/1582804176_187015_1582804289_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/verne/imagenes/2020/02/25/articulo/1582628993_071991_1582631824_noticia_normal.jpg\n",
" + ¿Por qué los mosquitos se ceban con nuestros tobillos?\n",
" - https://ep00.epimg.net/elpais/imagenes/2020/02/27/ciencia/1582797400_512615_1582797833_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/elpais/imagenes/2020/02/27/ciencia/1582797400_512615_1582797833_noticia_normal.jpg\n",
" + Consumo da la razón a los clientes de Fnac que compraron un móvil 575 euros más barato por un error\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582796975_880373_1582799022_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582796975_880373_1582800034_noticia_normal.jpg\n",
" + Javier Bardem: “Hoy hay algún Hernán Cortés en el Congreso”\n",
" - https://ep00.epimg.net/cultura/imagenes/2020/02/26/actualidad/1582734306_817032_1582749328_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/cultura/imagenes/2020/02/26/actualidad/1582734306_817032_1582749299_noticia_normal.jpg\n"
]
}
],
"source": [
"import xml.dom.minidom\n",
"\n",
"url = 'http://ep00.epimg.net/rss/elpais/portada.xml'\n",
"rss = requests.get(url).content.decode(\"UTF-8\")\n",
"\n",
"dom = xml.dom.minidom.parseString(rss)\n",
"\n",
"# Obtenemos todas las etiquetas \"item\"\n",
"items = dom.getElementsByTagName(\"item\")\n",
"\n",
"# Para cada etiqueta mostraremos el título de la noticia asociada y la url de la imagen asociada (si la tiene)\n",
"for item in items:\n",
" titulo = item.getElementsByTagName(\"title\")\n",
" \n",
" print(\" + \" + titulo[0].firstChild.nodeValue) # Detalle \"peliagudo\", el texto de dentro de una etiqueta \n",
" # es considerado un hijo. De hecho una etiqueta puede tener\n",
" # varios hijos de \"texto\". Ejemplo:\n",
" # \n",
" # Esto es texto\n",
" # \n",
" # Más texto\n",
" # \n",
" #\n",
" # El elemento \"etiquetaConTexto\" tiene tres hijos:\n",
" # + Hijo 1: de tipo texto: \"\\n Esto es texto\\n \"\n",
" # + Hijo 2: etiqueta \"etiquetaHijo\"\n",
" # + Hijo 3: de tipo texto: \"\\n Más text\\n \"\n",
"\n",
"# En este ejemplo, las urls de las imágenes asociadas a un item están en la etiqueta \"enclosure\", atributo \"url\":\n",
"\n",
" enclosures = item.getElementsByTagName(\"enclosure\")\n",
" \n",
" for e in enclosures:\n",
" print(\" - \" + e.getAttribute('url'))"
]
},
{
"cell_type": "markdown",
"id": "5ace3325-90a3-4f1b-8918-d05acd118a29",
"metadata": {},
"source": [
"#### ```DOM``` parser ```lxml.etree```\n",
"\n",
"Esta ```API``` es más sencilla y está más adaptada a ```Python```:\n",
"\n",
"+ Los elementos son listas (con lo que podemos acceder a sus hijos por índices)\n",
"+ Permite fácilmente modificar los elementos del ```DOM``` (lo mismo no es muy útil si estamos solo obteniendo información, pero vete tu a saber).\n",
"+ Los atributos de un elemento son un diccionario que está en elemento.attrib, con lo que acceder a ellos es muy \"natural\".\n",
"\n",
"\n",
"Tutorial: https://lxml.de/tutorial.html\n",
"\n",
"Para instalar el módulo:\n",
"\n",
"```\n",
"> conda install -c anaconda lxml\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "7473dd94-8255-48c0-b189-093d851153d9",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" + Un periodista que viajó a Milán para cubrir el Valencia-Atalanta, positivo por coronavirus\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582795523_075914_1582795972_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582795523_075914_1582795972_noticia_normal.jpg\n",
" + Mapa de la expansión y claves para entender el coronavirus de Wuhan\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582712658_011286_1582742390_miniatura_normal.png\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582712658_011286_1583145456_portadilla_normal.png\n",
" + El turismo italiano se resiente; España mira expectante\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582751511_964259_1582759340_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582751511_964259_1582759340_noticia_normal.jpg\n",
" - https://elpaisfs.prisasd.com/elpaistop/multimedia/20202/27/f6f986136f7d70e226ac5f38df9fa88a_video_1800.mp4\n",
" + “La magnitud del problema del coronavirus no será diferente a una gripe”\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582744701_468958_1582744844_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582744701_468958_1582797813_noticia_normal.jpg\n",
" + Seis italianos encerrados por partida doble\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582745125_354016_1582747646_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/26/actualidad/1582745125_354016_1582747646_noticia_normal.jpg\n",
" + Trump nombra al vicepresidente Pence a cargo de la crisis del coronavirus\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582762594_400436_1582763694_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582762594_400436_1582763694_noticia_normal.jpg\n",
" - https://elpaisfs.prisasd.com/elpaistop/multimedia/20202/27/202002279361360_1582792664_video_1800.mp4\n",
" + El coronavirus de Wuhan | Japón cerrará todos sus centros escolares hasta fin de marzo\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582772469_101682_1582773414_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582772469_101682_1582786463_noticia_normal.jpg\n",
" + El Gobierno salva el primer escollo de los Presupuestos gracias a ERC\n",
" - https://ep00.epimg.net/politica/imagenes/2020/02/27/actualidad/1582790343_062149_1582797637_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/politica/imagenes/2020/02/27/actualidad/1582790343_062149_1582807919_noticia_normal.jpg\n",
" - https://elpaisfs.prisasd.com/elpaistop/multimedia/20202/27/bd6f863b8c606b83aa4a190909cad1d2_video_1800.mp4\n",
" + La mesa de diálogo se reunirá mensualmente y los acuerdos serán “en el marco de la seguridad jurídica”\n",
" - https://ep00.epimg.net/politica/imagenes/2020/02/26/actualidad/1582729437_069559_1582743257_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/politica/imagenes/2020/02/26/actualidad/1582729437_069559_1582743257_noticia_normal.jpg\n",
" - https://elpaisfs.prisasd.com/elpaistop/multimedia/20202/27/9265b903ba4c44f3771b64a42fe06095_video_1800.mp4\n",
" + Así avanzan las encuestas en Galicia y País Vasco\n",
" - https://ep00.epimg.net/politica/imagenes/2020/02/26/actualidad/1582705222_037590_1582705381_noticia_normal.jpg\n",
" + Ciudadanos pagaba un sueldo a un vocal de la Junta Electoral Central que resolvió recursos del partido\n",
" - https://ep00.epimg.net/politica/imagenes/2019/11/17/actualidad/1574018167_006384_1574018434_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/politica/imagenes/2019/11/17/actualidad/1574018167_006384_1574018434_noticia_normal.jpg\n",
" - https://elpaisfs.prisasd.com/elpaistop/multimedia/20202/27/20200227164217541_1582818245_video_1800.mp4\n",
" + 50 antiguos ministros y dirigentes europeos se pronuncian contra el plan de Trump para Palestina\n",
" - https://ep00.epimg.net/internacional/imagenes/2020/02/26/actualidad/1582750435_447092_1582751809_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/internacional/imagenes/2020/02/26/actualidad/1582750435_447092_1582751809_noticia_normal.jpg\n",
" + Plácido Domingo anula sus representaciones en el Real antes de que el teatro las cancelara\n",
" - https://ep00.epimg.net/cultura/imagenes/2020/02/27/actualidad/1582789321_585769_1582794632_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/cultura/imagenes/2020/02/27/actualidad/1582789321_585769_1582790092_noticia_normal.jpg\n",
" - https://elpaisfs.prisasd.com/elpaistop/multimedia/20202/27/86e4da93f1d390d4fd81392d9f903c91_video_1800.mp4\n",
" + Así gestionan nuestros vecinos europeos la expansión de Airbnb\n",
" - https://ep00.epimg.net/internacional/imagenes/2020/02/21/sonar_europe/1582302332_702790_1582307413_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/internacional/imagenes/2020/02/21/sonar_europe/1582302332_702790_1582307413_noticia_normal.jpg\n",
" + La Fiscalía se querella contra una mujer por tuitear un vídeo falso de menores migrantes\n",
" - https://ep00.epimg.net/ccaa/imagenes/2018/11/24/madrid/1543077391_578679_1543078301_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/ccaa/imagenes/2018/11/24/madrid/1543077391_578679_1543078301_noticia_normal.jpg\n",
" + China desvela de qué está hecha la cara oculta de la Luna\n",
" - https://ep00.epimg.net/elpais/imagenes/2020/02/25/ciencia/1582651238_235155_1582741504_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/elpais/imagenes/2020/02/25/ciencia/1582651238_235155_1582741504_noticia_normal.jpg\n",
" + Especial EL PAÍS en Arco | Muntadas: “La sociedad ha degradado las palabras”\n",
" - https://ep00.epimg.net/elpais/imagenes/2020/02/27/actualidad/1582803771_531979_1582803808_portada_normal.jpg\n",
" + La historia de Duralex, una vajilla tan irrompible como nuestra nostalgia\n",
" - https://ep00.epimg.net/elpais/imagenes/2020/02/27/portada/1582804176_187015_1582804289_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/verne/imagenes/2020/02/25/articulo/1582628993_071991_1582631824_noticia_normal.jpg\n",
" + ¿Por qué los mosquitos se ceban con nuestros tobillos?\n",
" - https://ep00.epimg.net/elpais/imagenes/2020/02/27/ciencia/1582797400_512615_1582797833_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/elpais/imagenes/2020/02/27/ciencia/1582797400_512615_1582797833_noticia_normal.jpg\n",
" + Consumo da la razón a los clientes de Fnac que compraron un móvil 575 euros más barato por un error\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582796975_880373_1582799022_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/sociedad/imagenes/2020/02/27/actualidad/1582796975_880373_1582800034_noticia_normal.jpg\n",
" + Javier Bardem: “Hoy hay algún Hernán Cortés en el Congreso”\n",
" - https://ep00.epimg.net/cultura/imagenes/2020/02/26/actualidad/1582734306_817032_1582749328_miniatura_normal.jpg\n",
" - https://ep00.epimg.net/cultura/imagenes/2020/02/26/actualidad/1582734306_817032_1582749299_noticia_normal.jpg\n"
]
}
],
"source": [
"# Repetimos el ejercicio anterior pero con el parser DOM lxml.etree\n",
"from lxml import etree\n",
"\n",
"tree = etree.parse(url)\n",
"\n",
"raiz = tree.getroot()\n",
"\n",
"# Iteramos por todos los descendientes de raiz que sean \"item\"\n",
"\n",
"for item in raiz.iter(\"item\"):\n",
" for hijo in item.iter(\"title\"):\n",
" print(\" + \" + hijo.text)\n",
" \n",
" for hijo in item.iter(\"enclosure\"):\n",
" print(\" - \" + hijo.attrib['url'])\n",
" "
]
},
{
"cell_type": "markdown",
"id": "865d1142-839e-463b-8619-07f6c5662f83",
"metadata": {},
"source": [
"### Opción 4: Usando ```XPath``` para localizar elementos fácilmente\n",
"\n",
"```XPath``` (*XML Path Language*) es un lenguaje que permite construir expresiones que recorren y procesan un documento ```XML```. Permite buscar y seleccionar teniendo en cuenta la estructura jerárquica del ```XML```.\n",
"\n",
"+ https://es.wikipedia.org/wiki/XPath\n",
"+ https://www.w3schools.com/xml/xpath_syntax.asp"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "1337f87d-8f8d-460f-ac49-41947cb310f3",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# Replicaremos el ejemplo de la gráfica de casos de COVID-19 de manera mucho más simple\n",
"from lxml import etree\n",
"from io import StringIO, BytesIO\n",
"import matplotlib.pyplot as plt\n",
"\n",
"parserHTML = etree.HTMLParser()\n",
"\n",
"# Recuerda que html se inicializó mucho antes con el contenido de la página https://covid19.isciii.es/\n",
"tree = etree.parse(StringIO(html), parserHTML)\n",
"\n",
"tablas = tree.xpath('//table') # Nos devuelve todos los elementos \"table\" en cualquier sitio del documento\n",
" # En nuestro caso habrá devuelto 2 tablas\n",
"\n",
"# Nos interesa la segunda tabla de la página \n",
"tabla = tablas[1]\n",
"\n",
"comunidades = []\n",
"casos = []\n",
"\n",
"filas = tabla.xpath('tbody/tr') # Buscamos todos los
que estén dentro de
en la tabla\n",
"\n",
"for f in filas:\n",
" comunidades.append(f[0].text)\n",
" casos.append(int(f[1].text))\n",
" \n",
" \n",
"# Creamos el gráfico de barras\n",
"plt.bar(comunidades, casos)\n",
"# Rotation of the bars names\n",
"plt.xticks(rotation=90)\n",
"# Show graphic\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "ad4a679b-058c-44a5-be34-7a8315adbd0f",
"metadata": {},
"source": [
"***\n",
"**Ejercicio D.1:** Obtener un campo del Sloan Digital Sky Survey (SDSS)\n",
"\n",
"El [SDSS](https://www.sdss.org/) tiene multitud de herramientas que permiten la obtención de datos e imágenes del cielo. Por ejemplo en https://dr12.sdss.org/fields/ podemos descargar campos concretos utilizando las coordenadas del cielo que nos interesan. Jugando un poco con el formulario de esa página \"descubrimos\" que podemos obtener el campo mediante el uso de la siguiente URL que tiene como parámetros la ascension recta (ra) y la declinación (dec):\n",
"\n",
"https://dr12.sdss.org/fields/raDec?ra=250.423475&dec=36.461319\n",
"\n",
"Programemos una función para descargar la imagen que corresponde a cualquier coordenada que nos interese:\n"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "c7ee8236-5788-4481-b783-d189052d4d35",
"metadata": {},
"outputs": [],
"source": [
"# Tu código aquí\n",
" \n",
"# descargaSDSS(250.423475, 36.461319, \"m13.jpg\")\n",
"\n",
"# print(\"Descarga realizada\")"
]
},
{
"cell_type": "markdown",
"id": "91c52100-0d0d-4b81-8f3c-a41d832828d5",
"metadata": {},
"source": [
"***\n",
"**Ejecicio D.2:** Astronomy Picture of the Day (APOD) (desde la página oficial)\n",
"\n",
"Queremos hacer un script que descargue la imagen astronómica del día y la ponga de fondo de escritorio.\n",
"\n",
"La función de poner como fondo de escritorio depende del sistema operativo, por lo que habrá que descomentar la función ```setWallpaper``` que corresponda en el código de más abajo.\n",
"\n",
"Para conseguir nuestro objetivo tendremos que descargar la página del APOD y analizar el código ```HTML``` para dar con la URL de la imagen que queremos descargar."
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "15a657b1-e3dc-4c24-a304-ee9f2cd08c55",
"metadata": {},
"outputs": [],
"source": [
"#import dbus # conda install -c conda-forge dbus-python SOLO PARA Linux / KDE\n",
"\n",
"# Para Linux con KDE\n",
"#def setWallpaper(filepath):\n",
"# plugin = 'org.kde.image'\n",
"# jscript = \"\"\"\n",
"# var allDesktops = desktops();\n",
"# print (allDesktops);\n",
"# for (i=0;i\n",
"...\n",
" \n",
" \n",
" \t\t\t\t \t\t\t\t\t\t\t\t \t\t\t\t\t\t\t \t\t\t\t\t\t\n",
" \n",
"...\n",
"\n",
"```\n",
"Vemos que la petición que se realizar es con el método ```POST``` y que hay varios campos que se pueden rellenar: ```search``` (el campo de búsqueda en sí) y ```buscar``` (que es un radio button con dos opciones: ```msc``` o ```internet```). Además la petición del formulario se va a hacer a la misma página: ```action=\"iniciar.do\"```.\n"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "c1ed95cf-a503-4067-8d00-3f99da6b30f8",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\t\n",
"\t\t\n",
"\t\t\tMinisterio de Sanidad - Buscador\n",
"\t\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\t\n",
"\t\t\n",
"\t\t\t\n",
"\t\t\n",
"\t\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t \n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t \n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t\t\n",
"\t \n",
"\t \n",
"\t\n",
"\t\t\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"
\n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
"\n",
"\n"
]
}
],
"source": [
"print(soup.prettify()) # Simplemente nos permite ver el documento mejor formatado (indentaciones, espacios en blanco...)\n"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "3a935e9d-6910-43b6-a558-575f2c885ab9",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[Ministerio de Sanidad, Consumo y Bienestar Social - Profesionales - Enfermedad por nuevo coronavirus, COVID\n",
"-19]\n",
"https://www.mscbs.gob.es/profesionales/saludPublica/ccayes/alertasActual/nCov/home.htm\n",
"[Ministerio de Sanidad - Profesionales - Mapa del estado de la expedición del Certificado COVID\n",
" Digital de la UE en Comunidades Autónomas]\n",
"https://www.mscbs.gob.es/profesionales/saludPublica/ccayes/alertasActual/nCov/ccd/ccaa.htm\n",
"[Ministerio de Sanidad]\n",
"https://www.mscbs.gob.es/home.htm\n",
"[Ministerio de Sanidad, Consumo y Bienestar Social - Profesionales - Información para la ciudadanía - Coronavirus]\n",
"https://www.mscbs.gob.es/profesionales/saludPublica/ccayes/alertasActual/nCov/ciudadania.htm\n",
"[Ministerio de Sanidad, Consumo y Bienestar Social - Profesionales - Viajes y COVID\n",
"-19]\n",
"https://www.mscbs.gob.es/profesionales/saludPublica/ccayes/alertasActual/nCov/spth.htm\n",
"[Presentación de PowerPoint]\n",
"https://www.mscbs.gob.es/servCiudadanos/ayudas/pes/Actualizacion_PES_MDSA2030_2020.pdf\n",
"[Ministerio de Sanidad - Ministerio - Plan de Recuperación, Transformación y Resiliencia]\n",
"https://www.mscbs.gob.es/organizacion/recuTransResilencia/home.htm\n",
"[¿Sabes qué es la COVID\n",
" persistente o \"Long COVID\n",
"\"?]\n",
"https://www.mscbs.gob.es/profesionales/saludPublica/ccayes/alertasActual/nCov/documentos/COVID_persistente.pdf\n",
"[Cómo identificar a tus contactos estrechos]\n",
"https://www.mscbs.gob.es/profesionales/saludPublica/ccayes/alertasActual/nCov/documentos/COVID-19_Como_identificare_tus_contactos_estrechos.pdf\n",
"[Ministerio de Sanidad, Consumo y Bienestar Social - Profesionales - Salud pública - Prevención de la salud - Vacunaciones - Programa vacunación - Vacunas COVID\n",
"-19]\n",
"https://www.mscbs.gob.es/profesionales/saludPublica/prevPromocion/vacunaciones/covid19/vacunasCovid19.htm\n"
]
}
],
"source": [
"# Buscamos un
\n",
"\n",
"cuadroResultados = soup.find('div', {\"class\": \"capaCentroBuscador\"})\n",
"\n",
"# De ese cuadro extraemos todos los
(cada uno tiene un resultado de la búsqueda)\n",
"\n",
"resultados = cuadroResultados.find_all('li')\n",
"\n",
"for r in resultados:\n",
" # Dentro de cada