Para construir un scraper que descargue cómics de sitios web, empleamos Python con bibliotecas específicas. Las herramientas clave incluyen requests para solicitudes HTTP, BeautifulSoup para el análisis del DOM HTML, y threading para gestionar descargas concurrentes. El proceso general se divide en tres fases: obtención de datos iniciales, extracción de enlaces de capítulos, y descarga paralela de imágenes.
Fase 1: Búsqueda y Selección del Cómic
El usuario proporciona el nombre del cómic. Construimos la URL de búsqueda codificando el término. Tras realizar la petición, parseamos el HTML para extraer los resultados coincidentes, mostrando títulos y características para que el usuario elija uno.
import urllib.parse
import requests
from bs4 import BeautifulSoup
comic_name = input("Introduzca el nombre del cómic: ")
query = urllib.parse.urlencode({'keyword': comic_name})
search_url = f"https://www.mkzhan.com/search/?{query}"
response = requests.get(search_url)
soup = BeautifulSoup(response.text, 'lxml')
results = soup.select('div.common-comic-item')
titles = []
links = []
descriptions = []
for item in results:
anchor = item.select_one('p.comic__title > a')
titles.append(anchor.get_text())
links.append(anchor['href'])
descriptions.append(item.select_one('p.comic-feature').get_text())
print("Resultados encontrados:")
for idx, (title, desc) in enumerate(zip(titles, descriptions), start=1):
print(f"{idx}. {title} - {desc}")
choice = int(input("Seleccione el número del cómic: "))
selected_title = titles[choice - 1]
print(f"Ha seleccionado: {selected_title}")
Fase 2: Extracción de Capítulos
Una vez elegido el cómic, concatenamos su enlace relativo a la base del dominio. Analizamos la página del cómic para localizar la lista de capítulos, extrayendo sus enlaces y nombres. Estos datos se almacenan en listas para su uso posterior.
comic_link = f"https://www.mkzhan.com{links[choice - 1]}"
comic_page = requests.get(comic_link)
comic_soup = BeautifulSoup(comic_page.text, 'lxml')
chapter_list_container = comic_soup.select_one('ul.chapter__list-box.clearfix.hide')
chapter_elements = chapter_list_container.select('li > a')
chapter_links = [chap['data-hreflink'] for chap in chapter_elements]
chapter_names = [chap.get_text().strip() for chap in chapter_elements]
Fase 3: Descarga con Hilos
Para acelerar el proceso, definimos funciones que descarguen las imágenes de un capítulo. Utilizamos un pool de hilos que trabajan de forma concurrente, extrayendo URLs de imágenes del contenido de cada capítulo y guardándolas localmente. Se crea una estructura de driectorios anidados para organizar los archivos.
import os
import threading
def download_chapter_images(chapter_url, save_path):
headers = {'User-Agent': 'Mozilla/5.0'}
chapter_page = requests.get(f"https://www.mkzhan.com{chapter_url}", headers=headers)
chapter_soup = BeautifulSoup(chapter_page.text, 'lxml')
image_tags = chapter_soup.select('div.rd-article__pic.hide > img.lazy-read')
image_urls = [img['data-src'] for img in image_tags]
for img_idx, img_url in enumerate(image_urls, start=1):
img_data = requests.get(img_url, headers=headers).content
file_path = os.path.join(save_path, f"{img_idx}.jpg")
with open(file_path, 'wb') as file:
file.write(img_data)
return True
def worker(ch_links, ch_names):
while ch_links:
link = ch_links.pop()
name = ch_names.pop()
folder_path = f"./{selected_title}/{name}"
try:
os.makedirs(folder_path, exist_ok=True)
if download_chapter_images(link, folder_path):
print(f"Hilo {threading.current_thread().name} completó: {name}")
except Exception:
pass
os.makedirs(selected_title, exist_ok=True)
threads = []
for _ in range(30):
t = threading.Thread(target=worker, args=(chapter_links, chapter_names))
t.start()
threads.append(t)
for t in threads:
t.join()
print("Descarga finalizada.")