{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "
\n", "
\n", " \n", "
\n", "
\n", "\n", "

Máster Propio en Data Science y Big Data (IV Edición)

\n", "

Arquitecturas y Paradigmas para Ciencia del Dato (APCD)

\n", "

Técnicas de obtención de datos

\n", "
\n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Instructor\n", "
\n", "
\n", "
\n", " \n", "
\n", "
\n", " Javier de la Rosa, versae@linhd.uned.es, @versae\n", "
\n", "
\n", "
\n", " Postdoctoral Researcher en el Proyecto Europeo POSTDATA de la UNED\n", "
\n", " PhD, Estudios Hispánicos y Humanidades Digitales, University of Western Ontario, Canada\n", "
\n", " Máster en Inteligencia Artificial, Universidad de Sevilla, España\n", "
\n", "
\n", " Ex-Ingeniero de Investigación en la Stanford University, California\n", "
\n", " Ex-Director Técnico del laboratorio de investigación CulturePlex Lab en la University of Western Ontario, Canada\n", "
\n", "
\n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Índice\n", "\n", "1. **Introducción**\n", "2. Repositorios\n", "3. Scraping\n", "4. Extracción de información usando expresiones regulares\n", "5. Conclusiones\n", "6. Bibliografı́a" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Introducción\n", "\n", "La recolección de datos es el proceso de recopilación y medición de la información sobre un conjunto de variables especı́ficas.\n", "\n", "Aquı́ surge una pregunta, ¿necesitamos definir un modelo de datos para recolectar los datos asociados?\n", "\n", "El primer paso es saber qué se quiere obtener como resultado y qué variables nos harı́an falta." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Introducción\n", "\n", "Existen infinidad de opciones para recolectar datos dependiendo del proyecto y de la disciplina en la que trabajemos. Hoy en dı́a hay un punto común a todos estos procesos (y cada vez más necesario), es\n", "la digitalización de la información.\n", "\n", "Por dar una definición breve y simple, podrı́amos llamar digitalización al proceso de transformación de información \n", "analógica a formato digital. Esto facilita tareas como el almacenamiento, consulta, gestión, etc." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Introducción\n", "\n", "Partiendo del ámbito de la ciencia de datos, vamos a ver cuatro tipos de procedimientos en cuanto a recolección u obtención de datos se refiere:\n", "- Repositorios\n", "- Scraping\n", "- Extracción de información usando expresiones regulares\n", "- APIs" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Índice\n", "\n", "1. Introducción\n", "2. **Repositorios**\n", "3. Scraping\n", "4. Extracción de información usando expresiones regulares\n", "5. Conclusiones\n", "6. Bibliografı́a" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Repositorios\n", "Un repositorio o depósito es un sitio centralizado donde se almacena y mantiene información digital, habitualmente bases de\n", "datos o archivos informáticos. Los datos almacenados en un repositorio pueden distribuirse a través de una red informática (Internet) o de un medio fı́sico.\n", "\n", "Nosotros, principalmente, usaremos los repositorios para dos tareas:\n", "- Para almacenar y gestionar el código de nuestro proyecto\n", "- Para almacenar, descargar y gestionar los conjuntos de datos con los que trabajamos\n", "- Para facilitar el intercambio de datos" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Repositorios\n", "\n", "- Pueden ser de acceso público o estar protegidos y necesitar de una autentificación previa\n", "- Los repositorios más conocidos son los de carácter académico (investigación) e institucional (datos abiertos)\n", "- Los repositorios suelen contar con sistemas de respaldo y mantenimiento preventivo y correctivo (tolerancia a fallos)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Formatos\n", "- Generales: CSV, TXT, WORD, JSON, XML, XLS\n", "- Optimizados: HDF5, Parquet, Arrow\n", "- Semánticos (LOD, SPARQL): RDF, Turtle, N3, JSON-LD" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "![Ejemplo de Turtle](https://miro.medium.com/max/573/1*WgqGqn1tcd_aSpQbN45aBw.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Repositorios de datos\n", "- https://www.kaggle.com/datasets\n", "- http://www.kdnuggets.com/datasets/index.html\n", "- https://archive.ics.uci.edu/ml/datasets.php\n", "- https://github.com/caesar0301/awesome-public-datasets\n", "- http://sevilla.idesevilla.opendata.arcgis.com/\n", "- http://datosabiertos.sevilla.org/\n", "- http://datos.madrid.es/portal/site/egob/" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Repositorios de datos abiertos enlazados (LOD)\n", "- http://datos.bne.es/inicio.html\n", "- https://bnb.data.bl.uk/\n", "- https://www.europeana.eu/portal/en\n", "- https://wiki.dbpedia.org/\n", "- https://m.wikidata.org/wiki/Wikidata:Main_Page" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Repositorios de código\n", "- https://bitbucket.org/\n", "- https://www.github.com/\n", "- https://sourceforge.net/\n", "- https://launchpad.net/" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Índice\n", "1. Introducción\n", "2. Repositorios\n", "3. **Scraping**\n", "4. Extracción de información usando expresiones regulares\n", "5. Conclusiones\n", "6. Bibliografı́a" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping\n", "\n", "Web scraping es una técnica que utiliza programas software para extraer información de sitios web.\n", "\n", "Usualmente, estos programas simulan la navegación de un humano en Internet ya sea utilizando el protocolo HTTP manualmente, o incrustando un navegador en una aplicación." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping\n", "\n", "Como curiosidad: un concepto muy relacionado con el web scraping es la indexación que se produce en Internet. La indexación se lleva a cabo por programas (llamados spiders o crawlers) que rastrean y navegan automáticamente por toda la web. Esta técnica es la que adoptan la mayorı́a de los motores de búsqueda.\n", "\n", "Desde nuestro punto de vista, el web scraping se enfoca más en la transformación de datos sin estructura en la web en datos estructurados que pueden ser almacenados y analizados. Un campo en el que esta técnica es muy utilizada es el periodismo de datos (social media)." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping\n", "\n", "Para llevar a cabo técnicas de scraping tenemos que tener en cuenta, esencialmente, dos puntos fundamentales:\n", "- Acceso al código HTML de la página (hay muchas formas de conseguir esto)\n", "- Un lenguaje de programación para obtener los datos que nos interesan\n", "- En nuestro caso, usaremos la consola de desarrollo de Firefox/Google Chrome y Python." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping\n", "\n", "![Diagrama de una petición HTTP](http://www.hermosaprogramacion.com/wp-content/uploads/2015/01/http-protocolo-peticion.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping\n", "\n", "![HTTP](https://www.ntu.edu.sg/home/ehchua/programming/webprogramming/images/HTTP.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping\n", "\n", "![HTTP](https://www.ntu.edu.sg/home/ehchua/programming/webprogramming/images/HTTP_Steps.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - Uniform Resource Locator (URL)\n", "\n", "```\n", "protocol://hostname:port/path-and-file-name\n", "```\n", "- Protocol: HTTP, FTP, telnet, etc.\n", "- Hostname: DNS domain name (e.g., www.nowhere123.com) o dirección IP (e.g., 192.128.1.2).\n", "- Port: Puerto TCP de escucha.\n", "- Path: Ruta del recurso en el servidor.\n", "\n", "Ejemplo: `http://www.nowhere123.com/docs/index.html`" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - Uniform Resource Identifier (URI)\n", "\n", "Una URI es una forma más general de URL. Añade un par de campos más.\n", "\n", "```\n", "protocol://hostname:port/path-and-file-name?query#fragment\n", "```\n", "- Fragment: Porción dentro del recurso.\n", "- Query: Parámetros de la petición, e.g., `name=Ana&age=30`\n", "\n", "Ejemplo:\n", "```\n", "http://www.nowhere123.com/docs/index.html?order=1#table1\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - HTTP Request\n", "```\n", "GET /docs/index.html HTTP/1.1\n", "Host: www.nowhere123.com\n", "Accept: image/gif, image/jpeg, */*\n", "Accept-Language: en-us\n", "Accept-Encoding: gzip, deflate\n", "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\n", "\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - HTTP Request\n", "\n", "![reques](https://www.ntu.edu.sg/home/ehchua/programming/webprogramming/images/HTTP_RequestMessageExample.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - HTTP Request Methods\n", "\n", "- GET: Un cliente puede utilizar la petición GET para obtener un recurso web del servidor.\n", "- HEAD: Un cliente puede utilizar la solicitud HEAD para obtener el encabezado que habría obtenido una solicitud GET. Dado que la cabecera contiene la última fecha modificada de los datos, se puede utilizar para comparar con la copia de la caché local.\n", "- POST: Se utiliza para enviar datos al servidor web.\n", "- PUT: Pide al servidor que almacene los datos.\n", "- DELETE: Pide al servidor que borre los datos." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - HTTP Response\n", "```\n", "HTTP/1.1 200 OK\n", "Date: Sun, 18 Oct 2009 08:56:53 GMT\n", "Server: Apache/2.2.14 (Win32)\n", "Last-Modified: Sat, 20 Nov 2004 07:16:26 GMT\n", "ETag: \"10000000565a5-2c-3e94b66c2e680\"\n", "Accept-Ranges: bytes\n", "Content-Length: 44\n", "Connection: close\n", "Content-Type: text/html\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "```\n", "

It works!

\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - HTTP Response\n", "\n", "![response](https://www.ntu.edu.sg/home/ehchua/programming/webprogramming/images/HTTP_ResponseMessageExample.png)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - HTTP Response Status Codes\n", "\n", "- 1xx (Informativo): Solicitud recibida, el servidor continúa el proceso.\n", "- 2xx (Éxito): La solicitud fue recibida, comprendida, aceptada y atendida con éxito.\n", "- 3xx (Redirección): Se deben tomar más medidas para completar la solicitud.\n", "- 4xx (Error de cliente): La petición contiene una sintaxis errónea o no puede ser entendida.\n", "- 5xx (Error del servidor): El servidor no cumplió con una petición aparentemente válida." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - HTTP Response Status Codes\n", "\n", "Algunos de los códigos de estado más comunes son:\n", "- 100 Continuar: El servidor recibió la solicitud y en el proceso de dar la respuesta.\n", "- 200 OK: La solicitud se ha cumplido.\n", "- 301 Movido permanentemente.\n", "- 302 Encontrado y redirigido (o Movido temporalmente)." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - HTTP Response Status Codes\n", "\n", "Algunos de los códigos de estado más comunes son:\n", "- 400 Bad Request: El servidor no pudo interpretar o entender la petición, probablemente un error de sintaxis en el mensaje de petición.\n", "- 401 Se requiere autenticación.\n", "- 403 Prohibido.\n", "- 404 No encontrado." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - HTTP Response Status Codes\n", "\n", "Algunos de los códigos de estado más comunes son:\n", "- 500 Error interno del servidor: El servidor está confundido, a menudo causado por un error en el programa del lado del servidor que responde a la petición.\n", "- 502 Bad Gateway: Proxy o Gateway indica que recibe una mala respuesta del servidor de entrada.\n", "- 503 Servicio no disponible: El servidor no puede responder debido a sobrecargas o mantenimiento. El cliente puede volver a intentarlo más tarde." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scrapping - HTTP\n", "!!pip install requests\n", "\n", "import requests\n", "\n", "response = requests.get(\"https://httpbin.org/html\")\n", "print(response.status_code, response.ok)\n", "print(response.headers)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scrapping - HTTP\n", "\n", "print(response.text)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "
\n", "

\n", "Ejercicio\n", "

\n", "

\n", "Escriba una función, `status(urls)`, que dada una lista de de URLs en `urls`, devuelve un diccionario usando como claves los códigos de estado de las peticiones HTTP y como valores la lista correspondiente de URLs que lo producen.\n", "\n", "Por ejemplo:\n", "\n", "urls = [\n", " \"https://httpbin.org/\",\n", " \"https://httpbin.org/404\",\n", " \"https://www.eltiempo.es/\",\n", " \"https://www.pixar.com/cer890h76yt89j768y6590g43e9f4efv54er\",\n", "]\n", "status(urls)\n", "\n", " \n", "Debería producir\n", "\n", "\n", "{200: ['https://httpbin.org/', 'https://www.eltiempo.es/'],\n", " 404: ['https://httpbin.org/404', 'https://www.pixar.com/cer890h76yt89j768y6590g43e9f4efv54er']}\n", "\n", "

\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "urls = [\n", " \"https://httpbin.org/\",\n", " \"https://httpbin.org/404\",\n", " \"https://www.eltiempo.es/\",\n", " \"https://www.pixar.com/cer890h76yt89j768y6590g43e9f4efv54er\",\n", "]\n", "\n", "def status(urls):\n", " # Escriba su código aquí\n", " pass\n", " \n", "\n", "status(urls)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "```\n", "{200: ['https://httpbin.org/', 'https://www.eltiempo.es/'],\n", " 404: ['https://httpbin.org/404',\n", " 'https://www.pixar.com/cer890h76yt89j768y6590g43e9f4efv54er']}\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "
\n", "

\n", "Ejercicio\n", "

\n", "

\n", "Escriba el código necesario para descargar el contenido alojado en `https://httpbin.org/html` y devolver las 10 palabras más comunes y su frecuencia absoluta (total de apariciones)\n", "

\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "url = \"https://httpbin.org/html\"\n", "# Escriba aquí su solución" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "```\n", "[('', 42),\n", " ('the', 34),\n", " ('and', 25),\n", " ('of', 22),\n", " ('to', 17),\n", " ('his', 14),\n", " ('a', 14),\n", " ('in', 11),\n", " ('had', 8),\n", " ('old', 6)]\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - HTML\n", "\n", "Idealmente, todas las páginas web siguen una estructura bien definida semánticamente de acuerdo al Document Object Model (DOM). Esto nos permitirı́a extraer datos utilizando reglas como encontrar el elemento `

` cuyo id es \"subject\" y devolver el \"texto\" que contiene.\n", "\n", "En el mundo real, el código HTML de una web no tiene por qué estar bien formado y anotado. Esto significa que necesitaremos estudiar la estructura de una web antes de extraer información de la misma." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - HTML\n", "```html\n", "\n", "\n", "Mi web\n", "\n", "\n", "

Javier de la Rosa

\n", "

Ciencia de Datos

\n", "\n", "\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - HTML\n", "```html\n", "\n", "\n", "Mi web\n", "\n", "\n", "

Javier de la Rosa

\n", "

Ciencia de datos

\n", "

Noviembre 2019

\n", "\n", "\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - `robots.txt`\n", "\n", "El archivo robots.txt es un documento que define qué partes de un dominio pueden ser analizadas por los rastreadores de los motores de búsqueda y proporciona un enlace al XML-sitemap (ver [ejemplo de sitemap](https://yoast.com/sitemap_index.xml)).\n", "\n", "```\n", "# robots.txt for http://www.example.com/\n", "\n", "User-agent: UniversalRobot/1.0\n", "User-agent: GoogleBot\n", "Disallow: /sources/dtd/\n", "\n", "User-agent: *\n", "Disallow: /nonsense/\n", "Disallow: /temp/\n", "Disallow: /newsticker.shtml\n", "```\n", "\n", "Ejemplo real: https://www.google.com/robots.txt" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping con Python\n", "\n", "- [BeautifulSoup](http://www.crummy.com/software/BeautifulSoup/bs4/doc/), encargada de crear un árbol con los elementos que componen una web y facilitar su acceso\n", "- [requests](https://requests.readthedocs.io/en/master/) para facilitar la ejecución de peticiones a servidores desde código Python. Aunque nativamente se puede usar [urllib3](https://urllib3.readthedocs.io/en/latest/index.html).\n", "- [html5lib](https://github.com/html5lib/html5lib-python), para mejorar el tratamiento de los elementos HTML" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "!!pip install beautifulsoup4\n", "!!pip install requests requests-html\n", "!!pip install html5lib" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping - requests vs urllib3\n", "import requests\n", "\n", "print(\"requests:\",\n", " requests.get(\"http://httpbin.org/ip\").json()\n", ")\n", "\n", "\n", "import urllib3\n", "import json\n", "\n", "http = urllib3.PoolManager()\n", "response = http.request('GET', 'http://httpbin.org/ip')\n", "print(\"urllib3: \",\n", " json.loads(response.data.decode('utf-8'))\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping con Python\n", "\n", "# elpais.com example - First part\n", "from bs4 import BeautifulSoup\n", "import requests\n", "\n", "url = \"https://elpais.com/\"\n", "html = requests.get(url).text\n", "soup = BeautifulSoup(html, 'html5lib')\n", "links = []\n", "all_news_lines = soup.select('.articulo-titulo')\n", "for line in all_news_lines:\n", " link = line.find('a')\n", " links.append(link)\n", "links[:3]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping con Python\n", "\n", "# elpais.com example - Second part\n", "news = []\n", "for link in links:\n", " new = link.text # link.get(\"title\")\n", " news.append(new)\n", "news[:5]" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Selectores\n", "- Selector de tipo o etiqueta (todos)\n", "```css\n", "p\n", "p, span\n", "```\n", "\n", "- Selector descendente (dentro)\n", "```css\n", "p span\n", "h1 span\n", "```\n", "```html\n", "

Algo de texto especial!

\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Selectores (cont.)\n", "\n", "- Selectores de ID\n", "```css\n", "#destacado\n", "```\n", "```html\n", "

Segundo párrafo

\n", "```\n", "\n", "- Selector de clase\n", "```css\n", "p.destacado\n", "```\n", "```html\n", "

Lorem ipsum dolor sit amet...

\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Selectores (cont.)\n", "\n", "- Combinación de selectores básicos\n", "```css\n", ".aviso .especial\n", "```\n", "```html\n", "

Algo de texto especial!

\n", "```\n", "\n", "- Hijos directos\n", "```css\n", "td > span\n", "```\n", "```html\n", "Texto\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Selectores (cont.)\n", "\n", "- Precedencia directa (sin parentesco)\n", "```css\n", "p + a\n", "```\n", "```html\n", "

Paragraph y

enlace\n", "```\n", "\n", "- Posicionales\n", "```css\n", "p:first span:last a:n-child(2)\n", "```\n", "\n", "```html\n", "

Para 1 Span 1Span 2 Enlace 1 Enlace 2

Para 2

\n", "\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "
\n", "

\n", "Ejercicio\n", "

\n", "

\n", "Escriba las expresiones de selección para los siguientes casos:\n", " \n", "- Todos los `div` del documento.\n", "- Todos los `p` y `a`.\n", "- Todos los `a` descedientes de `p`.\n", "- Todos los elementos de las clase `nombreClase`.\n", "- Los `div` de las clase `nombreClase`.\n", "\n", "

\n", "\n", "
" ] }, { "cell_type": "raw", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "# Escriba su código aquí\n", "# Todos los div del documento.\n", "\n", "# Todos los p y a.\n", "\n", "# Todos los a descedientes de p.\n", "\n", "# Todos los elementos de las clase nombreClase.\n", "\n", "# Los div de las clase nombreClase.\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - Ejemplo: 43º Congreso de los EEUU\n", "```html\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
Member NameBirth-Death
ADAMS, George Madison1837-1920
ALBERT, William Julian1816-1879
ALBRIGHT, Charles1830-1880
\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping - Ejemplo: 43º Congreso de los EEUU\n", " \n", "html = \"\"\"\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
Member NameBirth-Death
ADAMS, George Madison1837-1920
ALBERT, William Julian1816-1879
ALBRIGHT, Charles1830-1880
\"\"\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping - Ejemplo: 43º Congreso de los EEUU\n", "\n", "soup = BeautifulSoup(html)\n", "print(soup.prettify())" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping - Ejemplo: 43º Congreso de los EEUU\n", "\n", "links = soup.find_all('a')\n", "for link in links:\n", " names = link.text\n", " full_link = link.get('href')\n", " print([names, full_link])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping - Ejemplo: 43º Congreso de los EEUU\n", "import csv\n", "\n", "with open(\"congress.csv\", \"w\") as file:\n", " writer = csv.writer(file)\n", " writer.writerow([\"Name\", \"Link\"])\n", " links = soup.find_all('a')\n", " for link in links:\n", " names = link.text\n", " full_link = link.get('href')\n", " writer.writerow([names, full_link])\n", "\n", "!cat congress.csv" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping con Python\n", "\n", "# Marca example - First Part\n", "from bs4 import BeautifulSoup\n", "import requests\n", "\n", "url = \"http://www.marca.com/futbol/primera/calendario.html\"\n", "soup = BeautifulSoup(requests.get(url).text, \"html5lib\")\n", "jornadas = soup.find_all(\"div\", \"jornada\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping con Python\n", "\n", "# Marca example - Second Part\n", "for jornada in jornadas:\n", " nombre_jornada = jornada.find(\"caption\").text\n", " partidos_jornada = jornada.find_all(\"tr\")\n", "nombre_jornada, partidos_jornada[5]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping con Python\n", "\n", "# Marca example - Third Part\n", "for partido_jornada in partidos_jornada[1:]:\n", " local = visitante = resultado = \"\"\n", " try:\n", " local = partido_jornada.find(\"td\", \"local\").text.strip()\n", " visitante = partido_jornada.find(\"td\", \"visitante\").text.strip()\n", " resultado = partido_jornada.find(\"td\", \"resultado\").text.strip()\n", " except:\n", " pass\n", "local, resultado, visitante" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping con Python\n", "\n", "# Marca example - Fourth Part\n", "resultados = []\n", "if \"Villarreal\" in [local, visitante]:\n", " partido = f\"{local} vs {visitante}: {resultado} | {nombre_jornada}\"\n", "resultados.append(partido)\n", "resultados" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping con Python\n", "\n", "resultados = []\n", "url = \"http://www.marca.com/futbol/primera/calendario.html\"\n", "equipo = \"Villarreal\"\n", "soup = BeautifulSoup(requests.get(url).text, \"html5lib\")\n", "jornadas = soup.find_all(\"div\", \"jornada\")\n", "for jornada in jornadas:\n", " nombre_jornada = jornada.find(\"caption\").text\n", " partidos_jornada = jornada.find_all(\"tr\")\n", " for partido_jornada in partidos_jornada[1:]:\n", " local = partido_jornada.find(\"td\", \"local\").text.strip()\n", " visitante = partido_jornada.find(\"td\", \"visitante\").text.strip()\n", " resultado = partido_jornada.find(\"td\", \"resultado\").text.strip()\n", " if equipo in [local, visitante]:\n", " partido = f\"{local} vs {visitante}: {resultado} | {nombre_jornada}\"\n", " if partido not in resultados:\n", " resultados.append(partido)\n", "resultados" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "
\n", "

\n", "Ejercicio\n", "

\n", "

\n", "Desde hace años, el portal de alexa.com mantiene listados de los sitios más visitados por país. En https://www.alexa.com/topsites/countries/ES se puede ver la lista de los 50 primeros. Usando la librería [`builtwith`](https://pypi.org/project/builtwith/), se pide escrapear los 50 sitios más visitados de España en el ranking de Alexa y devolver los sitios que usen el *framework* Javascript `React` (clave `'javascript-frameworks'` en el resultado devuelto por `builtwith`).\n", "

\n", "

(**Pista**: Para poder procesar una URL, debe tener el protocolo primero, `https://`. Adem'as algunas webs no funcionan con `builtwith`, así que hay que capturar las excepciones correspondientes)

\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "!!pip install builtwith\n", "import builtwith\n", "\n", "# Escriba su código aquí\n", "url = ...\n", "html = requests....\n", "soup = BeautifulSoup(...)\n", "selector = ...\n", "sites_using_react = []\n", "for element in soup.select(selector)[:10]:\n", " element_url = ...\n", " try:\n", " builts = builtwith.builtwith(element_url)\n", " frameworks = builts...\n", " except:\n", " frameworks = []\n", " if \"React\" in frameworks:\n", " sites_using_react.append(...)\n", "\n", "sites_using_react" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scrapping - Problemas\n", "- Dificultad a la hora de estudiar la estructura de una página web\n", "- Las páginas webs pueden cambiar a lo largo del tiempo\n", "- Nuestros programas también necesitan cambiar\n", "- Necesitamos revisar las leyes y los derechos de uso de las páginas webs para poder aplicar esta técnica\n", "- Contenido dinámico (☠️ Javascript ☠️)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "
\n", "

\n", "Ejercicio\n", "

\n", "

\n", "Dada la URL https://pythonprogramming.net/parsememcparseface/, se pide scrapearla y obtener el valor textual del id `yesnojs`.\n", "

\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Escriba su código aquí" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - Contenido dinámico\n", "\n", "El módulo [`requests_html`](https://github.com/psf/requests-html) permite descargar HTML y ejecutar el contenido dinámico existente.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "%%python\n", "from requests_html import HTMLSession\n", "\n", "html = HTMLSession().get('https://pythonprogramming.net/parsememcparseface/').html\n", "html.render()\n", "\n", "print(html.find('#yesnojs', first=True).text)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Scraping - Contenido dinámico\n", "\n", "Otra opción, bastante más versátil, es [Selenium](https://selenium.dev/) (y sus [drivers para Python](https://selenium-python.readthedocs.io)), ya que permite controlar programáticamente una instancia real de un navegador." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping - Contenido dinámico\n", "\n", "# En Anaconda !!conda install -yq python-chromedriver-binary\n", "!!pip install selenium chromedriver_binary\n", "from selenium import webdriver\n", "import chromedriver_binary # Adds chromedriver binary to path\n", "\n", "driver = webdriver.Chrome()\n", "driver.get(\"http://www.python.org\")\n", "print(driver.title, \"Python\" in driver.title)\n", "driver.quit()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping - Contenido dinámico\n", "# renfe.es\n", "\n", "driver = webdriver.Chrome()\n", "driver.get(\"http://www.renfe.es\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping - Contenido dinámico\n", "# renfe.es\n", "\n", "origen = driver.find_element_by_id('IdOrigen')\n", "origen.send_keys(\"SEVILLA-SANTA JUSTA\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "destino = driver.find_element_by_id(\"IdDestino\")\n", "destino.send_keys(\"MADRID (TODAS)\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "comprar = driver.find_element_by_css_selector(\"#datosBusqueda > button\")\n", "comprar.click()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Scraping - Contenido dinámico\n", "# renfe.es\n", "\n", "precios = driver.find_elements_by_css_selector(\"tr.trayectoRow > td:nth-child(6)\")\n", "for precio in precios:\n", " print(precio.text)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "driver.quit()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Índice\n", "1. Introducción\n", "2. Repositorios\n", "3. Scraping\n", "4. **Extracción de información usando expresiones regulares**\n", "5. Conclusiones\n", "6. Bibliografı́a" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Extracción de información usando expresiones regulares\n", "\n", "Una expresión regular (a menudo llamada también regex) es una secuencia de caracteres que forma un patrón de búsqueda, principalmente utilizada para la búsqueda de patrones en textos u operaciones de sustituciones.\n", "\n", "Haciendo uso de expresiones regulares sobre texto podremos extraer la información que nos interesa almacenar y/o gestionar.\n", "\n", "La teorı́a tras las expresiones regulares es compleja y muy amplia. Aquı́ sólo veremos unos ejemplos sencillos para entender el funcionamiento de esta técnica para nuestros objetivos." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expresiones regulares\n", "- [`(\\d{3}-){2}\\d{3}`](https://regexper.com/#%28%5Cd%7B3%7D-%29%7B2%7D%5Cd%7B3%7D)\n", "- [`(\\W|^)(tontería|maldito|caray|caramba|madre\\smía|ostras)(\\W|$)`](https://regexper.com/#%28%5CW%7C%5E%29%28tontería%7Cmaldito%7Ccaray%7Ccaramba%7Cmadre%5Csmía%7Costras%29%28%5CW%7C%24%29)\n", "- [`v[i!1][a@]gr[a@]`](https://regexper.com/#v%5Bi!1%5D%5Ba%40%5Dgr%5Ba%40%5D)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expresiones regulares en Python\n", "Seguiremos haciendo uso del lenguaje Python. Estudiaremos las expresiones regulares trabajando sobre una serie de ejemplos.\n", "\n", "El paquete Python que usaremos es el paquete re. Una búsqueda de una expresión regular tı́pica serı́a:\n", "```python\n", "match = re.search(pat, str)\n", "```\n", "donde `pat` serı́a el patrón de la expresión regular y `str` la cadena de texto donde buscar. La búsqueda del patrón devuelve el resultado si lo encuentra o None en otro caso." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Expresiones regulares en Python\n", "\n", "import re\n", "text = \"nos encanta el:data:science\"\n", "match = re.search(r\"el:\\w\\w\\w\\w\", text)\n", "if match:\n", " print(\"found:\", match.group())\n", "else:\n", " print(\"not found\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expresiones regulares en Python\n", "\n", "Patrones básicos que podemos usar:\n", "- `a`, `X`, `9`: Caracteres normales buscan la coincidencia de ellos mismos.\n", "- `\\w`: Busca la coincidencia de letras, dı́gitos o guión bajo `[a-zA-Z0-9 ]`. `\\W` coincide con cualquier carácter que no sea uno de los anteriores." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expresiones regulares en Python\n", "\n", "Más patrones básicos:\n", "- `\\s`: Busca la coincidencia de un único espacio en blanco (space, newline, return, tab, form `[ \\n \\r \\t \\f]`). `\\S` coincide con cualquier carácter que no sea uno de los anteriores.\n", "- `\\d`: Busca coincidencias de dı́gitos decimales `[0-9]`.\n", "- `\\`: Se usa también para tratar los caracteres especiales como caracteres normales (los escapa)." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expresiones regulares en Python\n", "Además de estos patrones, podremos usar una serie de caracteres especiales:\n", "- `.`: Coincide con cualquier carácter del texto.\n", "- `ˆ`, `$`: Sirven para indicar que la búsqueda del patrón sea al comienzo o al final del texto respectivamente.\n", "- `*`, `+`, `?`: Se usan para la repetición de ocurrencias en el texto.\n", "- `{}[]()-`: Estos caracteres se usan para la definición de grupos y conjuntos dentro del patrón de búsqueda. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Expresiones regulares en Python\n", "text = \"www.example.com\"\n", "numbers = \"12345\"\n", "mail = \"pepe@example.com\"\n", "\n", "print(re.search(r\"www\", text))\n", "print(re.search(r\"wwwe\", text))\n", "print(re.search(r\"\\d\\d\\d\", numbers))\n", "print(re.search(r\"\\w\\w@\\w\\w\", mail))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expresiones regulares en Python\n", "Caracteres para aplicar repetición de elementos:\n", "- `+`, buscarı́a 1 o más ocurrencias del patrón a su izquierda. Por ejemplo, `i+` equivale a uno o más caracteres `i`\n", "- `*`, buscarı́a 0 o más ocurrencias del patrón a su izquierda\n", "- `?`, buscarı́a 0 o 1 ocurrencia del patrón a su izquierda" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Expresiones regulares en Python\n", "text = \"www.example.com\"\n", "numbers_words = \"hola12345caracola\"\n", "numbers_words_spaces = \"hola12345 caracola\"\n", "mail = \"pepe@example.com\"\n", "\n", "print(re.search(r\"w+\", text))\n", "print(re.search(r\"w?\", text))\n", "print(re.search(r\"\\w\\d*\\w\", numbers_words))\n", "print(re.search(r\"\\w\\d+\\w\", numbers_words))\n", "print(re.search(r\"\\w\\d+\\s+\\w\", numbers_words_spaces))\n", "print(re.search(r\"^p\\w+\", mail))\n", "print(re.search(r\"p\\w+\", mail))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expresiones regulares en Python\n", "Dentro de nuestras expresiones regulares podemos usar corchetes.\n", "\n", "El uso de corchetes indica un conjunto de caracteres. Por ejemplo, `[abc]` buscarı́a `a`, `b` o `c`.\n", "\n", "Dentro de los corchetes podemos usar los patrones que hemos visto, como `\\w`, `\\s`, etc. Sólo hay una excepción, el carácter `.` significa un punto y no cualquier carácter." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Expresiones regulares en Python\n", "text = \"sevilla prueba@mail.com mas pruebas extras\"\n", "match = re.search(r\"\\w+@\\w+\", text)\n", "if match:\n", " print(match.group())\n", "match = re.search(r\"[\\w.-]+@[\\w.-]+\", text)\n", "if match:\n", " print(match.group())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expresiones regulares en Python - Extracción de grupos\n", "\n", "Una caracterı́stica muy útil cuando trabajamos con expresiones regulares son los grupos. Usar grupos nos permite separar el patrón por partes que luego podemos elegir individualmente.\n", "\n", "Para conseguir esto, englobamos las partes que nos interesan con paréntesis. Para obtener los valores de los grupos obtenidos, simplemente usamos la función `match.group()`, pasándole como parámetro el ı́ndice grupo que queremos seleccionar. Si no le pasamos ningún valor obtendremos el resultado de todo el patrón (funcionamiento normal)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Expresiones regulares en Python\n", "text = \"betis prueba@mail.com mas pruebas extras\"\n", "match = re.search(\"([\\w.-]+)@([\\w.-]+)\", text)\n", "if match:\n", " print(match.group()) ## the whole match\n", " print(match.group(1)) ## the user\n", " print(match.group(2)) ## the host" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expresiones regulares en Python - findall\n", "El método `re.search()` nos devuelve el primer resultado del patrón buscado sobre un texto. Usando el método `findall()` obtenemos todos los resultados del patrón buscado sobre el texto, devueltos en una lista de resultados.\n", "\n", "Por ejemplo, si queremos encontrar un patrón en un archivo de texto necesitarı́amos iterar sobre todas las lı́neas e ir buscando el patrón en cada una. Si usamos `findall()` podrı́amos pasar como parámetro el propio archivo completo, dejando que el método haga la búsqueda en todo el documento." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Expresiones regulares en Python\n", "text = \"betis prueba@mail.com scientist@hostmail.com mas prueba2@pepemail.com pruebas extras\"\n", "emails = re.findall(r\"[\\w\\.-]+@[\\w\\.-]+\", text)\n", "for email in emails:\n", " print(email)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expresiones regulares en Python - findall\n", "Si unimos la forma de trabajar de los grupos con el método `findall()`, en vez de obtener una lista de resultados obtendremos una lista de tuplas.\n", "\n", "Cada una de las tuplas contendrá los resultados de los grupos (group(1), group(2), etc.)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Expresiones regulares en Python\n", "text = \"betis prueba@mail.com scientist@hostmail.com mas prueba2@pepemail.com pruebas extras\"\n", "tuples = re.findall(r\"([\\w\\.-]+)@([\\w\\.-]+)\", text)\n", "print(tuples)\n", "for pair in tuples:\n", " print(pair[0])\n", " print(pair[1])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Expresiones regulares en Python - Substitution\n", "Por último, la función `re.sub(pat, replacement, str)` busca todas las coincidencias del patrón `pat` en la cadena `str` y los reemplaza con el valor de `replacement`.\n", "\n", "La cadena replacement puede incluir los valores `\\1`, `\\2`, etc. en referencia al texto de `group(1)`, `group(2)`, etc." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, "outputs": [], "source": [ "### Expresiones regulares en Python\n", "text = \"betis prueba@mail.com scientist@hostmail.com mas prueba2@pepemail.com pruebas extras\"\n", "print(re.sub(r\"([\\w\\.-]+)@([\\w\\.-]+)\", r\"alex@my_mail.com\", text))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "

\n", "Ejercicio\n", "

\n", "

\n", "Escriba la expresión regular para validar los sguientes supuestos (una expresión para cada uno):\n", " \n", "- Validar numero real positivo con x decimales.\n", "- Validar numero real negativo con x decimales.\n", "- Validar una fecha con formato dd/mm/aaaa\n", "- Validar un nombre, incluyendo nombres compuestos.\n", "- Validar un email.\n", "- Valida un nombre de usuario en twitter, empieza por @ y puede contener letras mayusculas y minusculas, numeros, guiones y guiones bajos.\n", "- Validar ISBN de 13 digitos, siempre empieza en 978 o 979.\n", " \n", "

\n", "
" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Índice\n", "1. Introducción\n", "2. Repositorios\n", "3. Scraping\n", "4. Extracción de información usando expresiones regulares\n", "5. **Conclusiones**\n", "6. Bibliografı́a" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Conclusiones\n", "\n", "En nuestro dı́a a dı́a en proyectos tecnológicos vamos a trabajar con repositorios de datos y de código.\n", "\n", "El scraping es una técnica muy usada y útil para estructurar dato procedente de la web. Entre los principales campos de aplicación encontramos el periodismo de datos (social media).\n", "\n", "Entre las dificultades que presenta el scraping destacamos el mantenimiento del código y el tener en cuenta los términos de uso legales.\n", "\n", "Las expresiones regulares nos permiten extraer información a partir de la aplicación de patrones a un texto dado. Esto facilita la creación de conjuntos de datos con un modelo de datos concreto." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Índice\n", "1. Introducción\n", "2. Repositorios\n", "3. Scraping\n", "4. Extracción de información usando expresiones regulares\n", "5. Conclusiones\n", "6. **Bibliografı́a**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Bibliografı́a\n", "- Data Science from scratch, by Joel Grus, O'reilly, 2015\n", "- https://en.wikipedia.org/wiki/Data_collection\n", "- https://es.wikipedia.org/wiki/Repositorio\n", "- https://es.wikipedia.org/wiki/Web_scraping\n", "- https://es.wikipedia.org/wiki/Expresión_regular\n", "- https://developers.google.com/edu/python/regular-expressions" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.5" }, "rise": { "enable_chalkboard": true, "footer": "
Máster Propio en Data Science y Big Data
Arquitecturas y paradigmas para Ciencia del Dato
", "scroll": true, "start_slideshow_at": "selected" } }, "nbformat": 4, "nbformat_minor": 2 }