<jupyter_start><jupyter_text>Web Scraping__[Web Scraping](https://www.imperva.com/learn/application-security/web-scraping-attack/)__ es el proceso de utilizar bots para extraer contenido y datos de un sitio web. En este proceso, se extrae el código HTML y los datos almacenados en una base de datos. Web Scraping permite replicar el contenido completo de un sitio web en cualquier lugar. Muchos negocios digitales que dependen de la recolección de datos, utilizan este proceso.A continuación, se mencionan algunos de los casos aplicables de esta técnica:- Clasificación de contenido, a tráves de la extracción de datos de multiples sitios web.- Comparación de precios y descripciones de productos sobre la base de sitios web que ofrecen productos.- Análisis de sentimiento a tráves de la extracción de datos de foros y redes sociales.Web Scraping es también utilizado para propósitos ilegales como ser: la subvaloración de precios y el robo de contenido protegido por derechos de autor. Esto podría provocar pérdidas financieras, especialmente si es una empresa que depende fuertemente de modelos de precios competitivos u ofertas en la distribución de contenido. Normalmente, las páginas tiene un archivo robots.txt en el cual especifican si es permitido o no extraer datos de ellas.__Nota__: evita realizar este proceso si previamente no cuentas con autorización del autor.Si quieres saber más, te dejamos abajo unos enlaces que podrían interesarte.- __[Estándar de exclusión de robots](https://es.wikipedia.org/wiki/Est%C3%A1ndar_de_exclusi%C3%B3n_de_robots)__- __[5 Things You Need to Know Before Scraping Data From Facebook](https://www.octoparse.com/blog/5-things-you-need-to-know-before-scraping-data-from-facebook)__ 1. [Extraer el código HTML](1)2. [Realizar búsquedas](2)3. [Experimentar estrategias para extraer datos](3)4. [Crear funciones y procesar los elementos](4)5. [Almacenar los datos en archivos](5)  Extraer el código HTMLPara explicar el proceso de Web Scraping, analizaremos la página web [Auto MPG web page](http://localhost:8000/auto_mpg.html). Esa página web es una página que fue creada para este tutorial. Recolecta los datos open source del dataset [Auto MPG](https://archive.ics.uci.edu/ml/datasets/auto+mpg). Puedes crear un pequeño servidor que retorne página [Auto MPG web page](http://localhost:8000/auto_mpg.html). Puedes cambiar el puerto si es diferente al 8000.Las columnas del dataset son las siguientes: nombre, cilindros, peso, año, territorio, aceleración, millas por galón, caballos de potencia y desplazamiento.Ejecuta la siguientes líneas de código:<jupyter_code>import requests

respuesta = requests.get("https://jordanmontt.github.io/fake-cars-webpage/")<jupyter_output><empty_output><jupyter_text>La biblioteca BeautifulSoup de bs4 nos permitirá análizar documentos HTML. Ejecuta las siguientes líneas de código para utilizar esta librería:<jupyter_code>from bs4 import BeautifulSoup
pagina = BeautifulSoup(respuesta.text, "html.parser" )<jupyter_output><empty_output><jupyter_text>Vizualiza si extrajiste bien el código HTML<jupyter_code>print(pagina.prettify())<jupyter_output><!DOCTYPE html>
<html lang="en">
 <head>
  <meta charset="utf-8"/>
  <title>
   Example Car Dataset
  </title>
  <style>
   body {
        background-color: rgb(0, 0, 0);
        color: rgb(211, 211, 211);
        font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        margin: 0 20px;
      }
      a:link {
        color: rgb(211, 211, 211);
      }
      a:visited {
        color: rgb(211, 211, 211);
      }
      div.car_block {
        background-color: rgb(34, 34, 34);
        padding: 15px 20px;
        border-left: 4px solid rgb(232, 10, 137);
      }
      .car_name {
        color: rgb(211, 211, 211);
        font-size: large;
      }
      .mpg {
        font-weight:bold;
      }
      .from {
        color: rgb(106, 116, 116);
        font-size: small;
      }
      .weight {
        font-style: italic;
      }
  </style>
 </head>
 <body>
  <h1>
   Example Car Datasheet (1970-1982)
  </h1>
  <p>
   This data comes from a
   <a href="https://archive.ics.uci.edu/ml[...]<jupyter_text>Puedes acceder directamente al body del html utilizando pagina.body<jupyter_code>print(pagina.body)<jupyter_output><body>
<h1>Example Car Datasheet (1970-1982)</h1>
<p>This data comes from a <a href="https://archive.ics.uci.edu/ml/datasets/Auto%2BMPG">public source</a> with citation 
"<NAME>. and <NAME>. (2017). UCI Machine Learning Repository [http://archive.ics.uci.edu/ml]. Irvine, CA: University of California, School of Information and Computer Science." and 
is referenced in "Quinlan,R. (1993). Combining Instance-Based and Model-Based Learning. In Proceedings on the Tenth International Conference of Machine Learning, 236-243, University of Massachusetts, Amherst. Morgan Kaufmann.".
</p>
<br/>
<div class="car_block" id="car-1"><span class="car_name">Chevrolet Chevelle Malibu</span> <span class="from">(1970, USA)</span> <br/> Achieves <span class="mpg">18.0 mpg</span> with <span class="cylinders">8</span> cylinders backed by <span class="horsepower">130</span> hp, 307.0 cubic inches of displacement, weighing <span class="weight">3,504</span> lbs with 0-60 mph acceleration in <span cl[...]<jupyter_text>Realizar búsquedasPuedes utilizar la función .find y .find_all para encontrar los elementos que deseas<jupyter_code>print(pagina.body.find(name="div", attrs={"id":"car-1"}))
print(len(pagina.body.find_all(name="div", attrs={"class":"car_block"})))
print(pagina.body.find_all(name="div", attrs={"class":"car_block"})[0])<jupyter_output><div class="car_block" id="car-1"><span class="car_name">Chevrolet Chevelle Malibu</span> <span class="from">(1970, USA)</span> <br/> Achieves <span class="mpg">18.0 mpg</span> with <span class="cylinders">8</span> cylinders backed by <span class="horsepower">130</span> hp, 307.0 cubic inches of displacement, weighing <span class="weight">3,504</span> lbs with 0-60 mph acceleration in <span class="acceleration">12.0</span> seconds</div>
406
<div class="car_block" id="car-1"><span class="car_name">Chevrolet Chevelle Malibu</span> <span class="from">(1970, USA)</span> <br/> Achieves <span class="mpg">18.0 mpg</span> with <span class="cylinders">8</span> cylinders backed by <span class="horsepower">130</span> hp, 307.0 cubic inches of displacement, weighing <span class="weight">3,504</span> lbs with 0-60 mph acceleration in <span class="acceleration">12.0</span> seconds</div><jupyter_text>Puedes acceder a los atributos de cada elemento como en el siguiente ejemplo.<jupyter_code>car_divs = pagina.body.find_all(name="div", attrs={"class":"car_block"})
div = car_divs[0]
div['class']<jupyter_output><empty_output><jupyter_text>Experimentar estrategias para extraer datosSi deseas extraer únicamente el contenido sin elementos HTML, realiza lo siguiente.<jupyter_code>print(div.text)<jupyter_output>Chevrolet Chevelle Malibu (1970, USA)  Achieves 18.0 mpg with 8 cylinders backed by 130 hp, 307.0 cubic inches of displacement, weighing 3,504 lbs with 0-60 mph acceleration in 12.0 seconds<jupyter_text>Puedes crear un generador (similar a un iterable) de la siguiente forma.<jupyter_code>print(div.stripped_strings)
print(list(div.stripped_strings))<jupyter_output><generator object PageElement.stripped_strings at 0x1124455f0>
['Chevrolet Chevelle Malibu', '(1970, USA)', 'Achieves', '18.0 mpg', 'with', '8', 'cylinders backed by', '130', 'hp, 307.0 cubic inches of displacement, weighing', '3,504', 'lbs with 0-60 mph acceleration in', '12.0', 'seconds']<jupyter_text>Puedes utilizar funciones poprias del lenguaje para obtener un mejor resultado de los datos que deseas obtener.<jupyter_code>div.find("span", attrs={"class":"mpg"}).text
div.find("span", attrs={"class":"mpg"}).text.split(" ")[0]<jupyter_output><empty_output><jupyter_text>Incluso puedes utilizar expresiones regulares si así lo deseas.<jupyter_code>import re
re.findall(r'.* (\d+.\d+) cubic inches', div.text)[0]<jupyter_output><empty_output><jupyter_text>Crear funciones y procesar los elementosFinalmente, te recomendamos crear funciones para cada item y procesar los elementos que contienen los datos.A continuación se muestra un ejemplo:<jupyter_code>import csv
import re
import requests
from bs4 import BeautifulSoup

def extraer_desplazamiento(div_automovil_text):
    texto_de_desplazamiento = re.findall(r'.* (\d+.\d+) cubic inches', div_automovil_text)[0]
    return float(texto_de_desplazamiento)

def extraer_caballos_potencia(div_automovil):
    texto_caballo_potencia = div_automovil.find('span', class_='horsepower').text
    try:
        texto_caballo_potencia = float(texto_caballo_potencia)
    except ValueError:
        texto_caballo_potencia = "NULL"
    return texto_caballo_potencia

def extraer_mpg(div_automovil):
    texto_de_mpg = div_automovil.find("span", attrs={"class":"mpg"}).text
    try:
        mpg = float(texto_de_mpg.split(' ')[0])
    except ValueError:
        mpg = "NULL"
    return mpg

def extraer_aceleracion(div_automovil):
    return float(div_automovil.find('span', class_='acceleration').text)

def extraer_territorio_y_anio(div_automovil):
    texto_de_from = div_automovil.find("span", attrs={"class":"from"}).text
    anio, territorio = texto_de_from.strip('()').split(',')
    anio = int(anio.strip())
    territorio = territorio.strip()
    return territorio, anio

def extraer_peso(div_automovil):
    texto_de_peso = div_automovil.find('span', class_='weight').text
    return int(texto_de_peso.replace(',', ''))

def extraer_cilindros(div_automovil):
    return int(div_automovil.find('span', class_='cylinders').text)

def extraer_nombre(div_automovil):
    return div_automovil.find('span', class_='car_name').text

def extraer_datos(div_automovil):
    fila = {}
    fila["nombre"] = extraer_nombre(div_automovil)
    fila["cilindros"] = extraer_cilindros(div_automovil)
    fila["peso"] = extraer_peso(div_automovil)
    fila["territorio"], fila["anio"] = extraer_territorio_y_anio(div_automovil)
    fila["aceleracion"] = extraer_aceleracion(div_automovil)
    fila["mpg"] = extraer_mpg(div_automovil)
    fila["caballos_potencia"] = extraer_caballos_potencia(div_automovil)
    fila["desplazamiento"] = extraer_desplazamiento(div_automovil.text)
    return fila

def extraer_datos_automoviles(pagina):
    divs_automoviles = pagina.body.find_all(name="div", attrs={"class":"car_block"})
    return list(map(extraer_datos, divs_automoviles))

        
respuesta = requests.get("https://jordanmontt.github.io/fake-cars-webpage/")
pagina = BeautifulSoup(respuesta.text, "html.parser" )
datos_automoviles = extraer_datos_automoviles(pagina)

print(f"Se ha extraido {len(datos_automoviles)} filas")
print(datos_automoviles[1])
print(datos_automoviles[-1])<jupyter_output>Se ha extraido 406 filas
{'nombre': '<NAME> 320', 'cilindros': 8, 'peso': 3693, 'territorio': 'USA', 'anio': 1970, 'aceleracion': 11.5, 'mpg': 15.0, 'caballos_potencia': 165.0, 'desplazamiento': 350.0}
{'nombre': '<NAME>', 'cilindros': 4, 'peso': 2720, 'territorio': 'USA', 'anio': 1982, 'aceleracion': 19.4, 'mpg': 31.0, 'caballos_potencia': 82.0, 'desplazamiento': 119.0}<jupyter_text>Almacenar los datos en archivosPuedes almacenar los datos extraídos en un archivo de tu preferencia<jupyter_code>def almacenar_datos_en_un_archivo_csv(datos_automoviles):
    with open("datos_automoviles1.csv", "w", encoding="utf-8", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=datos_automoviles[0].keys())
        writer.writeheader()
        writer.writerows(datos_automoviles)
almacenar_datos_en_un_archivo_csv(datos_automoviles)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.122794999143689, 'fraction_numerical': 0.02885768110977907, 'mean_word_length': 5.381967213114754, 'pattern_counts': {'":': 9, '<': 119, '<?xml version=': 0, '>': 117, 'https://': 8, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '456175', 'license': 'MIT', 'n_tokens_mistral': 4426, 'n_tokens_neox': 4108, 'n_words': 1031, 'path': 'Web Application/Notebooks/2. Web Scraping/web_scraping.ipynb', 'repo_name': 'jordanmontt/introduccion-ciencia-de-datos', 'size': '11702'}