2

Python を使用iterparseして、nessus スキャン (.nessus ファイル) の XML 結果を解析します。予期しないレコードの解析は失敗しますが、同様のレコードは正しく解析されています。

XML ファイルの一般的な構造は、次のような多数のレコードです。

<ReportHost>
  <ReportItem>
    <foo>9.3</foo>
    <bar>hello</bar>
  </ReportItem>
  <ReportItem>
     <foo>10.0</foo>
     <bar>world</bar>
</ReportHost>
<ReportHost>
   ...
</ReportHost>

言い換えれば、多数のホスト ( ReportHost) には報告する項目が多く ( ReportItem)、後者にはいくつかの特徴 ( foobar) があります。アイテムごとに 1 行を、その特性とともに生成することを検討します。

ファイルの途中の単純な行で解析が失敗します (fooその場合はcvss_base_score)

<cvss_base_score>9.3</cvss_base_score>

約 200 の同様の行が問題なく解析されました。

関連するコードは以下のとおりです。これはコンテキスト マーカーを設定します (inReportHostそしてinReportEvent、XML ファイルの構造のどこにいるかを教えてくれ、コンテキストに応じて値を割り当てるか出力します)。

import xml.etree.cElementTree as ET
inReportHost = False
inReportItem = False

for event, elem in ET.iterparse("test2.nessus", events=("start", "end")):
    if event == 'start' and elem.tag == "ReportHost":
        inReportHost = True
    if event == 'end' and elem.tag == "ReportHost":
        inReportHost = False
        elem.clear()
    if inReportHost:
        if event == 'start' and elem.tag == 'ReportItem':
            inReportItem = True
            cvss = ''
        if event == 'start' and inReportItem:
            if event == 'start' and elem.tag == 'cvss_base_score':
                cvss = elem.text
        if event == 'end' and elem.tag == 'ReportItem':
            print cvss
            inReportItem = False

cvsscvss = elem.text同一のエントリがファイル内で以前に適切に解析されていても、(割り当て後に) None 値を持つことがあります。

割り当ての下に次の行に沿って何かを追加すると

if cvss is None: cvss = "0"

その後、さらに多くの解析でcvss適切な値が割り当てられます (その他の値は None です)。

間違った解析を<ReportHost>...</reportHost>引き起こし、それをプログラムで実行すると、正常に動作します (つまり、期待どおりcvssに割り当てられ9.3ます)。

似たようなレコードが大量にあると、一部は正しく処理され、一部は正しく処理されないため (一部のレコードは同一であり、それでも異なる方法で処理されます)、コードのどこでミスをしたかわかりません。また、失敗したレコードについて特に何も見つけることができません。前後の同一のレコードは問題ありません。

4

1 に答える 1

4

iterparse() ドキュメントから:

注: iterparse() は、「開始」イベントを発行するときに開始タグの「>」文字を見たことを保証するだけであるため、属性は定義されていますが、その時点ではテキスト属性とテール属性の内容は未定義です。要素の子にも同じことが当てはまります。それらは存在する場合と存在しない場合があります。完全に入力された要素が必要な場合は、代わりに「終了」イベントを探してください。

変数をドロップinReport*し、完全に解析されたときに「終了」イベントでのみ ReportHost を処理します。cvss_base_scoreElementTree API を使用して、現在の ReportHost 要素などから必要な情報を取得します。

メモリを保持するには、次のようにします。

import xml.etree.cElementTree as etree

def getelements(filename_or_file, tag):
    context = iter(etree.iterparse(filename_or_file, events=('start', 'end')))
    _, root = next(context) # get root element
    for event, elem in context:
        if event == 'end' and elem.tag == tag:
            yield elem
            root.clear() # preserve memory

for host in getelements("test2.nessus", "ReportHost"):
    for cvss_el in host.iter("cvss_base_score"):
        print(cvss_el.text)
于 2013-02-03T10:23:58.007 に答える