XPATH + XML =高速処理





クエリを実行するとき、XPathはノードなどのエンティティで動作します。ノードには、要素(要素ノード)、属性(属性ノード)、テキスト(テキストノード)、名前空間(名前空間ノード)、処理命令(実行可能命令ノード)、コメント(コメントノード)のいくつかの種類があります。 、ドキュメント(ドキュメントノード)。



XPATHでノードのシーケンス、選択方向が設定され、特定の値を持つノードがどのように選択されるかを考えてみましょう。



ノードの選択には、主に6種類の構造が使用されます。







また、ノードを選択するときに、ノードの種類がわからない場合にワイルドカードマスクを使用することができます。







XPATH言語では、軸と呼ばれる特別な構成を使用して、現在のノードを基準にして選択します。







選択ルールは、絶対(// input [@ placeholder = "Login"-ルートノードから開始する選択]]または相対(* @ class = "okved-table__code"-現在のノードに相対的な選択)のいずれかです。



それぞれの選択ルールを作成します。サンプリングステップは、現在のノードに対して実行され、以下を考慮に入れます。



  • サンプリングする軸の名前
  • 名前または位置でノードを選択するための条件
  • ゼロ個以上の述語


一般に、1つのサンプリングステップの構文は次のとおりです。



axisname::nodetest[predicate]


一部の条件、パラメーター、または位置に対して特定のノードを選択するには、述語などのツールを使用します。述語条件は角括弧で囲まれています。例:







上記のXPATH言語構造に加えて、多数の演算子(+、-、*、div、mod、=、!=、And、orなど)および200を超える組み込み関数のサポートも含まれています。



そのような実用的な例を挙げましょう。特定の人のリストの期間に関する情報をアップロードする必要があります。これを行うには、notariat.ruサービスを使用します。



依存関係をインポートします。



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


人に関するデータの読み込み:



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


人に関する情報のあるページから情報を抽出します。



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


マルチプロセッシングモジュールを使用して検索を実行し、データ収集を高速化します。



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)




そして、結果を保存します。



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)


下の図は、個人ファイルを検索するためのページを示しています。これは、将来検索が実行されるフルネーム、生年月日を示しています。氏名と生年月日を入力した後、アルゴリズムはボタンをクリックしてケースを検索し、その後結果を分析します。







次の図にリストがあり、その要素はアルゴリズムによって解析されます。







上記の例は、XPATHを使用してWebページから情報を収集する方法を示しています。ただし、すでに述べたように、XPATHはあらゆるxmlドキュメントの処理に適用でき、xmlおよびxhtml要素、xslt変換にアクセスするための業界標準です。



多くの場合、コードの読みやすさはその品質に影響を与えるため、解析するときは通常の式を放棄し、XPATHを調べて、ワークフローに適用し始める必要があります。これにより、コードが理解しやすくなります。ミスが少なくなり、デバッグ時間が短縮されます。



All Articles