XPATH + XML =快速处理





执行查询时,XPath在诸如节点之类的实体上运行。节点有几种:元素(元素节点),属性(属性节点),文本(文本节点),名称空间(命名空间节点),处理指令(可执行指令节点),注释(注释节点)。 ,文档(文档节点)。



让我们考虑如何在XPATH中设置节点序列,选择方向以及具有特定值的节点的选择。



要选择节点,主要使用6种基本类型的结构:







此外,在选择节点时,当我们不知道应该采用哪种类型的节点时,可以使用通配符掩码。







在XPATH语言中,称为轴的特殊构造用于相对于当前节点进行选择。







选择规则可以是绝对的(//输入[@ placeholder =“ Login”-从根节点开始的选择],也可以是相对的(* @ class =“ okved-table__code”-相对于当前节点



的选择)。采样步骤是相对于当前节点执行的,并考虑到:



  • 要围绕其采样的轴的名称
  • 通过名称或位置选择节点的条件
  • 零个或多个谓词


通常,一个采样步骤的语法为:



axisname::nodetest[predicate]


为了为某些条件,参数或位置选择特定的节点,使用谓词这样的工具。谓词条件放在方括号中。示例:







除了上述XPATH语言构造之外,它还包含对许多运算符(+,-,*,div,mod,=,!=,And或等等)的支持,以及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从网页收集信息。但是正如已经提到的,XPATH适用于处理任何xml文档,这是访问xml和xhtml元素(xslt转换)的行业标准。



代码的可读性通常会影响其质量,因此在解析时应放弃正则表达式,研究XPATH并将其开始应用到工作流中。这将使您的代码更容易理解。您将犯更少的错误,并减少调试时间。



All Articles