【问题标题】:How to find XML element fast using Python?如何使用 Python 快速查找 XML 元素?
【发布时间】:2021-12-09 18:16:34
【问题描述】:

我对 XML 以及使代码有效的原因还很陌生,而且我使用的代码需要很长时间才能运行。

所以我想尽快从给定的经纬度值中提取海拔高度(我有很多经度、经度点)。我就是这样尝试的:

import xml.etree.ElementTree as ET
from urllib.request import urlopen
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

def elevation(lat, long):
    query = ('http://openwps.statkart.no/skwms1/wps.elevation2?request=Execute&service=WPS&version=1.0.0'
                 f'&identifier=elevation&datainputs=lat={lat};lon={long};epsg=4326')
    parsing = "{http://www.opengis.net/wps/1.0.0}"
    with urlopen(query) as f:
        tree = ET.parse(f)
        root = tree.getroot()
        return float(root.findall(f".//{parsing}Data/*")[0].text)

在我从 csv 文件中提取的数据集上使用此函数,同一文件中的多个数据集由“new_sheep”-line 分隔:

df = pd.read_csv("/Users/ninsalv/Documents/Sheepdata/Data.csv", delimiter=';',
                 dtype={"Initial start": "str", "Start": "str", "Stop": "str"})
print(df.head())

dataset = 1
Lat = []
Long = []
temp = 0
for i in range(len(df)):
    if "new_sheep" in df.iloc[i][0]:
        temp += 1
        continue
    if temp == dataset:
        Lat.append(df.iloc[i][3])
        Long.append(df.iloc[i][4])
    if temp > dataset:
        break

step = np.linspace(0,len(Lat),len(Lat))
altitude = []
for i in range(len(Lat)):
    altitude.append(elevation(Lat[i], Long[i]))
    if (i % 100) == 0:
        print("round number ", i)
plt.plot(step, altitude)

这行得通,但是每 100 个海拔高度需要将近一分钟的时间,而且我有大约 7000-15000 个点要检查我的数据集。有人知道 XML、pandas 或其他可以让我的代码更快的东西吗?

【问题讨论】:

  • 我猜问题不在于 XML 解析,而在于您对远程 Web 服务进行了数千次 HTTP 调用。您正在使用的 Web 服务端点似乎只返回一个点的高程:是否有可以将多个点传递到的端点?

标签: python pandas xml parsing


【解决方案1】:

您需要做的是并行获取您正在寻找的数据(HTTP 请求)。为此,您可以使用多线程。

请参见下面的示例。

import requests
from requests.sessions import Session
import time
from threading import Thread,local
from queue import Queue

url_list = [] # TODO long list of urls to be populated by your code
q = Queue(maxsize=0)            #Use a queue to store all URLs
for url in url_list:
    q.put(url)
thread_local = local()          #The thread_local will hold a Session object

def get_session() -> Session:
    if not hasattr(thread_local,'session'):
        thread_local.session = requests.Session() # Create a new Session if not exists
    return thread_local.session

def download_link() -> None:
    '''download link worker, get URL from queue until no url left in the queue'''
    session = get_session()
    while not q.empty():
        url = q.get()
        with session.get(url) as response:
            print(f'Read {len(response.content)} from {url}')
        q.task_done()          # tell the queue, this url downloading work is done

def download_all(urls) -> None:
    '''Start 10 threads, each thread as a wrapper of downloader'''
    thread_num = 10
    for i in range(thread_num):
        t_worker = Thread(target=download_link)
        t_worker.start()
    q.join()                   # main thread wait until all url finished downloading

print("start work")
start = time.time()
download_all(url_list)
end = time.time()
print(f'download {len(url_list)} links in {end - start} seconds')

【讨论】:

  • 最好不要从线程打印任何东西,而是返回结果并在主线程中处理所有输出。而且我在download_link() 中找不到任何无限循环的出口。好像您告诉队列下载完成但线程继续在后台工作直到脚本执行结束。它可能会产生问题,最好完全省略这个循环或添加一些条件。
  • 我发布的代码不是“剪切和粘贴”代码。它更像是一个我认为 OP 应该采用的概念。
猜你喜欢
  • 1970-01-01
  • 2016-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-04
  • 1970-01-01
  • 2012-03-22
相关资源
最近更新 更多