我在局域網的外部計算機上有一個日誌文件。日誌是一個XML文件。文件不能從http訪問,並且每秒更新一次。 當前我將日誌文件複製到我的計算機並運行解析器,但我想直接從外部主機解析文件。將附加數據增量分析到Python中的外部XML文件
我該怎麼用Python做到這一點?是否有可能解析整個文件一次,然後解析僅在未來版本中添加到最後的新內容?
我在局域網的外部計算機上有一個日誌文件。日誌是一個XML文件。文件不能從http訪問,並且每秒更新一次。 當前我將日誌文件複製到我的計算機並運行解析器,但我想直接從外部主機解析文件。將附加數據增量分析到Python中的外部XML文件
我該怎麼用Python做到這一點?是否有可能解析整個文件一次,然後解析僅在未來版本中添加到最後的新內容?
我假設你沒有訪問的另一個進程正在維護xml作爲一個對象每隔一段時間更新一次,然後轉儲結果。
如果您無法訪問轉儲XML的程序源,則需要在兩個XML版本之間進行區分以獲得通過網絡發送的增量更新。
而且我認爲你必須每次解析新的XML纔能有這種差異。
所以,也許你可以有一個Python進程來觀察文件,解析新版本,比較它(例如使用來自這個article的解決方案),然後你可以使用像xmlrpc這樣的工具在網絡上發送這個差異。如果你想節省帶寬,它可能會有所幫助。雖然我認爲我會通過網絡直接發送原始差異,但在本地機器中修補和解析文件。但是,如果只有一些XML值發生變化(無節點刪除或插入),則可能會有更快的解決方案。或者,如果你的xml文件的唯一操作是追加新的樹,那麼你應該只能解析這些新的樹,然後發送它們(先比較差異,然後解析服務器,發送給客戶端,合併到客戶端)。
外部電腦不在我的範圍之內。我只能通過ssh登錄並下載文件,我無法在其上運行任何應用程序。 XML通過添加行來更新。我甚至不知道文件何時更改,我必須每隔0.6秒檢查一次。網絡帶寬不是問題 - 它在我的LAN網絡中。 – Djent 2015-03-05 08:50:08
如何讓一個進程計算本地和遠程文件的差異,並將該差異作爲臨時文件每10秒鐘丟棄一次。然後你的python進程可以[看](https://pypi.python.org/pypi/watchdog)這個臨時文件,當它到達時解析它,並將節點添加到當前的XML中。 – Lilley 2015-03-05 18:05:04
@Lilley,利用文本變化位置的知識來通知一個不重要的解析器是可行的,但它也非常非常平凡 - 需要爲該作業編寫一個解析器,而我所知的唯一的解析器是用Java或LISP編寫的,而不是Python。 – 2015-03-09 17:05:12
您可以使用paramiko
和xml.sax
的默認解析器xml.sax.expatreader
,它實現了xml.sax.xmlreader.IncrementalParser
。
我在本地虛擬機上運行以下腳本來生成XML。
#!/bin/bash
echo "<root>" > data.xml
I=0
while sleep 2; do
echo "<entry><a>value $I</a><b foo='bar' /></entry>" >> data.xml;
I=$((I + 1));
done
這裏是增量消費者。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import xml.sax
from contextlib import closing
import paramiko.client
class StreamHandler(xml.sax.handler.ContentHandler):
lastEntry = None
lastName = None
def startElement(self, name, attrs):
self.lastName = name
if name == 'entry':
self.lastEntry = {}
elif name != 'root':
self.lastEntry[name] = {'attrs': attrs, 'content': ''}
def endElement(self, name):
if name == 'entry':
print({
'a' : self.lastEntry['a']['content'],
'b' : self.lastEntry['b']['attrs'].getValue('foo')
})
self.lastEntry = None
def characters(self, content):
if self.lastEntry:
self.lastEntry[self.lastName]['content'] += content
if __name__ == '__main__':
# use default ``xml.sax.expatreader``
parser = xml.sax.make_parser()
parser.setContentHandler(StreamHandler())
client = paramiko.client.SSHClient()
# or use ``client.load_system_host_keys()`` if appropriate
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('192.168.122.40', username = 'root', password = 'pass')
with closing(client) as ssh:
with closing(ssh.open_sftp()) as sftp:
with closing(sftp.open('/root/data.xml')) as f:
while True:
buffer = f.read(4096)
if buffer:
parser.feed(buffer)
else:
time.sleep(2)
值得注意的是,這隻能解決附加問題,而不是就地編輯。 OP的問題涉及日誌記錄 - 這適用於追加內容 - 但也會詢問「差異」,這是一種通常在現場編輯環境中使用的短語,因此可能需要進行一些澄清,然後才能確定這個答案是否是點。 – 2015-03-09 17:03:02
@CharlesDuffy看看第一個回答的第一個答案。 OP說*通過添加行來更新XML。 – saaj 2015-03-09 17:05:42
好的交易。編輯這個問題來說明清楚。 – 2015-03-09 17:07:55
「更改」過於模糊。如果唯一可能的更改是** append **操作,而不是文件中已經寫入的部分內容更改,這使得以有效的方式實現這一點變得可行 - 但只是說它會「改變」,而且您希望「差異」過於籠統,因爲它允許非附加操作,並且可以處理就地編輯的增量解析器是一項非常複雜的任務。 (在這方面研究的大多數人都在構建IDE;指出他們的工作是可行的,但我期望將其付諸實踐)。 – 2015-03-09 16:59:42
您是否有權訪問主機以運行您自己的程序?您使用什麼協議將日誌文件複製到您的計算機上?主機和計算機運行什麼操作系統? – chthonicdaemon 2015-03-09 17:03:25