Los selectores HTML son clave para el web scraping, ya que permiten a los desarrolladores dirigirse a elementos específicos de una página web. Mediante estos selectores, los desarrolladores pueden extraer datos con precisión.
El web scraping consiste en obtener datos de sitios web navegando por su estructura HTML. Los selectores HTML son cruciales para localizar etiquetas, atributos o contenidos específicos. Ya sea para extraer precios de productos o titulares, los selectores son tu guía.
El uso de selectores HTML agiliza eficazmente la extracción de datos y reduce los errores. Le ayudan a centrarse en los elementos importantes, ahorrando tiempo y esfuerzo en la recopilación de información de fuentes en línea.
En este blog, vamos a explorar cómo utilizar los selectores de abajo con Python y la biblioteca"Beautifulsoup":
En HTML, los ID son identificadores únicos asignados a elementos específicos, lo que garantiza que no haya dos elementos que compartan el mismo ID. Esta singularidad hace que los selectores de ID sean ideales para identificar elementos concretos de una página web. Por ejemplo, si está escaneando una página web con varias secciones, cada sección puede tener su propio ID, lo que le permite extraer datos de una sección concreta sin interferencias.
Tomemos por ejemplo este sitio webespecialmente el elemento siguiente <div id="pages"> ...</div>
Este elemento contiene otros elementos HTML anidados pero lo principal es que este elemento es único en este sitio web y podemos aprovecharnos de este escenario por ejemplo cuando queremos scrapear secciones concretas del sitio web. En este caso este elemento incluye algunos otros artículos que explicaremos con los otros selectores más abajo. Aquí como se ve esta sección en la página:
Veamos un ejemplo sencillo utilizando las bibliotecas "requests" y "bs4" de Python:
import requests
from bs4 import BeautifulSoup
# Step 1: Send a GET request to the website
url = "https://www.scrapethissite.com/pages/"
response = requests.get(url)
if response.status_code == 200:
# Step 2: Parse the HTML content with BeautifulSoup
soup = BeautifulSoup(response.text, 'html.parser')
# Step 3: Find the div with id="pages"
pages_div = soup.find("div", id="pages")
# Step 4: Display the content or handle it as needed
if pages_div:
print("Content of the div with id='pages':")
print(pages_div.text.strip())
else:
print("No div with id='pages' found.")
else:
print(f"Failed to retrieve the webpage. Status code: {response.status_code}")
Explicación:
soup.find("div", id="pages")
para localizar el <div>
elemento con id="pages"
. <div>
se imprime su contenido. Si no, un mensaje indica que falta.Los selectores de ID son potentes, pero tienen limitaciones. Los ID dinámicos que cambian con cada carga de la página pueden dificultar la extracción coherente de datos. En estas situaciones, puede ser necesario utilizar selectores alternativos para obtener resultados fiables.
Los selectores de clase son flexibles porque permiten seleccionar grupos de elementos que comparten la misma clase. Esto los hace esenciales para páginas web con elementos recurrentes. Por ejemplo, un sitio web que muestre una lista de productos puede asignar la misma clase a cada uno de ellos.
Volvamos a poner un ejemplo con este sitio web. Más arriba identificamos un <div id="pages">
usando ID Selector y en este elemento div hay algunos artículos que tienen la misma clase.
Como puedes ver tenemos cuatro elementos con la misma clase <div class="page">
Así es como se ven en el sitio web:
En el código siguiente, seleccionaremos todos los elementos con la clase "page", lo que devolverá una lista que puede utilizarse para el análisis posterior.
import requests
from bs4 import BeautifulSoup
# Step 1: Send a GET request to the website
url = "https://www.scrapethissite.com/pages/"
response = requests.get(url)
if response.status_code == 200:
# Step 2: Parse the HTML content with BeautifulSoup
soup = BeautifulSoup(response.text, 'html.parser')
# Step 3: Find all elements with class="page"
page_elements = soup.find_all("div", class_="page")
# Step 4: Save each element's text content in a list
pages_list = [page.text.strip() for page in page_elements]
print("Content of elements with class 'page':")
for i, page in enumerate(pages_list, start=1):
print(f"Page {i}:")
print(page)
print("-" * 20)
else:
print(f"Failed to retrieve the webpage. Status code: {response.status_code}")
Explicación:
soup.find_all("div", class_="page")
para localizar todos <div>
con la clase "page", devolviéndolos en forma de lista. Cuando utilice selectores de clase, tenga en cuenta posibles problemas como la selección de elementos no deseados. Varias clases en un mismo elemento pueden requerir un filtrado adicional para lograr una selección precisa.
Los selectores de atributos permiten seleccionar elementos en función de la presencia, el valor o el valor parcial de atributos específicos dentro de etiquetas HTML. Esto resulta especialmente útil cuando las clases o los ID no son únicos o cuando es necesario filtrar elementos con atributos dinámicos, como por ejemplo datos-*
o href
en los enlaces.
En el siguiente ejemplo, vamos a seleccionar todas las imágenes en el este página web y extraer sus URL de origen o src
atributos. Así es como se ve el elemento en la estructura html y en la vista de página web:
En el código siguiente, utilizamos BeautifulSoup para analizar todos los archivos <img> extrayendo sus src
y almacenarlos en una lista.
import requests
from bs4 import BeautifulSoup
# Step 1: Send a GET request to the website
url = "https://www.scrapethissite.com/pages/frames/"
response = requests.get(url)
if response.status_code == 200:
# Step 2: Parse the HTML content with BeautifulSoup
soup = BeautifulSoup(response.text, 'html.parser')
# Step 3: Find all <img> elements with a 'src' attribute
image_elements = soup.find_all("img", src=True)
# Step 4: Save the 'src' attributes in a list
images_list = [img['src'] for img in image_elements]
print("Image sources found on the page:")
for i, src in enumerate(images_list, start=1):
print(f"Image {i}: {src}")
else:
print(f"Failed to retrieve the webpage. Status code: {response.status_code}")
Los selectores de atributos sólo pueden seleccionar elementos con atributos estáticos, lo que los hace menos eficaces para el contenido dinámico, como los elementos cargados mediante JavaScript. Dependen de estructuras HTML estables, por lo que los cambios frecuentes en el diseño del sitio web pueden alterarlos. Además, no pueden gestionar filtros complejos ni condiciones múltiples, lo que limita su precisión. También pueden detectar elementos no deseados si atributos como class o name son compartidos por varios elementos.
Los selectores jerárquicos permiten seleccionar elementos HTML en función de su posición y relación con otros elementos de la estructura HTML. Este enfoque es especialmente útil cuando se trabaja con tablas o listas anidadas, donde los datos se organizan en un formato padre-hijo.
En este ejemplo, utilizamos selectores jerárquicos para extraer datos de una tabla de estadísticas de equipos de hockey que se encuentra en esta página web.
La tabla contiene filas <tr>
que representa a cada equipo, y cada fila contiene celdas <td>
con información como el nombre del equipo, el año, las victorias y las derrotas. Cada fila tiene el class="equipo"
identificándola como una entrada relevante en nuestros datos. Navegando desde el <table>
to each <tr> and then to each <td>
podemos capturar eficazmente los datos de forma estructurada.
A continuación encontrará dos imágenes que le ayudarán a visualizar dónde se encuentra esta tabla en la estructura HTML y cómo aparece en la página web real.
Ahora, veamos en el siguiente código cómo se pueden utilizar los selectores jerárquicos para extraer estos datos:
import requests
from bs4 import BeautifulSoup
url = "https://www.scrapethissite.com/pages/forms/"
# Step 1: Send a GET request to the website
response = requests.get(url)
if response.status_code == 200:
# Step 2: Parse the HTML content with BeautifulSoup
soup = BeautifulSoup(response.text, 'html.parser')
# Step 3: Find all rows in the table with class="team"
teams_data = []
team_rows = soup.find_all("tr", class_="team")
# Step 4: Extract and store each team's data
for row in team_rows:
team = {
"name": row.find("td", class_="name").text.strip(),
"year": row.find("td", class_="year").text.strip(),
"wins": row.find("td", class_="wins").text.strip(),
"losses": row.find("td", class_="losses").text.strip(),
"ot_losses": row.find("td", class_="ot-losses").text.strip(),
"win_pct": row.find("td", class_="pct").text.strip(),
"goals_for": row.find("td", class_="gf").text.strip(),
"goals_against": row.find("td", class_="ga").text.strip(),
"goal_diff": row.find("td", class_="diff").text.strip(),
}
teams_data.append(team)
# Step 5: Display the extracted data
for team in teams_data:
print(team)
else:
print(f"Failed to retrieve the webpage. Status code: {response.status_code}")
Los selectores jerárquicos dependen de la estructura HTML, por lo que los cambios en el diseño pueden romper fácilmente el script de raspado. También se limitan al contenido estático y no pueden acceder a elementos cargados dinámicamente mediante JavaScript. Estos selectores suelen requerir una navegación precisa a través de las relaciones padre-hijo, lo que puede resultar complicado en estructuras profundamente anidadas. Además, pueden resultar ineficaces a la hora de extraer datos dispersos, ya que deben atravesar varios niveles para llegar a elementos específicos.
Cada tipo de selector sirve a un propósito único, y combinarlos nos permite navegar y capturar datos con precisión a partir de contenido anidado o estructurado. Por ejemplo, el uso de un selector de ID puede ayudar a localizar el área de contenido principal, los selectores de clase pueden aislar elementos repetidos, los selectores de atributo pueden extraer enlaces o imágenes específicos, y los selectores jerárquicos pueden llegar a elementos anidados dentro de secciones específicas. Juntas, estas técnicas proporcionan un potente enfoque para el scraping de datos estructurados.
import requests
from bs4 import BeautifulSoup
# Target URL
url = "https://www.scrapethissite.com/pages/"
response = requests.get(url)
if response.status_code == 200:
# Step 2: Parse the HTML content with BeautifulSoup
soup = BeautifulSoup(response.text, 'html.parser')
# Use ID selector to find the main content
main_content = soup.find(id="pages")
# Use class selector to find each "page" section
pages = main_content.find_all("div", class_="page") if main_content else []
# Extract details from each "page" section using hierarchical selectors
for page in pages:
# Use hierarchical selector to find title link and URL within each "page"
title_tag = page.find("h3", class_="page-title")
title = title_tag.text.strip() if title_tag else "No Title"
link = title_tag.find("a")["href"] if title_tag and title_tag.find("a") else "No Link"
# Use class selector to find the description
description = page.find("p", class_="lead session-desc").text.strip() if page.find("p", class_="lead session-desc") else "No Description"
print(f"Title: {title}")
print(f"Link: {link}")
print(f"Description: {description}")
print("-" * 40)
else:
print(f"Failed to retrieve the webpage. Status code: {response.status_code}")
class="página"
para encontrar cada bloque de contenido individual que represente una sección de interés. page.find("h3", class_="page-title")
para encontrar el título. title_tag.find("a")["href"]
para recuperar la URL del enlace a partir de la etiqueta de anclaje del título. En el raspado web, saber cómo utilizar los selectores HTML puede mejorar en gran medida sus habilidades de extracción de datos, lo que le permite recopilar información importante con precisión. Selectores como ID, clase, atributo y selectores jerárquicos tienen cada uno usos específicos para diferentes tareas de raspado. El uso conjunto de estas herramientas le permitirá enfrentarse con confianza a una amplia gama de retos de raspado web.
Para practicar, sitios como Scrape This Site y Books to Scrape ofrecen excelentes ejemplos que te ayudarán a perfeccionar tus habilidades. Y si necesitas ayuda o quieres ponerte en contacto con otras personas interesadas en el web scraping, no dudes en unirte a nuestro canal de Discord en https://discord.com/invite/scrape.
¡Feliz raspado!