Extracción de datos específicos con Beautiful Soup en Python
Resumen
¿Alguna vez has querido extraer fácilmente datos específicos de un sitio web? Aprenderás cómo hacerlo usando Beautiful Soup en Python. Podrás obtener información esencial como títulos, precios e imágenes desde páginas web estructuradas rápidamente y guardarlas en formato CSV.
¿Cómo identificar elementos específicos en una página web?
Antes de extraer información con Python, necesitas identificar la estructura HTML donde se encuentra la información clave. Utilizando herramientas de desarrollo del navegador, puedes explorar las etiquetas HTML y clases de los elementos para encontrar exactamente las partes importantes del contenido.
Por ejemplo, en este proyecto se identifica que cada libro del sitio web está encerrado en un elemento llamado artículo: etiqueta article con clase product-pot. Dentro de cada artículo hay detalles como título, imagen, precio y otros.
¿Cómo extraer nombres, precios e imágenes con Beautiful Soup?
Primero obtendrás todos los artículos de productos usando Beautiful Soup con la función select:
products = soup.select('.product-pot')
Luego recorres cada artículo para extraer información concreta:
Para el título: localizarás la etiqueta h3 dentro del artículo, luego la etiqueta a contenida en ella.
nombre = producto.find('h3').find('a')['title']
Para el precio: buscas la etiqueta p que tenga la clase price_color y obtienes el texto de dicha etiqueta.
Esto generará un archivo CSV dentro de la carpeta resultados, estructurado por columnas que contienen cada aspecto esencial del producto que seleccionaste previamente.
¡Te invito a participar en el desafío propuesto: intenta obtener también el número de estrellas de cada libro y si está en stock! Deja tu solución en los comentarios.
# List to store the information
product_list =[]for product inproducts: # Book name
nombre = product.find("h3").find("a")["title"] # Price precio = product.find("p", class_="price_color").get_text() # Image imagen = product.find("div", class_="image_container").find("img")["src"] imagen_url ="http://books.toscrape.com/"+ imagen
# Estrellas estrellas = product.find("p", class_="star-rating")["class"][1] # Stock stock = product.find("p", class_="instock availability").get_text(strip=True) product_list.append({"name": nombre,"price": precio,"image_url": imagen_url,"stars": estrellas,"stock": stock
})# Display first 3 products as preview
print("First 5 products:")for i, product inenumerate(product_list[:3],1):print(f"\n{i}. {product['name']}")print(f" Price: {product['price']}")print(f" Image: {product['image_url']}")print(f" Stars: {product['stars']}")print(f" Stock: {product['stock']}")
Aquí dejo mi solución de scraping incluyendo la parte de extraer las estrellas del libro, su disponibilidad en stock y el guardado de los datos en un archivo de csv.
Waooo que código tan limpio... soy novato en esto de programar, así que espero llegar a este nivel!
Gracias por lo del código limpio @Fabian Mauricio Lópes Guasca.
Yo también soy novato aun, solo he aprendido poco a poco las bases del buen código. Sé que lograras aprender mucho más. Nunca pares de aprender.
En el contexto de Beautiful Soup, el uso de class_="product_pod" es una forma de referirse a los atributos de un elemento HTML. Sin embargo, al utilizar el método select(), se emplea la notación de CSS, donde el punto . indica una clase. Por eso, select(".product_pod") significa "selecciona todos los elementos con la clase product_pod". La primera forma es más directa al buscar atributos, mientras que la segunda es más flexible y potente al utilizar selectores CSS.
que curso tan bueno que docente tan bueno
Al usar .text en BeautifulSoup, este obtiene todo el contenido dentro de la etiqueta, incluidos los espacios, saltos de línea y otros caracteres de formato.
Para eliminar esos espacios y saltos de línea innecesarios, puedes utilizar .strip(), que elimina los espacios en blanco y saltos de línea al principio y al final del texto extraído.
Se salto un pedazo al momento de guardar en el excel.. como es la creacion del pandas creo .. para luego ser guardado en el excel
product_list =[]for product in products:#nombre del libro name = product.find("h3").find("a")["title"]print(name)#precio precio = product.find("p", class_="price_color").get_text()print(precio)#imagen imagen = product.find("div", class_="image_container").find("img")["src"] imagen_url = url + imagen
print(imagen_url)#estrellas estrellas = product.find("p", class_="star-rating").get("class")[1]print(estrellas)#stock stock = product.find("p", class_="instock availability").get_text(strip =True)print(stock)pass product_list.append({"Nombre": name,"Precio": precio,"Imagen_url": imagen_url,"Estrellas": estrellas,"Stock": stock})
Por aquí mi solución al scraping incluyendo el rating y disponibilidad del artículo:
# Listof products to store the extracted information
homework_products_list =[]# Loop through the products and extract the title, price, and picture URLfor product inproducts: # Title is found in the "h3" tag, and the actual title text is in the "title" attribute of the "a" tag inside the "h3" tag
title = product.find("h3").find("a")["title"] # Price is found in the "p" tag with the class"price_color", and we use the get_text() method to extract the text content, stripping any extra whitespace
price = product.find("p", class_="price_color").get_text(strip=True) # PictureURL is found in the "div" tag with the class"image_container", and the actual URL is in the "src" attribute of the "img" tag inside that "div" tag
# PictureURLs on the website are relative, so we need to concatenate the base URLwith the relative URL to get the full URLof the picture
picture = product.find("div", class_="image_container").find("img")["src"] picture_url = url + picture
# Calification is found in the "p" tag with the class"star-rating", and the actual calification is in the second classof that "p" tag
# the first classis"star-rating" and the second classis the calification(e.g.,"One","Two","Three","Four","Five") calification = product.find("p", class_="star-rating")["class"][1] # Stock is found in the "p" tag with the class"instock availability", and we use the get_text() method to extract the text content
# stripping any extra whitespace
stock = product.find("p", class_="instock availability").get_text(strip=True) # Append the extracted information as a dictionary to the products_list
homework_products_list.append({"title": title,"price": price,"picture_url": picture_url,"calification": calification,"stock": stock
})homework_path_csv ="results/homework_book_store_products.csv"withopen(homework_path_csv,"w", newline="", encoding="utf-8")ascsvfile: writer = csv.DictWriter(csvfile, fieldnames=["title","price","picture_url","calification","stock"]) writer.writeheader() # Write the header row to the CSV file
writer.writerows(homework_products_list) # Write the rows of product information to the CSV file
print(f"Data has been successfully written to {homework_path_csv}\nTotal products extracted: {len(homework_products_list)}")
Aqui dejo mi código con el agregado del rating de estrellas y el stock
Aquí no dejo una solución al reto, más bien dejo un scrap que acabo de realizar a una empresa que vende de todo aquí en Colombia, buscando precios para el Celular S24:
productos = soup.select('div.grid-pod')diccionario ={'emprea':['Fallabela']*len(productos),'foto':[],'titulo':[],'marca':[],'distribuidor':[],'descuento':[],'precio_descuento':[],'precio_anterior':[]}for producto_all inproductos:
# versión limpia
foto_tag = producto_all.find('img') price_tag = producto_all.find('span') foto = foto_tag['src']if foto_tag and foto_tag.has_attr('src')else'' titulo = producto_all.find('div', class_='pod-details-4_GRID').find('b', class_="subTitle-rebrand").text marca = producto_all.find('div', class_='pod-details-4_GRID').find('b').text distribuidor = producto_all.find('div', class_='pod-details-4_GRID').find('span').find('b').text descuento = price_tag['data-discount-percentage']if price_tag and price_tag.has_attr('data-discount-percentage')else'0%' # Verificar si hay descuento
precio_descuento = producto_all.find('div',class_='pod-summary-4_GRID').find('ol').find('li').find('span').text precio_anterior = price_tag['crossed line-height-17']if price_tag and price_tag.has_attr('crossed line-height-17')elseNone #Guardar los datos en el diccionario
diccionario['foto'].append(foto if foto else'none') diccionario['titulo'].append(titulo) diccionario['marca'].append(marca.strip()if marca else'none') diccionario['distribuidor'].append(distribuidor.strip()if distribuidor else'none') diccionario['descuento'].append(descuento.strip()if precio_descuento else'none') diccionario['precio_descuento'].append(precio_descuento.strip()if precio_descuento else'none') diccionario['precio_anterior'].append(precio_anterior.strip()if precio_anterior else'none')print(diccionario)# Guardar los datos en un archivo CSVpd.DataFrame.from_dict(diccionario).to_csv('resultados/celulares_s24_fallabela.csv', index=False)# Contar el numero de productos extraidos
print(f'Se extrajron {len(diccionario)} productos.')
En la parte de las carpetas a la izquierda hay que entrar a esa direccion y agregamos la carpeta de resultados dentro de MyDrive... y nuestro path quedaria asi: