File size: 7,020 Bytes
4792bae e6dafd1 4792bae e564101 e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 e564101 e6dafd1 e564101 e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 4792bae e6dafd1 e564101 e6dafd1 e564101 e6dafd1 e564101 e6dafd1 e564101 e6dafd1 e564101 e6dafd1 e564101 e6dafd1 e564101 e6dafd1 4792bae e6dafd1 4792bae e6dafd1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | import requests
from bs4 import BeautifulSoup
import os
from weasyprint import HTML, CSS
from PIL import Image
from io import BytesIO
import re
import random
import mimetypes
import json
import time
class WebScrapperTool:
"""Herramienta para hacer scraping de páginas web y convertir a diferentes formatos"""
def __init__(self, output_dir):
"""Inicializa la herramienta
Args:
output_dir: Directorio donde se guardarán los archivos
"""
self.output_dir = output_dir
self.session = self._create_session()
# Crear directorio de salida si no existe
if not os.path.exists(output_dir):
os.makedirs(output_dir)
def _create_session(self):
"""Crea una sesión de requests con user agent aleatorio"""
session = requests.Session()
# Lista de user agents comunes
user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.67'
]
# Configurar headers con user agent aleatorio
headers = {
'User-Agent': random.choice(user_agents),
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3',
'Upgrade-Insecure-Requests': '1',
'DNT': '1', # Do Not Track
}
session.headers.update(headers)
return session
def is_image_url(self, url):
"""Verifica si una URL es una imagen basándose en la extensión y/o Content-Type
Args:
url: URL a verificar
Returns:
bool: True si es una imagen, False en caso contrario
"""
# Verificar por extensión de archivo
image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp', '.tiff']
if any(url.lower().endswith(ext) for ext in image_extensions):
return True
# Verificar por Content-Type
try:
response = self.session.head(url, timeout=10)
content_type = response.headers.get('Content-Type', '')
return content_type.startswith('image/')
except:
# Si falla la verificación por header, intentamos con la extensión solamente
return False
def get_image_metadata(self, url):
"""Obtiene metadatos de una imagen
Args:
url: URL de la imagen
Returns:
dict: Diccionario con metadatos
"""
try:
# Obtener la imagen
response = self.session.get(url, timeout=10)
response.raise_for_status()
# Metadatos básicos
metadata = {
'URL': url,
'Content-Type': response.headers.get('Content-Type', 'Desconocido'),
'Tamaño (bytes)': len(response.content),
}
# Intentar obtener dimensiones
try:
img = Image.open(BytesIO(response.content))
metadata['Dimensiones'] = f"{img.width}x{img.height} píxeles"
metadata['Formato'] = img.format
metadata['Modo'] = img.mode
except:
metadata['Dimensiones'] = "No se pudieron determinar"
return metadata
except Exception as e:
return {'Error': str(e)}
def scrape_to_text(self, url, output_path=None):
"""Hace scraping de una URL y guarda el contenido como texto plano
Args:
url: URL para hacer scraping
output_path: Ruta donde guardar el archivo de texto
Returns:
str: Ruta al archivo generado
"""
try:
# Obtener contenido de la página
response = self.session.get(url, timeout=15)
response.raise_for_status()
# Parsear HTML
soup = BeautifulSoup(response.text, 'html.parser')
# Eliminar scripts, estilos y elementos no visibles
for element in soup(['script', 'style', 'head', 'title', 'meta', '[document]']):
element.extract()
# Obtener texto
text = soup.get_text(separator='\n')
# Limpiar espacios en blanco excesivos
lines = [line.strip() for line in text.split('\n')]
text = '\n'.join(line for line in lines if line)
# Generar nombre de archivo si no se proporciona
if not output_path:
filename = f"texto_{int(time.time())}.txt"
output_path = os.path.join(self.output_dir, filename)
# Guardar texto en archivo
with open(output_path, 'w', encoding='utf-8') as f:
f.write(f"URL: {url}\n\n")
f.write(text)
return output_path
except Exception as e:
raise Exception(f"Error al hacer scraping a texto: {str(e)}")
def scrape_to_pdf(self, url, output_path=None):
"""Hace scraping de una URL y guarda el contenido como PDF
Args:
url: URL para hacer scraping
output_path: Ruta donde guardar el archivo PDF
Returns:
str: Ruta al archivo generado
"""
try:
# Generar nombre de archivo si no se proporciona
if not output_path:
filename = f"documento_{int(time.time())}.pdf"
output_path = os.path.join(self.output_dir, filename)
# CSS para mejorar el estilo del PDF
css_string = """
@page {
margin: 1cm;
}
body {
font-family: Arial, sans-serif;
line-height: 1.5;
font-size: 12px;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 1em;
margin-bottom: 0.5em;
}
p {
margin-bottom: 0.5em;
}
img {
max-width: 100%;
height: auto;
}
"""
# Generar PDF
HTML(url=url).write_pdf(
output_path,
stylesheets=[CSS(string=css_string)]
)
return output_path
except Exception as e:
raise Exception(f"Error al convertir a PDF: {str(e)}")
|