XPATH + XML = traitement rapide





Lors de l'exécution de requêtes, XPath opère sur des entités telles que des nœuds. Les nœuds sont de plusieurs types: élément (nœud d'élément), attribut (nœud d'attribut), texte (nœud de texte), espace de noms (nœud d'espace de nom), instruction de traitement (nœud d'instruction exécutable), commentaire (nœud de commentaire) , document (noeud de document).



Considérons comment dans XPATH la séquence de nœuds est définie, les directions de sélection et la sélection de nœuds avec des valeurs spécifiques.



Pour sélectionner des nœuds, 6 types de structures de base sont principalement utilisés:







De plus, lors de la sélection de nœuds, il est possible d'utiliser des masques génériques lorsque l'on ne sait pas quel type de nœud doit prendre.







Dans le langage XPATH, des constructions spéciales appelées axe sont utilisées pour sélectionner par rapport au nœud courant.







La règle de sélection peut être soit absolue (// input [@ placeholder = "Login" - sélection à partir du nœud racine], soit relative (* @ class = "okved-table__code" - sélection relative au nœud actuel).



Construction d'une règle de sélection pour chaque l'étape d'échantillonnage est effectuée par rapport au nœud courant et prend en compte:



  • Le nom de l'axe autour duquel échantillonner
  • Condition de sélection d'un nœud par nom ou par position
  • Zéro prédicat ou plus


En général, la syntaxe d'une étape d'échantillonnage est:



axisname::nodetest[predicate]


Pour sélectionner des nœuds spécifiques pour certaines conditions, paramètres ou positions, un outil tel que des prédicats est utilisé. La condition de prédicat est placée entre crochets. Exemples:







en plus des constructions de langage XPATH ci-dessus, il contient également la prise en charge d'un certain nombre d'opérateurs (+, -, *, div, mod, =,! =, Et, ou, etc.) ainsi que plus de 200 fonctions intégrées.



Donnons un exemple concret. Nous devons télécharger des informations sur les périodes d'une certaine liste de personnes. Pour ce faire, nous utiliserons le service notariat.ru.



Nous importons les dépendances.



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


Chargement des données sur les personnes:



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


Nous extrayons des informations à partir de pages contenant des informations sur des personnes.



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


Nous effectuons des recherches à l'aide du module multitraitement pour accélérer la collecte de données.



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)




Et nous sauvegardons les résultats:



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 figure ci-dessous montre la page de recherche des fichiers personnels, qui indique le nom complet, la date de naissance, qui sont ensuite recherchés. Après avoir entré le nom complet et la date de naissance, l'algorithme clique sur le bouton pour rechercher un cas, après quoi il analyse les résultats.







Dans la figure suivante, nous voyons une liste dont les éléments sont analysés par l'algorithme.







L'exemple ci-dessus a montré comment vous pouvez utiliser XPATH pour collecter des informations à partir de pages Web. Mais comme déjà mentionné, XPATH est applicable pour le traitement de tous les documents xml, étant la norme de l'industrie pour accéder aux éléments xml et xhtml, transformations xslt.



Souvent, la lisibilité du code affecte sa qualité, vous devez donc abandonner les expressions régulières lors de l'analyse, étudier XPATH et commencer à l'appliquer dans votre flux de travail. Cela rendra votre code plus facile à comprendre. Vous ferez moins d'erreurs et réduirez également le temps de débogage.



All Articles