{"id":3264,"date":"2025-10-06T16:09:25","date_gmt":"2025-10-06T14:09:25","guid":{"rendered":"https:\/\/tecnologia.euroinnova.com\/como-hacer-web-scraping-con-python\/"},"modified":"2025-10-07T14:52:29","modified_gmt":"2025-10-07T12:52:29","slug":"como-hacer-web-scraping-con-python","status":"publish","type":"post","link":"https:\/\/tecnologia.euroinnova.com\/en\/como-hacer-web-scraping-con-python","title":{"rendered":"How to do web scraping with Python"},"content":{"rendered":"<p class=\"code-line\" data-line-start=\"0\" data-line-end=\"1\"><a id=\"Cmo_hacer_web_scraping_con_Python_0\"><\/a>El <strong>web scraping<\/strong> es el proceso de extraer informaci\u00f3n de sitios web de forma automatizada mediante scripts. Esta t\u00e9cnica es popular en sectores como:<\/p>\n<ul>\n<li class=\"has-line-data\" data-line-start=\"6\" data-line-end=\"7\"><strong>E-commerce<\/strong>: monitoreo de precios y an\u00e1lisis de la competencia.<\/li>\n<li class=\"has-line-data\" data-line-start=\"7\" data-line-end=\"8\"><strong>Ciencia de datos<\/strong>: recolecci\u00f3n masiva de datos para machine learning.<\/li>\n<li class=\"has-line-data\" data-line-start=\"8\" data-line-end=\"9\"><strong>Periodismo de datos<\/strong>: investigaciones automatizadas.<\/li>\n<li class=\"has-line-data\" data-line-start=\"9\" data-line-end=\"11\"><strong>Investigaci\u00f3n acad\u00e9mica<\/strong>: obtenci\u00f3n de datos de fuentes p\u00fablicas.<\/li>\n<\/ul>\n<p class=\"has-line-data\" data-line-start=\"11\" data-line-end=\"12\">Gracias al web scraping, se pueden recopilar datos de m\u00faltiples sitios web de manera eficiente, algo inviable manualmente. <strong>Python<\/strong> es uno de los lenguajes m\u00e1s utilizados para esta tarea, gracias a sus bibliotecas como <strong>BeautifulSoup<\/strong> y <strong>Requests<\/strong>, que permiten descargar y procesar contenido web de forma program\u00e1tica, extrayendo informaci\u00f3n como texto, enlaces e im\u00e1genes.<\/p>\n<p class=\"has-line-data\" data-line-start=\"13\" data-line-end=\"14\">Es importante tener en cuenta los aspectos legales y \u00e9ticos del scraping, ya que algunos sitios proh\u00edben esta pr\u00e1ctica mediante sus t\u00e9rminos de servicio, y existen leyes de privacidad en muchos pa\u00edses.<\/p>\n<p class=\"has-line-data\" data-line-start=\"15\" data-line-end=\"16\">En el <strong>e-commerce<\/strong>, las empresas utilizan scraping para ajustar precios en tiempo real al analizar los de sus competidores. En <strong>ciencia de datos<\/strong>, facilita la creaci\u00f3n de algoritmos y an\u00e1lisis predictivo. En el <strong>periodismo de datos<\/strong>, los periodistas extraen grandes vol\u00famenes de informaci\u00f3n de bases p\u00fablicas para descubrir patrones. En la <strong>investigaci\u00f3n acad\u00e9mica<\/strong>, los investigadores recopilan datos de sitios cient\u00edficos y acad\u00e9micos para sus estudios.<\/p>\n<p class=\"has-line-data\" data-line-start=\"17\" data-line-end=\"18\">Esta gu\u00eda te ense\u00f1ar\u00e1 a realizar web scraping con <strong>Python<\/strong> usando <strong>BeautifulSoup<\/strong> y <strong>Requests<\/strong>, abarcando desde la configuraci\u00f3n hasta la extracci\u00f3n y almacenamiento de datos, con t\u00e9cnicas avanzadas para manejar errores y evitar bloqueos.<\/p>\n<h2 class=\"code-line\" data-line-start=\"19\" data-line-end=\"20\"><a id=\"Paso_1_Preparar_el_entorno_de_trabajo_19\"><\/a><strong>Paso 1: Preparar el entorno de trabajo<\/strong><\/h2>\n<p class=\"has-line-data\" data-line-start=\"21\" data-line-end=\"22\">Antes de empezar con el web scraping, es b\u00e1sico preparar el entorno de trabajo e instalar las herramientas necesarias. Tener el entorno correctamente configurado evitar\u00e1 problemas t\u00e9cnicos futuros.<\/p>\n<p class=\"has-line-data\" data-line-start=\"23\" data-line-end=\"24\">Aseg\u00farate de usar una versi\u00f3n de Python compatible, como Python 3.6 o posterior, ya que la mayor\u00eda de las bibliotecas de scraping, como <strong>BeautifulSoup<\/strong>, requieren versiones recientes. Si utilizas versiones antiguas de Python, algunas funcionalidades pueden no estar disponibles.<\/p>\n<p class=\"has-line-data\" data-line-start=\"25\" data-line-end=\"26\">Adem\u00e1s de <strong>BeautifulSoup<\/strong>, puedes considerar otras bibliotecas como <strong>lxml<\/strong>, que procesa HTML m\u00e1s r\u00e1pido, o <strong>Scrapy<\/strong>, que es m\u00e1s avanzada y adecuada para proyectos de scraping a gran escala, como la recolecci\u00f3n de datos en m\u00faltiples p\u00e1ginas.<\/p>\n<h3 class=\"code-line\" data-line-start=\"27\" data-line-end=\"28\"><a id=\"Instalacin_de_Python_y_dependencias_necesarias_27\"><\/a><strong>Instalaci\u00f3n de Python y dependencias necesarias<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"29\" data-line-end=\"30\">Si a\u00fan no tienes <strong>Python<\/strong> instalado, puedes descargarlo desde el <a href=\"https:\/\/www.python.org\/downloads\/\" target=\"_blank\" rel=\"noopener\">sitio oficial<\/a>. Aseg\u00farate de que Python est\u00e9 correctamente instalado ejecutando el comando adecuado en tu terminal o l\u00ednea de comandos.<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"32\" data-line-end=\"34\">python --version\n<\/code><\/pre>\n<\/div>\n<p class=\"has-line-data\" data-line-start=\"35\" data-line-end=\"36\">Esto verificar\u00e1 la versi\u00f3n de Python instalada en tu sistema. Si no aparece una versi\u00f3n de Python, aseg\u00farate de que est\u00e9 correctamente instalado o en el PATH del sistema.<\/p>\n<h3 class=\"code-line\" data-line-start=\"37\" data-line-end=\"38\"><a id=\"Instalacin_de_BeautifulSoup_y_Requests_37\"><\/a><strong>Instalaci\u00f3n de BeautifulSoup y Requests<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"39\" data-line-end=\"40\"><strong>BeautifulSoup<\/strong> y <strong>Requests<\/strong> son dos de las bibliotecas m\u00e1s utilizadas para hacer web scraping con Python. Requests se utiliza para realizar solicitudes HTTP, mientras que BeautifulSoup facilita la extracci\u00f3n y el an\u00e1lisis del contenido HTML.<\/p>\n<p class=\"has-line-data\" data-line-start=\"41\" data-line-end=\"42\">Para instalarlas, ejecuta el comando correspondiente en tu terminal.<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"44\" data-line-end=\"46\">pip install beautifulsoup4 requests\n<\/code><\/pre>\n<\/div>\n<h2 class=\"code-line\" data-line-start=\"47\" data-line-end=\"48\"><a id=\"Paso_2_Hacer_una_solicitud_HTTP_a_una_pgina_web_47\"><\/a><strong>Paso 2: Hacer una solicitud HTTP a una p\u00e1gina web<\/strong><\/h2>\n<p class=\"has-line-data\" data-line-start=\"49\" data-line-end=\"50\">En web scraping, el m\u00e9todo <strong>GET<\/strong> es el m\u00e1s com\u00fan, ya que permite recuperar datos de una p\u00e1gina web sin modificarlos. En algunos casos, podr\u00edas necesitar <strong>POST<\/strong> para enviar datos al servidor, como en formularios o cuando un sitio requiere autenticaci\u00f3n.<\/p>\n<p class=\"has-line-data\" data-line-start=\"51\" data-line-end=\"52\">Tambi\u00e9n es importante manejar respuestas del servidor como redirecciones (c\u00f3digos 3xx). <strong>Requests<\/strong> te permite seguir redirecciones autom\u00e1ticamente con el par\u00e1metro <code>allow_redirects=True<\/code>.<\/p>\n<p class=\"has-line-data\" data-line-start=\"53\" data-line-end=\"54\">El primer paso es obtener el contenido HTML de la p\u00e1gina, y con <strong>Requests<\/strong>, puedes enviar solicitudes HTTP de manera eficiente.<\/p>\n<h3 class=\"code-line\" data-line-start=\"55\" data-line-end=\"56\"><a id=\"Ejemplo_bsico_de_solicitud_HTTP_55\"><\/a><strong>Ejemplo b\u00e1sico de solicitud HTTP<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"57\" data-line-end=\"58\">Este ejemplo muestra c\u00f3mo hacer una solicitud HTTP a una p\u00e1gina web usando <strong>Requests<\/strong> en Python. La solicitud obtiene el contenido HTML de la p\u00e1gina, que luego podr\u00e1s analizar para extraer los datos.<\/p>\n<p class=\"has-line-data\" data-line-start=\"59\" data-line-end=\"60\">Aseg\u00farate de que la URL sea v\u00e1lida y que el servidor permita este tipo de solicitudes.<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"63\" data-line-end=\"69\"><span class=\"hljs-keyword\">import<\/span> requests\n\nurl = <span class=\"hljs-string\">'https:\/\/ejemplo.com'<\/span>\nresponse = requests.get(url)\nhtml = response.text\n<\/code><\/pre>\n<\/div>\n<h3 class=\"code-line\" data-line-start=\"70\" data-line-end=\"71\"><a id=\"Verificar_el_estado_de_la_solicitud_70\"><\/a><strong>Verificar el estado de la solicitud<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"72\" data-line-end=\"73\">Es esencial verificar si la solicitud fue exitosa para asegurar que el servidor respondi\u00f3 correctamente. Un c\u00f3digo <strong>200<\/strong> indica \u00e9xito, pero si obtienes c\u00f3digos como <strong>404<\/strong> (no encontrada) o <strong>403<\/strong> (prohibido), debes gestionarlos adecuadamente para evitar fallos, modificando la URL o los encabezados de la solicitud si es necesario.<\/p>\n<p class=\"has-line-data\" data-line-start=\"74\" data-line-end=\"75\">A continuaci\u00f3n, se muestra c\u00f3mo verificar el estado de la solicitud y manejar posibles errores:<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"77\" data-line-end=\"82\"><span class=\"hljs-keyword\">if<\/span> response.status_code == <span class=\"hljs-number\">200<\/span>:\n    print(<span class=\"hljs-string\">\"La solicitud fue exitosa\"<\/span>)\n<span class=\"hljs-keyword\">else<\/span>:\n    print(<span class=\"hljs-string\">\"Error en la solicitud:\"<\/span>, response.status_code)\n<\/code><\/pre>\n<\/div>\n<p class=\"has-line-data\" data-line-start=\"83\" data-line-end=\"84\">Si obtienes un 404, probablemente la URL est\u00e1 mal escrita o la p\u00e1gina ya no est\u00e1 disponible. En el caso de un 403, el acceso est\u00e1 restringido, lo que podr\u00eda requerir el uso de un User-Agent diferente o incluso la implementaci\u00f3n de proxies para evitar bloqueos. Adem\u00e1s, otros c\u00f3digos como 500 (error interno del servidor) indican problemas temporales en el servidor que tambi\u00e9n pueden requerir reintentos o ajustes en las solicitudes.<\/p>\n<h2 class=\"code-line\" data-line-start=\"85\" data-line-end=\"86\"><a id=\"Qu_hacer_si_la_solicitud_falla_85\"><\/a><strong>Qu\u00e9 hacer si la solicitud falla<\/strong><\/h2>\n<p class=\"has-line-data\" data-line-start=\"87\" data-line-end=\"88\">Si obtienes un error como <strong>404<\/strong> (p\u00e1gina no encontrada) o <strong>403<\/strong> (acceso denegado), revisa que la URL sea correcta y que el contenido est\u00e9 disponible. Un <strong>403<\/strong> puede ocurrir si el servidor detecta un script automatizado. Para evitar esto, puedes modificar los <strong>headers<\/strong>, especialmente el <strong>User-Agent<\/strong>, para que la solicitud parezca provenir de un navegador real.<\/p>\n<p class=\"has-line-data\" data-line-start=\"89\" data-line-end=\"90\">Aqu\u00ed te mostramos c\u00f3mo incluir un <strong>User-Agent<\/strong> que simule el acceso desde un navegador:<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"92\" data-line-end=\"97\">headers = {\n    <span class=\"hljs-string\">'User-Agent'<\/span>: <span class=\"hljs-string\">'Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.110 Safari\/537.3'<\/span>\n}\nresponse = requests.get(url, headers=headers)\n<\/code><\/pre>\n<\/div>\n<p class=\"has-line-data\" data-line-start=\"98\" data-line-end=\"99\">Adem\u00e1s del <strong>User-Agent<\/strong>, algunos sitios pueden requerir otros encabezados como <strong>Referer<\/strong> o <strong>Cookies<\/strong> para permitir el acceso. Si persisten los problemas, revisa el archivo <strong>robots.txt<\/strong> del sitio o utiliza t\u00e9cnicas como la rotaci\u00f3n de proxies o la limitaci\u00f3n de velocidad entre solicitudes para reducir el riesgo de bloqueos y mejorar la confiabilidad del scraper.<\/p>\n<h2 class=\"code-line\" data-line-start=\"100\" data-line-end=\"101\"><a id=\"Paso_3_Analizar_y_extraer_datos_con_BeautifulSoup_100\"><\/a><strong>Paso 3: Analizar y extraer datos con BeautifulSoup<\/strong><\/h2>\n<p class=\"has-line-data\" data-line-start=\"102\" data-line-end=\"103\">Con el HTML de la p\u00e1gina, puedes usar <strong>BeautifulSoup<\/strong> para analizar y extraer los datos que necesitas. No solo permite extraer texto, sino tambi\u00e9n acceder a atributos espec\u00edficos de etiquetas HTML, como el atributo <code>src<\/code> en las im\u00e1genes.<\/p>\n<p class=\"has-line-data\" data-line-start=\"104\" data-line-end=\"105\"><strong>BeautifulSoup<\/strong> tambi\u00e9n facilita la navegaci\u00f3n por el \u00e1rbol DOM, permiti\u00e9ndote moverte entre elementos relacionados con propiedades como <code>.parent<\/code>, <code>.next_sibling<\/code> o <code>.previous_sibling<\/code>, ideal para extraer datos vinculados, como un t\u00edtulo de producto y su precio.<\/p>\n<h3 class=\"code-line\" data-line-start=\"106\" data-line-end=\"107\"><a id=\"Para_simular_una_solicitud_desde_un_navegador_106\"><\/a><strong>Para simular una solicitud desde un navegador<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"108\" data-line-end=\"109\">Algunos servidores bloquean las solicitudes automatizadas. Para evitarlo, puedes modificar los encabezados HTTP de la solicitud, especialmente el <strong>User-Agent<\/strong>, para que parezca proveniente de un navegador real.<\/p>\n<p class=\"has-line-data\" data-line-start=\"110\" data-line-end=\"111\">En este ejemplo, utilizamos la biblioteca BeautifulSoup para analizar el contenido HTML una vez que hemos obtenido una respuesta exitosa. Esto te permitir\u00e1 extraer los datos que necesitas de la estructura HTML de la p\u00e1gina.<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"113\" data-line-end=\"117\"><span class=\"hljs-keyword\">from<\/span> bs4 <span class=\"hljs-keyword\">import<\/span> BeautifulSoup\n\nsoup = BeautifulSoup(html, <span class=\"hljs-string\">'html.parser'<\/span>)\n<\/code><\/pre>\n<\/div>\n<h3 class=\"code-line\" data-line-start=\"118\" data-line-end=\"119\"><a id=\"Navegar_por_la_estructura_HTML_118\"><\/a><strong>Navegar por la estructura HTML<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"120\" data-line-end=\"121\">Una vez que hayas obtenido el contenido HTML de la p\u00e1gina web, el siguiente paso es navegar por su estructura y localizar los elementos que te interesan. Con <strong>BeautifulSoup<\/strong>, puedes buscar y seleccionar elementos espec\u00edficos del documento HTML, como etiquetas <code>&lt;div&gt;<\/code>, <code>&lt;p&gt;<\/code>, <code>&lt;a&gt;<\/code>, entre muchas otras, utilizando m\u00e9todos como <code>find()<\/code> y <code>find_all()<\/code>.<\/p>\n<p class=\"has-line-data\" data-line-start=\"122\" data-line-end=\"123\">El m\u00e9todo <code>find()<\/code> te permite seleccionar el primer elemento que coincide con un criterio espec\u00edfico, mientras que <code>find_all()<\/code> devuelve una lista de todos los elementos que coinciden con el criterio dado. Esto es muy \u00fatil cuando necesitas extraer informaci\u00f3n como t\u00edtulos, p\u00e1rrafos o enlaces de una p\u00e1gina web.<\/p>\n<p class=\"has-line-data\" data-line-start=\"124\" data-line-end=\"125\">A continuaci\u00f3n se muestra un ejemplo b\u00e1sico de c\u00f3mo encontrar y extraer el primer t\u00edtulo <code>&lt;h1&gt;<\/code> de la p\u00e1gina, as\u00ed como todos los enlaces dentro de las etiquetas <code>&lt;a&gt;<\/code>:<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"127\" data-line-end=\"136\"><span class=\"hljs-comment\"># Encontrar el primer t\u00edtulo de la p\u00e1gina<\/span>\ntitulo = soup.find(<span class=\"hljs-string\">'h1'<\/span>).text\nprint(titulo)\n\n<span class=\"hljs-comment\"># Encontrar todos los enlaces de la p\u00e1gina<\/span>\nenlaces = soup.find_all(<span class=\"hljs-string\">'a'<\/span>)\n<span class=\"hljs-keyword\">for<\/span> enlace <span class=\"hljs-keyword\">in<\/span> enlaces:\n    print(enlace.get(<span class=\"hljs-string\">'href'<\/span>))\n<\/code><\/pre>\n<\/div>\n<p class=\"has-line-data\" data-line-start=\"137\" data-line-end=\"138\">En este ejemplo, el primer t\u00edtulo de la p\u00e1gina se extrae utilizando find(\u2018h1\u2019), seguido de la propiedad .text para obtener el contenido de texto de esa etiqueta. Luego, utilizamos find_all(\u2018a\u2019) para obtener todos los enlaces de la p\u00e1gina y, en un bucle, imprimimos el atributo href de cada enlace.<\/p>\n<p class=\"has-line-data\" data-line-start=\"139\" data-line-end=\"140\">Estos m\u00e9todos permiten extraer f\u00e1cilmente la informaci\u00f3n estructurada de una p\u00e1gina HTML. Adem\u00e1s, si necesitas ser m\u00e1s espec\u00edfico, BeautifulSoup tambi\u00e9n admite filtros m\u00e1s detallados, como buscar por clases, atributos espec\u00edficos o combinaciones de etiquetas, lo que facilita el acceso a los datos exactos que necesitas.<\/p>\n<h3 class=\"code-line\" data-line-start=\"141\" data-line-end=\"142\"><a id=\"Uso_de_mtodos_como_find_y_find_all_141\"><\/a><strong>Uso de m\u00e9todos como <code>find()<\/code> y <code>find_all()<\/code><\/strong><\/h3>\n<ul>\n<li class=\"has-line-data\" data-line-start=\"143\" data-line-end=\"144\"><code>find()<\/code>: encuentra el primer elemento que coincide con el criterio.<\/li>\n<li class=\"has-line-data\" data-line-start=\"144\" data-line-end=\"146\"><code>find_all()<\/code>: encuentra todos los elementos que coinciden con el criterio especificado.<\/li>\n<\/ul>\n<h3 class=\"code-line\" data-line-start=\"146\" data-line-end=\"147\"><a id=\"Extraer_informacin_clave_146\"><\/a><strong>Extraer informaci\u00f3n clave<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"148\" data-line-end=\"149\"><strong>BeautifulSoup<\/strong> es muy \u00fatil para extraer informaci\u00f3n clave de p\u00e1ginas web, especialmente en sitios complejos como tiendas en l\u00ednea, donde los datos est\u00e1n distribuidos en diferentes partes del HTML. Puedes extraer t\u00edtulos, enlaces o p\u00e1rrafos, y usar clases espec\u00edficas de los contenedores HTML para obtener selectivamente informaci\u00f3n como nombres, precios y descripciones de productos.<\/p>\n<p class=\"has-line-data\" data-line-start=\"151\" data-line-end=\"152\">En el siguiente ejemplo, te mostramos c\u00f3mo puedes extraer datos clave de productos, como el nombre y el precio, buscando etiquetas HTML espec\u00edficas dentro de un <code>div<\/code> con una clase particular:<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"154\" data-line-end=\"160\">productos = soup.find_all(<span class=\"hljs-string\">'div'<\/span>, class_=<span class=\"hljs-string\">'producto'<\/span>)\n<span class=\"hljs-keyword\">for<\/span> producto <span class=\"hljs-keyword\">in<\/span> productos:\n    nombre = producto.find(<span class=\"hljs-string\">'h2'<\/span>).text\n    precio = producto.find(<span class=\"hljs-string\">'span'<\/span>, class_=<span class=\"hljs-string\">'precio'<\/span>).text\n    print(f<span class=\"hljs-string\">\"Producto: {nombre}, Precio: {precio}\"<\/span>)\n<\/code><\/pre>\n<\/div>\n<p class=\"has-line-data\" data-line-start=\"161\" data-line-end=\"162\">En este caso, estamos buscando todos los div con la clase \u201cproducto\u201d. Una vez que los encontramos, accedemos a los elementos h2 dentro de cada div para obtener el nombre del producto, y a las etiquetas span con la clase \u201cprecio\u201d para extraer su precio.<\/p>\n<p class=\"has-line-data\" data-line-start=\"163\" data-line-end=\"164\">Este tipo de extracci\u00f3n es \u00fatil en escenarios donde los datos est\u00e1n bien estructurados y siguen un patr\u00f3n claro. BeautifulSoup te permite definir criterios precisos para localizar y extraer estos elementos clave, y personalizar tu scraping seg\u00fan las necesidades del proyecto. A medida que tu proyecto de scraping se hace m\u00e1s complejo, tambi\u00e9n puedes combinar esta t\u00e9cnica con otras herramientas de an\u00e1lisis o almacenamiento de datos.<\/p>\n<h2 class=\"code-line\" data-line-start=\"165\" data-line-end=\"166\"><a id=\"Paso_4_Manejar_estructuras_HTML_ms_complejas_165\"><\/a><strong>Paso 4: Manejar estructuras HTML m\u00e1s complejas<\/strong><\/h2>\n<p class=\"has-line-data\" data-line-start=\"167\" data-line-end=\"168\">En p\u00e1ginas m\u00e1s complejas, debes ser m\u00e1s espec\u00edfico al seleccionar los datos. <strong>BeautifulSoup<\/strong> te permite extraer informaci\u00f3n de tablas HTML localiz\u00e1ndolas con <code>find()<\/code> y luego iterando sobre las filas y celdas con <code>find_all('tr')<\/code> y <code>find_all('td')<\/code>. Esto es \u00fatil en sitios de comercio electr\u00f3nico, donde los productos suelen estar organizados en tablas.<\/p>\n<p class=\"has-line-data\" data-line-start=\"169\" data-line-end=\"170\">Tambi\u00e9n puedes extraer datos de listas <code>&lt;ul&gt;<\/code> y <code>&lt;ol&gt;<\/code>, comunes en blogs o directorios, para obtener enlaces a art\u00edculos, categor\u00edas o descripciones.<\/p>\n<h3 class=\"code-line\" data-line-start=\"171\" data-line-end=\"172\"><a id=\"Extraer_datos_de_tablas_HTML_171\"><\/a><strong>Extraer datos de tablas HTML<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"173\" data-line-end=\"174\">Cuando trabajas con datos que se presentan en formato de tabla, como tablas de precios, horarios o listados de productos, <strong>BeautifulSoup<\/strong> te permite extraer f\u00e1cilmente la informaci\u00f3n contenida en dichas tablas. Las tablas HTML est\u00e1n estructuradas con etiquetas <code>&lt;table&gt;<\/code>, <code>&lt;tr&gt;<\/code> para las filas, y <code>&lt;td&gt;<\/code> para las celdas de datos. El proceso de extracci\u00f3n implica localizar la tabla, iterar sobre las filas y, finalmente, extraer el contenido de las celdas.<\/p>\n<p class=\"has-line-data\" data-line-start=\"175\" data-line-end=\"176\">En el siguiente ejemplo, te mostramos c\u00f3mo localizar una tabla dentro de una p\u00e1gina web y extraer sus datos fila por fila:<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"178\" data-line-end=\"185\">tabla = soup.find(<span class=\"hljs-string\">'table'<\/span>)\nfilas = tabla.find_all(<span class=\"hljs-string\">'tr'<\/span>)\n<span class=\"hljs-keyword\">for<\/span> fila <span class=\"hljs-keyword\">in<\/span> filas:\n    celdas = fila.find_all(<span class=\"hljs-string\">'td'<\/span>)\n    <span class=\"hljs-keyword\">for<\/span> celda <span class=\"hljs-keyword\">in<\/span> celdas:\n        print(celda.text)\n<\/code><\/pre>\n<\/div>\n<p class=\"has-line-data\" data-line-start=\"186\" data-line-end=\"187\">Aqu\u00ed, <code>find('table')<\/code> localiza la primera tabla en el documento HTML. Luego, <code>find_all('tr')<\/code> encuentra todas las filas dentro de la tabla, y dentro de cada fila, <code>find_all('td')<\/code> localiza todas las celdas de datos. El bucle recorre cada celda y utiliza <code>.text<\/code> para extraer el contenido de texto dentro de las etiquetas <code>&lt;td&gt;<\/code>.<\/p>\n<p class=\"has-line-data\" data-line-start=\"188\" data-line-end=\"189\">Este m\u00e9todo es \u00fatil cuando necesitas extraer y estructurar grandes vol\u00famenes de datos tabulares, permiti\u00e9ndote procesar la informaci\u00f3n de manera eficiente para su an\u00e1lisis posterior o almacenamiento en una base de datos.<\/p>\n<h3 class=\"code-line\" data-line-start=\"190\" data-line-end=\"191\"><a id=\"Seleccin_con_selectores_CSS_190\"><\/a><strong>Selecci\u00f3n con selectores CSS<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"192\" data-line-end=\"193\">Tambi\u00e9n puedes usar <strong>selectores CSS<\/strong> para obtener elementos m\u00e1s complejos, como listas de productos o tablas, en lugar de usar solo <code>find()<\/code> y <code>find_all()<\/code>. Los selectores CSS te permiten buscar elementos utilizando reglas de estilo similares a las que se aplican en una hoja de estilos, como seleccionar elementos por su clase, id, o incluso combinaciones m\u00e1s avanzadas.<\/p>\n<p class=\"has-line-data\" data-line-start=\"194\" data-line-end=\"195\">Por ejemplo, si quieres seleccionar todas las im\u00e1genes dentro de un <code>div<\/code> con una clase espec\u00edfica, puedes hacerlo con el siguiente c\u00f3digo:<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"197\" data-line-end=\"202\"><span class=\"hljs-comment\"># Seleccionar todas las im\u00e1genes dentro de un div con clase 'galeria'<\/span>\nimagenes = soup.select(<span class=\"hljs-string\">'div.galeria img'<\/span>)\n<span class=\"hljs-keyword\">for<\/span> img <span class=\"hljs-keyword\">in<\/span> imagenes:\n    print(img[<span class=\"hljs-string\">'src'<\/span>])\n<\/code><\/pre>\n<\/div>\n<p class=\"has-line-data\" data-line-start=\"203\" data-line-end=\"204\">El m\u00e9todo select() permite una selecci\u00f3n m\u00e1s flexible y precisa utilizando las mismas reglas que se aplicar\u00edan en un archivo CSS, lo que te da m\u00e1s control sobre la informaci\u00f3n que deseas extraer.<\/p>\n<h3 class=\"code-line\" data-line-start=\"205\" data-line-end=\"206\"><a id=\"Iterar_sobre_elementos_HTML_205\"><\/a><strong>Iterar sobre elementos HTML<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"207\" data-line-end=\"208\">Para extraer m\u00faltiples elementos de una p\u00e1gina, puedes iterar sobre los resultados de <code>find_all()<\/code> o <code>select()<\/code>. Esto es \u00fatil cuando trabajas con grandes vol\u00famenes de datos, como listas de productos o enlaces, permiti\u00e9ndote acceder a los atributos y contenido de cada elemento.<\/p>\n<p class=\"has-line-data\" data-line-start=\"209\" data-line-end=\"210\">Este enfoque facilita la automatizaci\u00f3n y organizaci\u00f3n eficiente de los datos, aplicando las mismas operaciones a varios elementos similares en una p\u00e1gina.<\/p>\n<h2 class=\"code-line\" data-line-start=\"211\" data-line-end=\"212\"><a id=\"Paso_5_Evitar_bloqueos_o_restricciones_211\"><\/a><strong>Paso 5: Evitar bloqueos o restricciones<\/strong><\/h2>\n<p class=\"has-line-data\" data-line-start=\"213\" data-line-end=\"214\">Es importante respetar las normas del sitio web y no sobrecargar los servidores. Muchos sitios usan mecanismos de protecci\u00f3n como CAPTCHAs o bloqueos por IP. Para evitar que tu IP sea bloqueada, puedes usar <strong>proxies rotativos<\/strong> que distribuyan las solicitudes desde diferentes direcciones IP. Servicios como <strong>ScraperAPI<\/strong> o <strong>ProxyMesh<\/strong> pueden ayudarte.<\/p>\n<p class=\"has-line-data\" data-line-start=\"215\" data-line-end=\"216\">Otra t\u00e9cnica es variar los <strong>User-Agents<\/strong> para simular navegadores reales y evitar ser detectado como un script automatizado. Tambi\u00e9n puedes a\u00f1adir intervalos aleatorios entre solicitudes usando la biblioteca <strong>time<\/strong> para reducir la carga en los servidores y simular el comportamiento humano.<\/p>\n<h3 class=\"code-line\" data-line-start=\"217\" data-line-end=\"218\"><a id=\"Manejo_de_headers_y_UserAgent_217\"><\/a><strong>Manejo de headers y User-Agent<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"219\" data-line-end=\"220\">Muchos sitios web detectan solicitudes de scripts mediante el encabezado <strong>User-Agent<\/strong>, que identifica el navegador y sistema operativo. Si no especificas un <strong>User-Agent<\/strong> adecuado, el servidor puede bloquear tu acceso.<\/p>\n<p class=\"has-line-data\" data-line-start=\"221\" data-line-end=\"222\">Para evitar bloqueos, modifica los headers de la solicitud para que simule ser de un navegador real, lo que hace que el comportamiento de tu scraper sea m\u00e1s dif\u00edcil de detectar.<\/p>\n<p class=\"has-line-data\" data-line-start=\"223\" data-line-end=\"224\">A continuaci\u00f3n, se muestra un ejemplo de c\u00f3mo a\u00f1adir un <strong>User-Agent<\/strong> com\u00fan de navegador a los headers de tu solicitud:<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"226\" data-line-end=\"232\">headers = {\n    <span class=\"hljs-string\">'User-Agent'<\/span>: <span class=\"hljs-string\">'Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/58.0.3029.110 Safari\/537.3'<\/span>\n}\n\nresponse = requests.get(url, headers=headers)\n<\/code><\/pre>\n<\/div>\n<p class=\"has-line-data\" data-line-start=\"233\" data-line-end=\"234\">Este m\u00e9todo te permite disfrazar tu scraper para que sea menos probable que sea bloqueado por el servidor. Sin embargo, algunos sitios tambi\u00e9n analizan otros headers como <strong>Referer<\/strong>, <strong>Accept-Language<\/strong> o <strong>Cookies<\/strong>, por lo que en casos m\u00e1s complejos podr\u00edas necesitar a\u00f1adir estos headers adicionales para emular mejor una solicitud de navegador real.<\/p>\n<p class=\"has-line-data\" data-line-start=\"235\" data-line-end=\"236\">Tambi\u00e9n es posible rotar diferentes <strong>User-Agents<\/strong> entre varias solicitudes para hacer que tu scraper sea a\u00fan m\u00e1s dif\u00edcil de detectar, imitando accesos desde varios navegadores o dispositivos. Esta t\u00e9cnica se puede combinar con la rotaci\u00f3n de proxies y la simulaci\u00f3n de tiempos de respuesta variables, para evitar restricciones o bloqueos.<\/p>\n<h3 class=\"code-line\" data-line-start=\"237\" data-line-end=\"238\"><a id=\"Respetar_el_archivo_robotstxt_237\"><\/a><strong>Respetar el archivo robots.txt<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"239\" data-line-end=\"240\">El archivo <strong>robots.txt<\/strong> indica qu\u00e9 \u00e1reas de un sitio web est\u00e1n permitidas o prohibidas para el acceso automatizado de scrapers. Se encuentra en la ra\u00edz del sitio (por ejemplo, <code>https:\/\/ejemplo.com\/robots.txt<\/code>) y contiene directrices para bots.<\/p>\n<p class=\"has-line-data\" data-line-start=\"241\" data-line-end=\"242\">Respetar estas reglas es clave para evitar problemas legales o bloqueos. Aunque <strong>robots.txt<\/strong> no bloquea t\u00e9cnicamente el acceso, ignorarlo puede llevar a bloqueos de IP o CAPTCHAs, y en algunas jurisdicciones, el scraping contra las pol\u00edticas del sitio puede ser ilegal.<\/p>\n<h3 class=\"code-line\" data-line-start=\"243\" data-line-end=\"244\"><a id=\"Intervalos_entre_solicitudes_243\"><\/a><strong>Intervalos entre solicitudes<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"245\" data-line-end=\"246\">Para evitar sobrecargar el servidor y reducir el riesgo de bloqueo, es recomendable a\u00f1adir un <strong>intervalo<\/strong> entre solicitudes. Enviar muchas solicitudes en poco tiempo puede hacer que el servidor bloquee tu IP o aplique restricciones como CAPTCHAs.<\/p>\n<p class=\"has-line-data\" data-line-start=\"247\" data-line-end=\"248\">A\u00f1adir pausas entre peticiones no solo imita el comportamiento humano, sino que respeta los recursos del servidor y minimiza la probabilidad de ser bloqueado.<\/p>\n<p class=\"has-line-data\" data-line-start=\"249\" data-line-end=\"250\">En Python, puedes implementar un intervalo entre las solicitudes utilizando la funci\u00f3n <code>time.sleep()<\/code> para introducir pausas. A continuaci\u00f3n, un ejemplo que implementa una pausa de 2 segundos entre cada solicitud:<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"252\" data-line-end=\"255\"><span class=\"hljs-keyword\">import<\/span> time\ntime.sleep(<span class=\"hljs-number\">2<\/span>)  <span class=\"hljs-comment\"># Pausa de 2 segundos<\/span>\n<\/code><\/pre>\n<\/div>\n<p class=\"has-line-data\" data-line-start=\"256\" data-line-end=\"257\">Es recomendable variar la duraci\u00f3n de las pausas de manera aleatoria para hacer que el scraper sea a\u00fan m\u00e1s dif\u00edcil de detectar. Puedes combinar esto con otras pr\u00e1cticas, como la rotaci\u00f3n de proxies y User-Agents, para garantizar que tus solicitudes se realicen de manera eficiente y sin interrupciones.<\/p>\n<h2 class=\"code-line\" data-line-start=\"258\" data-line-end=\"259\"><a id=\"Paso_6_Guardar_los_datos_extrados_258\"><\/a><strong>Paso 6: Guardar los datos extra\u00eddos<\/strong><\/h2>\n<p class=\"has-line-data\" data-line-start=\"260\" data-line-end=\"261\">Una vez extra\u00eddos los datos, el siguiente paso es almacenarlos para su uso posterior. Guardarlos en un archivo <strong>CSV<\/strong> es una opci\u00f3n com\u00fan, pero para grandes vol\u00famenes de datos o scraping continuo, es m\u00e1s eficiente usar bases de datos como <strong>MySQL<\/strong>, <strong>PostgreSQL<\/strong> o <strong>MongoDB<\/strong>, que permiten consultas r\u00e1pidas y an\u00e1lisis en tiempo real.<\/p>\n<p class=\"has-line-data\" data-line-start=\"262\" data-line-end=\"263\">Si est\u00e1s scrapeando im\u00e1genes o archivos, puedes almacenarlos en servicios de almacenamiento en la nube como <strong>Amazon S3<\/strong>, lo que facilita la gesti\u00f3n de grandes cantidades de datos multimedia.<\/p>\n<h3 class=\"code-line\" data-line-start=\"264\" data-line-end=\"265\"><a id=\"Almacenar_los_datos_en_archivos_locales_264\"><\/a><strong>Almacenar los datos en archivos locales<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"266\" data-line-end=\"267\">Puedes guardar los datos en un archivo CSV para an\u00e1lisis posterior o utilizar otros formatos como JSON.<\/p>\n<div style=\"background-color: #f3f4f6; border-radius: .75rem; padding: 1rem;\">\n<pre><code class=\"has-line-data\" data-line-start=\"269\" data-line-end=\"282\"><span class=\"hljs-keyword\">import<\/span> csv\n\n<span class=\"hljs-comment\"># Abrir archivo CSV en modo escritura<\/span>\n<span class=\"hljs-keyword\">with<\/span> open(<span class=\"hljs-string\">'datos.csv'<\/span>, <span class=\"hljs-string\">'w'<\/span>, newline=<span class=\"hljs-string\">''<\/span>) <span class=\"hljs-keyword\">as<\/span> archivo_csv:\n    writer = csv.writer(archivo_csv)\n    \n    <span class=\"hljs-comment\"># Escribir encabezados<\/span>\n    writer.writerow([<span class=\"hljs-string\">'T\u00edtulo'<\/span>, <span class=\"hljs-string\">'Enlace'<\/span>])\n\n    <span class=\"hljs-comment\"># Escribir datos (ejemplo de un bucle)<\/span>\n    <span class=\"hljs-keyword\">for<\/span> enlace <span class=\"hljs-keyword\">in<\/span> enlaces:\n        writer.writerow([titulo, enlace.get(<span class=\"hljs-string\">'href'<\/span>)])\n<\/code><\/pre>\n<\/div>\n<h3 class=\"code-line\" data-line-start=\"283\" data-line-end=\"284\"><a id=\"Opciones_adicionales_de_almacenamiento_283\"><\/a><strong>Opciones adicionales de almacenamiento<\/strong><\/h3>\n<p class=\"has-line-data\" data-line-start=\"285\" dat \n\n","protected":false},"excerpt":{"rendered":"<p>El web scraping es el proceso de extraer informaci\u00f3n de sitios web de forma automatizada mediante scripts. Esta t\u00e9cnica es [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":881,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[1],"tags":[],"class_list":["post-3264","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sin-categorizar"],"acf":[],"_links":{"self":[{"href":"https:\/\/tecnologia.euroinnova.com\/en\/wp-json\/wp\/v2\/posts\/3264","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tecnologia.euroinnova.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tecnologia.euroinnova.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tecnologia.euroinnova.com\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/tecnologia.euroinnova.com\/en\/wp-json\/wp\/v2\/comments?post=3264"}],"version-history":[{"count":0,"href":"https:\/\/tecnologia.euroinnova.com\/en\/wp-json\/wp\/v2\/posts\/3264\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tecnologia.euroinnova.com\/en\/wp-json\/wp\/v2\/media\/881"}],"wp:attachment":[{"href":"https:\/\/tecnologia.euroinnova.com\/en\/wp-json\/wp\/v2\/media?parent=3264"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tecnologia.euroinnova.com\/en\/wp-json\/wp\/v2\/categories?post=3264"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tecnologia.euroinnova.com\/en\/wp-json\/wp\/v2\/tags?post=3264"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}