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, 鈥渢ags-box鈥)]/span[@class=鈥渢ag-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 鈥榬esponsive鈥, 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: 鈥淭he 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: 鈥淚t 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=鈥渃ol-md-8鈥漖/h1/a/text()鈥).get()

top ten
response.xpath(鈥//div[@class=鈥渃ol-md-4 tags-box鈥漖/span/a/text()鈥).getall()

citas:
response.xpath(鈥//div[@class=鈥渜uote鈥漖/span[@class=鈥渢ext鈥漖/text()鈥).getall()

Mac o Linux
scrapy shell 鈥榟 ttp://quotes.toscrape.com/鈥

Windows
scrapy shell 鈥渉 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("===============================")