es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Scrapy/Python: esperar a que una solicitud de yield termine antes de ejecutar el código (descarga de imágenes)

Tengo un proyecto cuyo propósito es extraer todos los capítulos de un libro (parsear), luego para cada capítulo, descargar las imágenes (parse_chapter) y crear un archivo PDF para el capítulo (create_pdf).

Aquí está mi código (ejemplo mínimo de trabajo):

def parse(self, response):
        chapters = response.xpath('/html/body/div[1]/div/div[1]/div/div[4]/div/ul/li[1]/h5/a/@href')

    for chapter in chapters:
        yield scrapy.Request(chapter.get(), callback=self.parse_chapter)


def parse_chapter(self, response):
        logging.debug("parse_chapter")

    image_urls = response.xpath('/html/body/div[1]/div[3]/div/div[2]/div[2]/a/img/@src').get()

    yield {
        'image_urls' : image_urls
    }

    self.create_pdf()
    # una vez que se crea el PDF => eliminar todas las imágenes


def create_pdf(self):
        files = os.listdir(os.getcwd() + '/tmp/')
        if len(files) > 0:
            ...

Además, ya modifiqué los archivos settings.py y pipelines.py.

El problema es: la función create_pdf se llama antes de que todas las imágenes se descarguen. ¿Hay alguna manera de esperar a que la solicitud de yield termine antes de ejecutar create_pdf?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Sí, se puede usar la palabra clave yield para pausar la ejecución de parse_chapter() hasta que se descarguen todas las imágenes. Puede modificar parse_chapter() de la siguiente manera:

    def parse_chapter(self, response):
        logging.debug("parse_chapter")
    
        image_urls = response.xpath('/html/body/div[1]/div[3]/div/div[2]/div[2]/a/img/@src').getall()
    
        for image_url in image_urls:
            yield scrapy.Request(image_url, callback=self.save_image)
    
        # pausar la ejecución hasta que se descarguen todas las imágenes
        yield {'pdf_created': self.create_pdf()}
    
    def save_image(self, response):
        file_name = response.url.split('/')[-1]
        with open(os.getcwd() + '/tmp/' + file_name, 'wb') as f:
            f.write(response.body)
    
    def create_pdf(self):
        files = os.listdir(os.getcwd() + '/tmp/')
        if len(files) > 0:
            ...
    

    En parse_chapter(), iteramos sobre todas las image_urls y creamos una solicitud para cada imagen usando scrapy.Request(). También emitimos un diccionario con una clave de 'pdf_created' y un valor de self.create_pdf(). Esto pausará la ejecución hasta que se procesen todas las solicitudes de imagen y se devuelvan sus respuestas por Scrapy.

    En create_pdf(), verificamos la presencia de archivos de imagen en el directorio /tmp/ como antes. Sin embargo, ahora llamamos a esta función solo después de que se hayan descargado todas las imágenes.

    Tenga en cuenta que la respuesta de parse_chapter() contendrá tanto las URL de las imágenes como la clave 'pdf_created'. Deberá modificar su pipeline para manejar correctamente este diccionario.

Comments are closed.