No tienes acceso a esta clase

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

Operadores en Xpath

11/21
Recursos

Aportes 23

Preguntas 2

Ordenar por:

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

RESUMEN:Operadores en Xpath

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

Hay una forma de filtrar más avanzada y es con operadores lógicos.

Operadores lógicos en Xpath :
Cabe notar que los operadores se están usando dentro del predicado.

  • !=
  • <>
  • and
  • or
  • not

Ejemplo:

#Usando el operador != diferente, le estoy diciendo que me
traiga todos los nodos span que tienen clase diferente a Texto.

$x('//span[@class!="text"]')

# Usando operador not me devuelve todos los nodos que no tienen
el atributo class.

$x('//span[not(@class)]'

XPATH CSS Selector
!= :not(attr = value)
position()
attr1 AND attr2 [attr1][attr2]
selector[attr1 OR attr2] selector1, selector2
NOT() :not(attr or selector)
# span con clase diferente de text
$$('span[class]:not(.text)')

# span de clase text y atributo itemprop
$$('span.text[itemprop]')

# span con clase text o tag-item
$$('span.text, span.tag-item')

# span que no tienen atributo de clase
$$('span:not([class])')

*Css no tiene un forma nativa de usar el position de xpath, pero se pueden herramientas del lenguaje de programacion, como los slices de python

$x('//span[@class!="text"]') // todos los span que tenga una clase distinta de "text"

$x('/html/body/div/div[position()=1]') // trae los elementos en la posicion 1

$x('/html/body/div/div[position()>1]') // trae todos los elementos que se encuentran despues de la posicion 1

$x('//span[@class="text" and @class="tag-item"]') // trae los elementos que tengan como clase a "text" Y a "tag-item"

$x('//span[@class="text" or @class="tag-item"]') // trae los elementos que tengan como clase a "text" O a "tag-item"

$x('//span[not(@class)]') // trae todos los span que NO tengan una clase

Hay un div en el html el cual tiene ambas clases (row y header-box), pero no me funciona de esta forma, no deberia servir?

$x('//div[@class="row" and @class="header-box"]')

Me funciona si lo hago de esta forma solo si estan en este orden inclusive

$x('//div[@class="row header-box"]')```

¿Alguien sabe por qué en este caso las posiciones arrancan en 1 y no en 0?, siendo que está escribiendo en JS.

Quería practicar un poco. Mi objetivo fue obtener el primer tag de cada quote. Les comparto mi código:

$x('/html/body/div/div[@class="row"]/div[1]/div[@class="quote"]/div[@class="tags"]/a[@class="tag"][1]/text()').map(item => item.wholeText)

$x('//div[@class="quote"][1]/span[@class="text"]/text()').map(x => x.wholeText)
# Traer la primera Quote de toda la página

//div[@class="tags"]/a[position()<=3]/text()
# Top 3 de Tags por Quotes

Lista de operadores y su descripción

Interesante

Para llamar cierta cantidad de elementos, se usa position()
$x(’//div[@class=“quote” or position()=2]’)
En este ejemplo, llamamos a los divs que tengan la class quote o que estén en la posición dos (la cual es relativa a su nodo padre.)

Siempre me he preguntado por qué una plataforma como Platzi no puede hasta la fecha darse cuenta que la barra siempre presente de ‘play’, ‘pause’, etc. disminuye la calidad de experiencia en los usuarios. Es un problema que lo he visto y vivido desde que entré a la plataforma y que muchas otras personas también lo han padecido; sin embargo, a la fecha el inconveniente persiste.

Excelente clase, definiticamente XPath es un gran aliado para el Web Scraping.

Les comparto los Operadores vistos en clase:

$x('//span[@class!="text"]/text()')
$x('//span[@class!="text"]/text()').map(x => x.wholeText)
Todos los span que tienen una clase distinta a texto.

$x('/html/body/div/div[position()>1]')
Trae los elementos de una posicion hacia arriba.

$x('//span[@class="text" or @class="tag-item"]')
Trae todos los span que tengan como clase a text o que tengan como clase tag-item.

$x('//span[@class="text" and @class="tag-item"]')
Trae todos los span que tengan como clase a text y que tengan como clase tag-item.

$x('//span[not(@class)]')
Trae todos los span que no tengan un atributo de tipo class.

Operadores en XPath

  • ! = : indica que debe ser distinto
$x('//span[@class!="text"]')
--> (11) [span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.sh-red]
# 11 nodos span que tiene clase de tipo tag-item y no de tipo texto
  • < : permite obtener las etiquetas segun sea mayor o menor a un determinado valor

$x('/html/body/div/div[position()>1]')
--> [div.row]
#obtiene las etiquetas que estan despues de la primera.
  • and : indica que trae las etiquetas que cumplen dos condiciones a la vez
$x('//span[@class="text" and @class="tag-item"]')
#obtiene los nodos con clases de tipo text y tag-item
  • or : trae los nodos que cumplan con alguna de dos condiciones
$x('//span[@class="text" or @class="tag-item"]')
--> (20) [span.text, span.text, span.text, span.text, span.text, span.text, span.text, span.text, span.text, span.text, span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.tag-item, span.tag-item]
#obtiene los nodos que tengan clases de tipo text o de tipo tag-item
  • not : trae los nodos que no cumplen una condicion
$x('//span[not(@class)]')
--> (11) [span, span, span, span, span, span, span, span, span, span, span]
#trae los nodos que no tienen atributos de tipo clase

Otra clase rompe cabezas que te hace salir de tu zona de confort y saber más del tema. Una maquina de incorporar nuevo conocimiento.

Código para traer los 3 elementos del top ten de tags:

$x('//span[@class="tag-item"][position()<4]/a/text()').map(x => x.wholeText)
$x('/html/body/div/div[@class="row"]/div[1]/div[@class="quote"]/div[@class="tags"]/a[@class="tag"][1]/text()').map(item => item.wholeText)

🤖🤖🤖
Operadores lógicos en Xpath :
Cabe notar que los operadores se están usando dentro del predicado.
!=
<>
and
or
not

Para traer a todos los autores de las citas

$x('//span/small[@class = "author"]/text()').map(x =>x.wholeText)
import requests
import lxml.html as html
import os #nos sirve para crear una carpeta con la fecha de hoy#
import datetime #nos sirve para TRAER la fecha de hoy#

HOME_URL = 'https://www.larepublica.co/'

XPATH_LINK_TO_ARTICLE = '//div[contains(@class, "V") or contains(@class, "col")]/a[contains(@class, "kicker")]/@href'
XPATH_TITLE = '//div[@class="mb-auto"]/text-fill/span/text()'
XPATH_SUMMARY = '//div[@class="lead"]/p/text()'
XPATH_BODY = '//div[@class="html-content"]/p[not(@class)]/text()'


def parse_notice(link, today):
    try:
        response = requests.get(link)
        if response.status_code == 200:
            notice = response.content.decode('utf-8')
            parsed = html.fromstring(notice)

            try:
                title = parsed.xpath(XPATH_TITLE)[0]
                title = title.replace('\"','')
                summary = parsed.xpath(XPATH_SUMMARY)[0]
                body = parsed.xpath(XPATH_BODY)            
            except IndexError:
                return

            with open(f'{today}/{title}.text', 'w', encoding='utf-8') as f:
                f.write(title)
                f.write('\n\n')
                f.write(summary)
                f.write('\n\n')
                for p in body:
                    f.write(p)
                    f.write('\n')
        else:
            raise ValueError(f'Error: {response.status_code}')
    except ValueError as ve:
        print(ve)


def parse_home():
    try:
        response = requests.get(HOME_URL)
        if response.status_code == 200:
            home = response.content.decode('utf-8') #response.content devuelve el documento html de la respuesta y .decode es un metodo que transforma todo los caracteres especiales en algo que python puede leer#
            parsed = html.fromstring(home)     #toma el contenido de html que ya se tiene en texto y se transforma en un documento especial en el cual se puede hacer XPATH#
            links_to_notices = parsed.xpath(XPATH_LINK_TO_ARTICLE)   #obtener la lista de links#
            #print(links_to_notices)#

            today = datetime.date.today().strftime('%d-%m-%Y') #nos TRAE la fecha de hoy#
            if not os.path.isdir(today):
                os.mkdir(today)     #esta linea de codigo crea una carpeta con la fecha de hoy, solo la crea si esa carpeta no existe#
            for link in links_to_notices:
                parse_notice(link, today) #Se va a entrar a cada link y se va a extraer toda la informacion del XPATH y eso lo va a guardar en con la fecha de hoy#
        else:
            raise ValueError(f'Error: {response.status_code}')
    except ValueError as ve:
        print(ve)               #este bloque de codigo sirve para detectar errores y devuelve el status code#


def run():
    parse_home()


if __name__ == '__main__':
    run()

Muy interesante

Operadores
= , !=, <, >, and, or, not.

Hola a todos, os dejo mis apuntes de esta clase, sin embargo, he creado un respositorio en github donde estan todos los apuntes de este curso: https://github.com/fer2002743/web-scraping

<h1>Operadores en Xpath</h1>

Para ser capaces de filtrar de una forma mas avanzada nos vamos a valer de operadores. Supongamos que quiero traer todos los elementos de spam que tienen una clase distinta a texto, para ello hacemos esto:

$x('//span[@class != "text"]')

Si recordamos clases anteriores, cuando usamos el predicado [1] o [last()] traemos el ultimo o el primer elemento, sin embargo, que pasa cuando tengo mucho elementos??. En este caso puedo usar un operador para filtrar que elementos quiero, por ejemplo:

$x('/HTML/body/div/div[position()>1]')
#esta expresion me trae los elementos que estan de uno para arriba

Por otro lado, tambien podemos usar los operadores logicos “and” y “or”, por ejemplo

#operador logico and
$x('//span[@class="text and @class="tag-item"]')

#operador logico or
$x('//span[@class="text" or @class="tag-item"]')

#operador not

$x('//span[not (@class="text")]')

Facundo sos groso!!!