XPATH + XML = Schnelle Verarbeitung





Bei der Ausführung von Abfragen arbeitet XPath mit Entitäten wie Knoten. Es gibt verschiedene Arten von Knoten: Element (Elementknoten), Attribut (Attributknoten), Text (Textknoten), Namespace (Namespace-Knoten), Verarbeitungsanweisung (ausführbarer Anweisungsknoten), Kommentar (Kommentarknoten) , Dokument (Dokumentknoten).



Betrachten wir, wie in XPATH die Reihenfolge der Knoten, die Auswahlrichtungen festgelegt und Knoten mit bestimmten Werten ausgewählt werden.



Zur Auswahl von Knoten werden hauptsächlich 6 grundlegende Arten von Strukturen verwendet:







Bei der Auswahl von Knoten können auch Platzhaltermasken verwendet werden, wenn wir nicht wissen, welche Art von Knoten verwendet werden soll.







In der XPATH-Sprache werden spezielle Konstrukte, die als Achse bezeichnet werden, verwendet, um relativ zum aktuellen Knoten auszuwählen.







Die Auswahlregel kann entweder absolut (// Eingabe [@ placeholder = "Login" - Auswahl ab dem Wurzelknoten]) oder relativ (* @ class = "okved-table__code" - Auswahl relativ zum aktuellen Knoten) sein. Erstellen Sie



jeweils eine Auswahlregel Der Abtastschritt wird relativ zum aktuellen Knoten ausgeführt und berücksichtigt:



  • Der Name der Achse, um die herum abgetastet werden soll
  • Bedingung für die Auswahl eines Knotens nach Name oder Position
  • Null oder mehr Prädikate


Im Allgemeinen lautet die Syntax eines Abtastschritts:



axisname::nodetest[predicate]


Um bestimmte Knoten für bestimmte Bedingungen, Parameter oder Positionen auszuwählen, wird ein Werkzeug wie Prädikate verwendet. Die Prädikatbedingung ist in eckigen Klammern angegeben. Beispiele:







Zusätzlich zu den oben genannten XPATH-Sprachkonstrukten enthält es Unterstützung für eine Reihe von Operatoren (+, -, *, div, mod, =,! =, And, oder usw.) sowie über 200 integrierte Funktionen.



Lassen Sie uns ein solches praktisches Beispiel geben. Wir müssen Informationen über die Zeiträume einer bestimmten Personenliste hochladen. Zu diesem Zweck verwenden wir den Dienst notariat.ru.



Wir importieren Abhängigkeiten.



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


Laden von Daten über Personen:



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


Wir extrahieren Informationen von Seiten mit Informationen über Personen.



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


Wir führen Suchvorgänge mit dem Multiprozessor-Modul durch, um die Datenerfassung zu beschleunigen.



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)




Und wir speichern die Ergebnisse:



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)


Die folgende Abbildung zeigt die Suchseite für persönliche Dateien, auf der der vollständige Name und das Geburtsdatum angegeben sind, nach denen anschließend gesucht wird. Nach Eingabe des vollständigen Namens und des Geburtsdatums klickt der Algorithmus auf die Schaltfläche, um nach einem Fall zu suchen, und analysiert anschließend die Ergebnisse.







In der nächsten Abbildung sehen wir eine Liste, deren Elemente vom Algorithmus analysiert werden.







Das obige Beispiel hat gezeigt, wie Sie mit XPATH Informationen von Webseiten sammeln können. Wie bereits erwähnt, kann XPATH für die Verarbeitung von XML-Dokumenten verwendet werden. Dies ist der Industriestandard für den Zugriff auf XML- und XML-Elemente sowie für XSLT-Transformationen.



Oft wirkt sich die Lesbarkeit des Codes auf die Qualität aus. Daher sollten Sie beim Parsen auf reguläre Ausdrücke verzichten, XPATH studieren und mit der Anwendung in Ihrem Workflow beginnen. Dadurch wird Ihr Code leichter verständlich. Sie machen weniger Fehler und reduzieren auch die Debugging-Zeit.



All Articles