No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Aprende todo un fin de semana sin pagar una suscripci贸n 馃敟

Reg铆strate

Comienza en:

3D
15H
29M
39S
Curso de Scrapy

Curso de Scrapy

Facundo Garc铆a Martoni

Facundo Garc铆a Martoni

Finalizando la creaci贸n del spider

21/27
Recursos

Aportes 26

Preguntas 5

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

No todos los parrafos de los documentos tienen la misma estructura o est谩n en el mismo order. Con la expresi贸n del body dada en la clase algunos parrafos me salieron vac铆os. Llegu茅 a esta expresi贸n para obtener la descripci贸n completa de los documentos

body = ''.join(response.xpath('//div[contains(@class, "field-item")]/p[not(child::strong and child::i) and not(@class)]/text()').getall())

Nueva etiqueta para el titulo :

In [7]: response.xpath('//h3/a/text()').get()
Out[7]: 'Lunik on Loan: A Space Age Spy Story'```

02/08/2022
Si cuando al final de la clase quieres ver el archivo en Json y no te deja, prueba este codigo:

import scrapy

# XPATHS

# Links
XPATH_LINKS_DECLASSIFIED = '//a[starts-with(@href, "collection") and (parent::h3|parent::h2)]/@href'
# Titles:
XPATH_TITLES = '//h1[@class="documentFirstHeading"]/text()'
# Body
XPATH_PARAGRAPHS = '//div[@class="field-item even"]//p[not(@class)]/text()'


class SpiderCIA(scrapy.Spider):

    name = 'cia'
    start_urls = [
        'https://www.cia.gov/readingroom/historical-collections'
    ]

    custom_settings = {
        'FEEDS': {
            'cia.json': {
                'format': 'json',
                'encoding': 'utf-8',
                'indent': 4,
            }
        },
    }

    def parse(self, response):
        links_declassified = response.xpath(XPATH_LINKS_DECLASSIFIED).getall()
        for link in links_declassified:
            yield response.follow(link, callback=self.parse_link, cb_kwargs={'url': response.urljoin(link)})

    def parse_link(self, response, **kwargs):
        link = kwargs['url']
        title = response.xpath(XPATH_TITLES).get()
        #paragraphs = response.xpath(XPATH_PARAGRAPHS)[1::].getall()
        paragraphs = response.xpath(XPATH_PARAGRAPHS).getall()

        yield {
            'url': link,
            'title': title,
            'body': paragraphs
        }

Updated 08.01.2021:

import scrapy

# XPATHS

# Links
XPATH_LINKS_DECLASSIFIED = '//a[starts-with(@href, "collection") and (parent::h3|parent::h2)]/@href'
# Titles:
XPATH_TITLES = '//h1[@class="documentFirstHeading"]/text()'
# Body
XPATH_PARAGRAPHS = '//div[@class="field-item even"]//p[not(@class)]/text()'

class SpiderCIA(scrapy.Spider):

    name = 'cia'
    start_urls = [
        'https://www.cia.gov/readingroom/historical-collections'
    ]

    custom_settings={
        'FEEDS':{
            'cia.json':{
                'format': 'json',
                'encoding': 'utf-8',
                'indent': 4,
                }
                },
    }

    def parse(self, response):
        links_declassified = response.xpath(XPATH_LINKS_DECLASSIFIED).getall()
        for link in links_declassified:
            yield response.follow(link, callback=self.parse_link, cb_kwargs={'url': response.urljoin(link)})

    def parse_link(self, response, **kwargs):
        link = kwargs['url']
        title = response.xpath(XPATH_TITLES).get()
        #paragraphs = response.xpath(XPATH_PARAGRAPHS)[1::].getall()
        paragraphs = response.xpath(XPATH_PARAGRAPHS).getall()

        yield {
            'url': link,
            'title': title,
            'body': paragraphs
        }

Con esta versi贸n en el body se extraen todos los 鈥減谩rrafos鈥. En algunos comentarios he visto versiones alternativas para extraer s贸lo el primer p谩rrafo teniendo en cuenta que no todos los art铆culos tienen la misma estructura que Facundo explic贸 en el tutorial.

https://devhints.io/xpath
para que no olviden los predicados

Aporte: si bien algunas informes tienen mas de un parrafo podemos ejecutar la siguiente linea de codigo.

response.xpath('normalize-space(//div[@class="field-item even"]/p/text())').getall()

Si bien getall() genera una lista con varios parrafos normalize-space genera una lista con un solo elemento lo cual nos facilita manejar el parrafo.

AngelFA04. Siento la respuesta muy generica y no se ha puesto en duda lo poderoso que sea. Pero si he visto en varias documentaciones que solo recomiendan Xpath sobre CSS Selector cuando ya es muy dificil extraer data con este. Asi que me gustaria conocer puntualmente esas ventaja/desventaja por parte del profesor o alguien experto en el tema.

Hola @facundo y demas compa帽eros.

Alguien me puede explicar cual es mas recomendado de usar entre CSS Selectors o Xpath?
Cual seria el escenario ideal para cada uno?

He visto varias documentaciones donde recomiendan el uso de CSS Selectors. Agradecere sus comentarios.

Saludos

Por alguna raz贸 cuando intento correrlo como Facundo me arroja el json sin estar dentro de corchetes y adem谩s sin comas.

Si lo corro con:

scrapy crawl cia -o cia.json```
eso no pasa

En mi opinion con CSS tienes una sintaxis mas limpia y f谩cil de leer, pero XPATH es mucho m谩s poderoso.

Amigos aqu铆 solucionado para traer todos los p谩rrafos en uno solo y guardar en nuestro json.

title = response.xpath('//h1[@class="documentFirstHeading"]/text()').get()
      contents = response.xpath('//div[@class="content"]//div[@class="field-items"]/div[@class="field-item even"]/p[not(@class)]/text()').getall()
      contents = ' '.join(contents)

si al ejecutar el programa, genera un archivo vacio.

Me sirvi贸 cambiar los custom settings de esta manera, y ya me gener贸 el documento completo,

custom_settings = {
        'FEEDS': {
            'cia.json': {
                'format': 'json',
                'encoding': 'utf-8',
                'indent': 4,
            }
        },
    }

Hola a todos, comparto mi c贸digo mas reciente y funcional
NOTA: Mi inter茅s es la ciencia de datos, por lo que lo extraje tipo csv y poder tener datos para aplicarle un NLP mas f谩cilmente.

import scrapy

## links = '//div[@class="content"]//li[@class="leaf"]/a/@href'
# title = //li[@class="leaf active-trail"]/a/text()
# Body = //div[@class="content clearfix"]//p[not(child::strong and child::i) and not(@class)]/text()

class Cia(scrapy.Spider):
    name = 'cia'
    start_urls = ['https://www.cia.gov/readingroom/historical-collections']
    custom_settings = {
        'FEED_URI' : 'cia.csv',
        'FEED_FORMAT':'csv',
        'FEED_EXPORT_ENCODING':'utf-8'  
    }


    def parse(self,response):
        links_desclassified = response.xpath('//div[@class="content"]//li[@class="leaf"]/a/@href').getall()
        # Recorrer todos los links para extraer la informaci贸n.
        for link in links_desclassified:
            yield response.follow(link,callback=self.parse_link,cb_kwargs= {
                                                                            'url':response.urljoin(link)            
                                                                            })


    def parse_link(self,response,**kwargs):
        link = kwargs['url']
        title = response.xpath('//li[@class="leaf active-trail"]/a/text()').get()
        body = response.xpath('//div[@class="content clearfix"]//p[not(child::strong and child::i) and not(@class)]/text()').get()
        
        
        yield {
            'url':link,
            'title':title,
            'body':body
        }

bueno 鈥 v铆 que a muchos les daba vac铆o el json, por lo que decid铆 no poner el custom files y esas caracter铆sitcas ponerlas en la terminal

scrapy crawl cia -o quotess.json

entonces 鈥
el c贸digo actualizado a la fecha de hoy es

import scrapy

# XPath

# traser los links => response.xpath('//blockquote/p/a/@href').getall() 
# primer pparafo firstp=response.xpath('//div[@class="field-item even"]//p/text()').getall()
# title tittle = response.xpath('//h1/text()').get()

class SpiderCIA(scrapy.Spider):
    name = 'cia'
    start_urls = [
        'https://www.cia.gov/readingroom/'
    ]
   
    def parse(self, response):
        links_declassified = response.xpath('//blockquote/p/a/@href').getall()
        for link in links_declassified:
            yield response.follow(link, callback=self.parse_link, cb_kwargs={'url': response.urljoin(link)})

    def parse_link(self, response, **kwargs):
        link = kwargs['url']
        title = response.xpath('//h1/text()').get()
        firstp =response.xpath('//div[@class="field-item even"]//p/text()').getall()

        yield {
            'url': link,
            'title': title,
            'body': firstp
        }

no es la mejor, queda limpiar algo pero les soluciona el problema de que no impirme nada, adem谩s como ven est谩n cambiando la estructura de la web bastante seguido, suerte!

Mi expresi贸n para obtener los p谩rrafos:

//div[contains(@class, "field-item even")]/p[not(@class)]/descendant-or-self::*/text()

Para obtener el texto de los p junto a sus hijos de distinta etiqueta

'//div[@class="field-item even"]//p[not(@class)]/descendant-or-self::node()/text()'

Ayuda!!!
mi .codigo no imprime nada en el archivo .json, alguna recomendaci貌n??

import scrapy

#XPATH
#links = //a[starts-with(@href, "collection") and(parent::h3|parent::h2)]/@href
#title = //h1 [@class = "documentFirstHeading"]/text()
#Paragraph = //div [@class = "field-item even"]/p/text()

class SpiderCIA (scrapy.Spider):
    name = 'cia'
    start_urls: ['https://www.cia.gov/library/readingroom/historical-collections']

    custom_settings = {
        'FEED_URI': 'cia.json',
        'FEED_FORMAT': 'json',
        'FEED_EXPORT_ENCODING': 'utf-8'
    }

    def parse (self, response):
        links_declassified = response.xpath('//a[starts-with(@href, "collection") and(parent::h3|parent::h2)]/@href').getall()
        for link in links_declassified:
            yield response.follow(link, callback = self.parse_link, cb_kwargs={'url':response.urljoin(link)})
    
    def parse_link (self, response, **kwargs):
        link = kwargs['url']
        title = response.xpath('//h1 [@class = "documentFirstHeading"]/text()').get()
        paragraph = response.xpath('//div [@class = "field-item even"]/p/text()').get()

        yield {
            'url': link,
            'title': title,
            'body': paragraph,
        }`

No me funcion贸 el xpath propuesto por Facundo para obtener el body en este articulo https://www.cia.gov/readingroom/collection/aquiline. En su lugar implement茅 este:

"".join(response.xpath('//div[@class="field-item even"]/p[3]/text()').getall()) 

Si se fijan, hay un join de una lista porque en mi caso, el body tenia un elemento <i> que hace que el xpath rompa el parrafo en 2 partes鈥 por eso hago un getall() y luego junto los elementos de la lista.

Scrapy 2.4.0 - no active project

Unknown command: crawl

Use 鈥渟crapy鈥 to see available commands mmm me puedes ayudar con este error por favor.

interesante

Intente almacenar los 鈥渜ueries鈥 en un archivo .yaml para acceder a ellos como en el proyecto del curso con el profe david, pero obtengo un error de que el modulo yaml no existe, estuve investigando y segun lo que entiendo podria ser por un problema de versiones con la libreria yaml, intente en color el archivo yaml en todos los niveles de identecion del scrapper y seguia sin funcionar alguien ha intentado algo parecido?

excelente, que bien. Los trucos , lo mejor

Con fetch podemos ir a otra url, por ejemplo:

>>> fetch('https://www.cia.gov/library/readingroom/collection/lunik-loan-space-age-spy-story')

en mi caso la primera tenia un p谩rrafo que no dec铆a nada pero tenia otro nodo strong al no llamarlo si me tra铆a el primer p谩rrafo

response.xpath('//div[@class="field-item even"]//p[not(@class) and not(strong)]/text()').get()

Buen d铆a,

aveces el primer item con etiqueta <p> puede ser un pie de imagen, con esta peque帽a l贸gica se puede extraer el verdadero body:

  • Primero no usar .get() sino usar .getall() para que me extraiga la lista y despu茅s:
if len(paragraph[0]) > 30:
            paragraph = paragraph[0]
        else:
            paragraph = paragraph[1]