XPATH + XML = procesamiento rápido





Al realizar consultas, XPath opera en entidades como nodos. Los nodos pueden ser de varios tipos: elemento, atributo, texto, espacio de nombres, instrucción de procesamiento, comentario. , documento (nodo de documento).



Consideremos cómo en XPATH se establecen la secuencia de nodos, las direcciones de selección y se seleccionan los nodos con valores específicos.



Para seleccionar nodos, se utilizan principalmente 6 tipos básicos de estructuras:







Además, a la hora de seleccionar nodos, es posible utilizar máscaras comodín cuando no sabemos qué tipo de nodo debe tomar.







En el lenguaje XPATH, se utilizan construcciones especiales llamadas eje para seleccionar en relación con el nodo actual.







La regla de selección puede ser absoluta (// input [@ placeholder = "Login" - selección comenzando desde el nodo raíz], o relativa (* @ class = "okved-table__code" - selección relativa al nodo actual).



Construir una regla de selección para cada El paso de muestreo se lleva a cabo en relación con el nodo actual y tiene en cuenta:



  • El nombre del eje para muestrear alrededor
  • Condición para seleccionar un nodo por nombre o posición
  • Cero o más predicados


En general, la sintaxis de un paso de muestreo es:



axisname::nodetest[predicate]


Para seleccionar nodos específicos para algunas condiciones, parámetros o posiciones, se utiliza una herramienta como los predicados. La condición de predicado está entre corchetes. Ejemplos:







además de las construcciones del lenguaje XPATH anteriores, también contiene soporte para varios operadores (+, -, *, div, mod, =,! =, And, or, etc.) así como más de 200 funciones integradas.



Démosle un ejemplo tan práctico. Necesitamos cargar información sobre los períodos de una determinada lista de personas. Para hacer esto, usaremos el servicio notariat.ru.



Importamos dependencias.



from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
from multiprocessing import Pool
from retry import retry
import itertools, time, pprint, os, re, traceback, sys, datetime
import pandas as pd, numpy as np, multiprocessing as mp


Cargando datos sobre personas:



df_people = pd.read_excel('people.xlsx')


Extraemos información de páginas con información sobre personas.



def find_persons(driver, name, birth_date):
    base_url = 'https://notariat.ru/ru-ru/help/probate-cases/'
    #    
    driver.get(base_url)
    #       
    driver.find_element_by_xpath('//input[@name="name"]').send_keys(name)
    #       
    driver.find_element_by_xpath('//select[@data-placeholder=""]/following::div/a').click()
   #       
    driver.find_element_by_xpath('//select[@data-placeholder=""]/following::div//li[@data-option-array-index={}]'.format(birth_date.day)).click()
    #       
    driver.find_element_by_xpath('//select[@data-placeholder=""]/following::div/a').click()
   #       
    driver.find_element_by_xpath('//select[@data-placeholder=""]/following::div//li[@data-option-array-index={}]'.format(birth_date.month)).click()
    #      
    driver.find_element_by_xpath('//input[@placeholder=""]').send_keys(str(birth_date.year))
    #  
    driver.find_element_by_xpath('//*[contains(., " ")]').click()
    #   20     ,        «probate-cases__result-list»
    WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CLASS_NAME, "probate-cases__result-list")))
    time.sleep(2)
    
    #      
    max_pages = 1
    pages_counters = driver.find_elements_by_xpath('//a[@class="pagination__item-content"]')
    if pages_counters:
        max_pages = int(pages_counters[-1].text)
    
    data = []
    def parse_page_data():
        #            
        lines = driver.find_elements_by_xpath('//ol[@class="probate-cases__result-list"]/li')
        for line in lines:
            name = ' '.join(map(lambda el: el[0].upper() + el[1:].lower(), line.find_element_by_xpath('.//h4').text.split()))
            death_date = datetime.datetime.strptime(line.find_element_by_xpath('.//p').text.split(':')[-1].strip(), '%d.%m.%Y')
            data.append((name, birth_date, death_date))
    #      
    if max_pages == 1:
        parse_page_data() #         
    else: 
        for page_num in range(1, max_pages + 1):
            #       ,       
            driver.find_element_by_xpath('//li[./a[@class="pagination__item-content" and text()="{}"]]'.format(page_num)).click()
            time.sleep(0.2)
            #      
            parse_page_data()
    return data


Realizamos búsquedas utilizando el módulo de multiprocesamiento para agilizar la recolección de datos.



def parse_persons(persons_data_chunk, pool_num):
    #   Chrome   headless    (      DOM    notariat.ru  )
    chrome_options = Options()
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--window-size=1920,1080")
    driver = webdriver.Chrome(options=chrome_options)
    driver.set_page_load_timeout(20)
    data = [] 
    print(pool_num, '')
    #         
    for ind, (person_name, person_date) in enumerate(persons_data_chunk, start=1):
        print('pool:', pool_num, ', person: ', ind, '/', len(persons_data_chunk))
        try:
            data.extend(find_persons(driver, person_name, person_date))
        except Exception as e:
            print(pool_num, 'failed to load', person_name, person_date, "error:", e)
            traceback.print_exception(*sys.exc_info()) 
    print(pool_num, 'done')
    return data

def parse(people_data, parts=5):
    p = mp.Pool(parts)
    #               
    people_in_chanks = np.array_split(people_data, parts if parts < len(people_data) else 1) or []
    all_data = p.starmap(parse_persons, zip(people_in_chanks, range(parts)))
    out = []
    for el in all_data:
        out.extend(el)
    return out
parsed_data = parse(people_data)




Y guardamos los resultados:



df = pd.DataFrame({
    '': list(map(lambda el: el[0], parsed_data)),
    " ": list(map(lambda el: el[1], parsed_data)),
    ' ': list(map(lambda el: el[2], parsed_data))
})
df.to_excel('results.xlsx', index=False)


La siguiente figura muestra la página de búsqueda de archivos personales, que indica el nombre completo, fecha de nacimiento, que posteriormente se buscan. Después de ingresar el nombre completo y la fecha de nacimiento, el algoritmo hace clic en el botón para buscar un caso, luego de lo cual analiza los resultados.







En la siguiente figura, vemos una lista, cuyos elementos son analizados por el algoritmo.







El ejemplo anterior mostró cómo puede usar XPATH para recopilar información de páginas web. Pero como ya se mencionó, XPATH es aplicable para procesar cualquier documento xml, siendo el estándar de la industria para acceder a elementos xml y xhtml, transformaciones xslt.



A menudo, la legibilidad del código afecta su calidad, por lo que debe abandonar las expresiones regulares al analizar, estudiar XPATH y comenzar a usarlo en su flujo de trabajo. Esto hará que su código sea más fácil de entender. Cometerá menos errores y también reducirá el tiempo de depuración.



All Articles