No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Curso de Scrapy

Curso de Scrapy

Facundo García Martoni

Facundo García Martoni

Usando XPath para extraer datos

11/27
Recursos

Aportes 26

Preguntas 0

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

En este caso no es necesario // en span o bueno a mi me funciona bien sin el:
//div[contains(@class, “tags-box”)]/span[@class=“tag-item”]/a/text()

Obtuve el mismo resultado usando:

response.xpath("//div[contains(@class, 'tags-box')]//a[contains(@class, 'tag')]/text()").getall()

Resumen:
■■■■■■■

Una vez se tiene el objeto response podemos empezar a probar las expresiones Xpath, en el shell de scrapy. scrapy shell url

Hay que tener en consideración el HTML, CSS y si la página es ‘responsive’, es decir, que su HTML y la disposición de los elementos varía en función del tamaño del dispositivo (Mobile, Web, Tablet) en el que se renderiza.

  • ¿Porqué importa?.

En el momento de inspeccionar elementos con la herramienta de desarrolladores, es ideal verificar que estés extrayendo expresiones xpath de la versión del sitio web que deseas. Con una página web responsiva, tienes diferentes versiones, las clases pueden cambiar, y los objetos moverse de sitio.

De allí que hacer crawl de una página para obtener primero su HTML es tan útil. Sabes que el HTML que te trae la respuesta es del que vas a extraer tu información.

  • Expresión para traer la lista de etiquetas más famosas.

 response.xpath('//span[@class="tag-item"]/a/text()').getall()

['love', 'inspirational', 'life', 'humor', 'books', 'reading', 'friendship', 'friends', 'truth', 'simile']

Dependiendo de tus intenciones puedes guardar archivos de diferentes formas con Scrapy. Por ejemplo, si necesitas una ráida visualización de mis datos scrapeados puedo usar el comando: scrapy crawl Name_Spider -o file.jl. Esto te arroja un archivo .jl

De lo contrario también puedo hacer cosas como:


import scrapy
import pandas as pd


class Experiment(scrapy.Spider):
    name = 'Experiment'
    start_urls = ['...quotes.toscrape.com/']

    def parse(self,response):
        # Title Web page
        title = response.xpath('//h1/a/text()').get()

        # Quote
        authors = response.xpath('//small[@class="author"]/text()').getall()
        texts = response.xpath('//span[@class="text"]/text()').getall()
        

        scraped = {'Authors': authors,'Text':texts}
        data = pd.DataFrame(scraped)
        print(data)
        return data

Veo que hay muchos diciendo que se puede extraer lo que dijo Facundo de esta y de esta otra forma, por ejemplo, yo regularmente trato de hacer el ejercicio antes de que lo explique y llegué a la siguiente solución:

response.xpath('//span[@class = "tag-item"]/a/text()').getall()

Recuerden que en programación no existe una única respuesta correcta, y cada una de ellas tendrá sus pros y sus contras, algunas serán más sencillas de programar, otras más óptimas en cuanto a uso de recursos, etc…
El punto es que no dejen de explorar diversos caminos y que aprendan de la forma de programar tanto del profesor como de otras personas y con ello es como crecerán!

Pueden usar el código también de esta manera:

def parse(self, response):
        print('*' * 10)
        print('\n\n\n')
        quotes = response.xpath('//span[@class="text"]/text()').getall()
        authors = response.xpath('//small/text()').getall()
        main_tags = response.xpath('//div[@class="quote"]/div/a[position()<2]/text()').getall()
        for i in range(len(quotes)):
            print('\n')
            print(f'Quote: {quotes[i]}')
            print(f'Author: {authors[i]}')
            print(f'Main tag: {main_tags[i]}')
            print('\n')

        print('\n\n\n')
        print('*' * 10)

De esta manera, les llega la info así (por si se necesita separar dato por dato):

Quote: “The world as we have created it is a process of our thinking. It cannot be changed without changing
our thinking.”
Author: Albert Einstein
Main tag: change




Quote: “It is our choices, Harry, that show what we truly are, far more than our abilities.”
Author: J.K. Rowling
Main tag: abilities

Aquí una manera de hacerlo de forma un poco más pythonizada:

import scrapy

class QuotesSpider(scrapy.Spider):
    name = 'extract'
    start_urls = ['https://quotes.toscrape.com/']

    def parse(self, response):
        for i in response.xpath('//span[@class="text"]/text()').getall():
            print(i+'\n\n')
        
        for i in response.xpath('//span[@class="tag-item"]/a/text()').getall():
            print(i+'\n\n')
import **scrapy**

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    start_urls = [
        'url'
    ]

    def parse(self, response):
        print("*"*100)
        print('\n\n')
        title = response.xpath('//div[@class="col-md-8"]/h1/a/text()').get()
        print(f"Titulo: {title}")
        print('\n\n')

        quotes = response.xpath('//div[@class="col-md-8"]/div[@class="quote"]/span[@class="text"]/text()').getall()
        print("Citas: ")
        for quote in quotes:
            print(f"- {quote}")
        
        print('\n\n')

        tags = response.xpath('//span[@class="tag-item"]/a/text()').getall()
        print("Tags: ")
        for tag in tags:
            print(f"- {tag}")
            
        print('\n\n')
        print("*"*100)

import scrapy

#titulo = response.xpath('//div/h1/a/text()').get()
#tag = response.xpath('//div/span/a[@class="tag"]/text()').getall()
#citas= response.xpath('//div[@class="col-md-8"]/div/span[@class]/text()').getall()


class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    start_urls = []

    def parse(self, response):
        title = response.xpath('//div/h1/a/text()').get()
        tags = response.xpath('//div/span/a[@class="tag"]/text()').getall()
        citas = response.xpath('//div[@class="col-md-8"]/div/span[@class]/text()').getall()
        with open('datos.txt', 'w', encoding='utf-8') as f:
            f.write('\n\n')
            f.write('*'*25)
            f.write('\n\n')
            f.write('title = ' + title)
            f.write('\n\n')
            for i in tags:
                f.write('tag = '+ i +'\n')
            f.write('\n\n')
            for i in citas:
                f.write('citas =' + i + '\n')
            f.write('*' * 25)
            f.write('\n\n')

mi scrapper busca definiciones de palabras en ingles

import scrapy
word = input("What word are you looking for: ")
BASE_URL = f'https://www.wordsmyth.net/?level=3&ent={word}'
WORD = '//h3[@class="headword"]/text()'
DEFINITION = '//td[@class="data"]/text()'

class WordsSpider(scrapy.Spider):
    name = 'words' #unique name, you can't repeat this name in other spider
    start_urls = [
        BASE_URL
    ] 
    def parse(self, response): #this name is required in all spiders.
        print("*"*60)
        try:
            print(f"------> {response.xpath(WORD).get().upper()} <------")
        except:
            print(f"------> {word.upper()} <------")
        definitions = response.xpath(DEFINITION).getall()
        counter = 0
        for definition in definitions:
            if len(definition) > 3:
                counter +=1
                print(f"definition {counter}: {definition}")
            else:
                continue
        print("*"*60)

En la version que se descarga en 04/2022 el script para correr el siper es:

scrapy runspider <.\ruta\nombredelarchivo.py>
response.xpath('//div[contains(@class,"tags")]/a/text()').getall()

intenté sin el span ya que no se lo veía el código, funcionó

Pues a mi no me funciono no he podido imprimir nada ni con las funciones de logging de scrapy, me sale esto y si estoy en la carpeta correcta y tengo el codigo correcto.

2020-07-24 15:59:10 [scrapy.utils.log] INFO: Scrapy 2.2.1 started (bot: quotes_scraper)
2020-07-24 15:59:10 [scrapy.utils.log] INFO: Versions: lxml 4.5.2.0, libxml2 2.9.5, cssselect 1.1.0, parsel 1.6.0, w3lib 1.22.0, Twisted 20.3.0, Python 3.8.5 (tags/v3.8.5:580fbb0, Jul 20 2020, 15:43:08) [MSC v.1926 32 bit (Intel)], pyOpenSSL 19.1.0 (OpenSSL 1.1.1g  21 Apr 2020), cryptography 3.0, Platform Windows-10-10.0.18362-SP0
2020-07-24 15:59:10 [scrapy.utils.log] DEBUG: Using reactor: twisted.internet.selectreactor.SelectReactor
2020-07-24 15:59:10 [scrapy.crawler] INFO: Overridden settings:
{'BOT_NAME': 'quotes_scraper',
 'NEWSPIDER_MODULE': 'quotes_scraper.spiders',
 'ROBOTSTXT_OBEY': True,
 'SPIDER_MODULES': ['quotes_scraper.spiders']}
2020-07-24 15:59:10 [scrapy.extensions.telnet] INFO: Telnet Password: 7f4b2d1e2d6ae442
2020-07-24 15:59:10 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.logstats.LogStats']
2020-07-24 15:59:11 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2020-07-24 15:59:11 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2020-07-24 15:59:11 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2020-07-24 15:59:11 [scrapy.core.engine] INFO: Spider opened
2020-07-24 15:59:11 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2020-07-24 15:59:11 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
2020-07-24 15:59:11 [scrapy.core.engine] INFO: Closing spider (finished)
2020-07-24 15:59:11 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'elapsed_time_seconds': 0.025915,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2020, 7, 24, 20, 59, 11, 183729),
 'log_count/INFO': 10,
 'start_time': datetime.datetime(2020, 7, 24, 20, 59, 11, 157814)}
2020-07-24 15:59:11 [scrapy.core.engine] INFO: Spider closed (finished)

XPath se define como ruta XML. Es una sintaxis o lenguaje para encontrar cualquier elemento en la página web usando la expresión de ruta XML. XPath se usa para encontrar la ubicación de cualquier elemento en una página web usando la estructura HTML DOM.

Puede comenzar ejecutando la herramienta Scrapy sin argumentos e imprimirá alguna ayuda de uso y los comandos disponibles: Scrapy XY - sin proyecto activo Uso: scrapy <comando> [opciones] [args] Comandos disponibles: rastreo Ejecutar una búsqueda de araña Obtener una URL con el descargador de Scrapy.

XPath es un lenguaje para seleccionar nodos en documentos XML , que también se puede utilizar con HTML. Tanto lxml como Scrapy Selectors están construidos sobre la biblioteca libxml2, lo que significa que son muy similares en velocidad y precisión de análisis.

claramente hay una manera más simple de obtener el top ten tags, pero ciertamente es interesante prácticar la que propone facundo.

response.xpath('//div[@class="col-md-4 tags-box"]/span/a/text()').getall()

Favor actualizar la version de scrapy en la 2.4.0 no son necesarios los comandos para organizar la información

Aunque vimos en el curso Xpath dejo esta url de apoyo rapido

https://devhints.io/xpath

Comparto la funcion parse

    def parse(self, response):
        print('*' * 10)
        print('\n\n\n')
        title = response.xpath('//h1/a/text()').get()
        print(f'Titulo: {title}')
        print('\n\n')

        qoutes = response.xpath('//span[@class="text" and @itemprop="text"]/text()').getall()
        print('Citas: ')
        for quote in qoutes:
            print(f'-{quote}')
        print('\n\n')

        top_ten_tags = response.xpath('//div[contains(@class, "tags-box")]//span[@class="tag-item"]/a/text()').getall()
        print('Top Ten Tags: ')
        for tag in top_ten_tags:
            print(f'-{tag}')
        print('\n\n')

        print('\n\n\n')
        print('*' * 10)

mas sencillo, pero es mas interesante como el profesor lo hace.

('//div/a[@class="tag"]/text()').getall()

Excelente clase. No se si a ustedes les pasa lo mismo con respecto a getall()
/Entonces a la fecha Mayo / 07 / 2021. (que viva el paro Nacional en Colombia)
el comando que me funciono para traer todo es

extract()

Espero les ayude a los futuros scrapers.

Grande Facu! Genial la clase, todo muy bien explicado

el titulo lo extraje de manera mas especifica : response.xpath(’//div[@class=“col-md-8”]/h1/a/text()’).get()

top ten
response.xpath(’//div[@class=“col-md-4 tags-box”]/span/a/text()’).getall()

citas:
response.xpath(’//div[@class=“quote”]/span[@class=“text”]/text()’).getall()

Mac o Linux
scrapy shell ‘h ttp://quotes.toscrape.com/’

Windows
scrapy shell “h ttp://quotes.toscrape.com/”

interesante

  def parse(self,response): #Analize a response and bring all the information we want
    print("===============================")
    print("\n")
    print("\n")
    # print(response.status, response.headers)

    title= response.xpath('//h1/a/text()').get()
    print(f'Title: {title}')
    print("\n")

    quotes = response.xpath('//span[@class="text" and @itemprop="text"]/text()').getall()
    print(f'Quotes:')
    for quote in quotes:
      print(f'♦ {quote}')
    print("\n")

    top_tep_tags= response.xpath('//div[contains(@class,"tags-box")]//span[@class="tag-item"]/a/text()').getall()
    print('Top 10 tags:')
    for tag in top_tep_tags:
      print(f'♠{tag}')
    print("\n")

    print("\n")
    print("\n")
    print("===============================")