2017-02-12 4 views
-1

Schätzen Sie Hilfe mit Python Xpath. Ich habe den folgenden XML-Code. Momentan verwende ich Python und lese Zeile für Zeile und versuche dann, es zu extrahieren. Aber ich verstehe, dass die Tabellen 1000 Zeilen lang sind und Zeilen für Zeile verwendet werden, um sie zu lesen und Logik zu setzen, ist weit jenseits von mir.Verwenden von Python Xpath zum Extrahieren von Daten in eine CSV-Datei

Ich möchte diese Daten aus dem XML-Code extrahieren und in eine CSV-Datei eingeben.

Wie verwende ich Xpath, um es zu tun?

XML-Beispielcode:

<thead> 
    <tr> 
     <th class="section" data-bind="text: name">Ratios</th> 
     <!-- ko foreach : $parent.dataPoints --> 
      <th> 
       <span data-bind="text: absPeriod.indexOf('LTM') != -1 ? 'LTM Ending' : absPeriod">FY2013</span> 
       <br> 
       <span data-bind="text: periodDate, format: 'date'">30/Jun/2013</span> 
      </th> 

      <th> 
       <span data-bind="text: absPeriod.indexOf('LTM') != -1 ? 'LTM Ending' : absPeriod">FY2014</span> 
       <br> 
       <span data-bind="text: periodDate, format: 'date'">30/Jun/2014</span> 
      </th> 

      <th> 
       <span data-bind="text: absPeriod.indexOf('LTM') != -1 ? 'LTM Ending' : absPeriod">FY2015</span> 
       <br> 
       <span data-bind="text: periodDate, format: 'date'">30/Jun/2015</span> 
      </th> 

      <th> 
       <span data-bind="text: absPeriod.indexOf('LTM') != -1 ? 'LTM Ending' : absPeriod">FY2016</span> 
       <br> 
       <span data-bind="text: periodDate, format: 'date'">30/Jun/2016</span> 
      </th> 

      <th> 
       <span data-bind="text: absPeriod.indexOf('LTM') != -1 ? 'LTM Ending' : absPeriod">LTM Ending</span> 
       <br> 
       <span data-bind="text: periodDate, format: 'date'">31/Dec/2016</span> 
      </th> 
     <!-- /ko --> 
     <th class="uncheck" data-bind="visible: $root.series().length > 0" style="display: none;">&nbsp;</th> 
    </tr> 
</thead> 
<tbody> 
    <!-- ko foreach : dataPoints --> 
     <tr data-bind="css: { 'odd': ($index() % 2 == 0) }" class="odd"> 
      <td class="checkbox left"> 
       <div class="trigger" data-bind="attr: { 'data-name': property, 'data-group': group }, click: function(data, event) { $root.handleClick($root, data, event); }" data-name="returnAssets" data-group="ratio"> 
        <span class="name" data-bind="text: name">Return on Assets</span> 
        <span data-bind="visible: $data.hasOwnProperty('glossaryTerm')"> 
         <img src="img/info.png" alt="" data-bind="tooltip: $data.hasOwnProperty('glossaryTerm') ? glossaryTerm : null" tooltip-copy="Return on Assets is a measure of company profitability relative to total assets. It is calculated by dividing tax-effective EBIT (Earnings before Interest and Tax) by Average Total Assets over a 12-months period." class="tooltip-item"> 
        </span> 
       </div> 
       <input type="checkbox"> 
      </td> 
      <!-- ko foreach : $root.dataPoints --> 
       <td data-bind="text: $data.hasOwnProperty($parent.property) &amp;&amp; $data[$parent.property] != null? $data[$parent.property] : '-', formatNonZeroValue: 'number', attr: { 'data-value': $data.hasOwnProperty($parent.property) ? $data[$parent.property] : null, 'data-name': $parent.property }" data-value="14.6931" data-name="returnAssets">14.693</td> 

       <td data-bind="text: $data.hasOwnProperty($parent.property) &amp;&amp; $data[$parent.property] != null? $data[$parent.property] : '-', formatNonZeroValue: 'number', attr: { 'data-value': $data.hasOwnProperty($parent.property) ? $data[$parent.property] : null, 'data-name': $parent.property }" data-value="13.5242" data-name="returnAssets">13.524</td> 

       <td data-bind="text: $data.hasOwnProperty($parent.property) &amp;&amp; $data[$parent.property] != null? $data[$parent.property] : '-', formatNonZeroValue: 'number', attr: { 'data-value': $data.hasOwnProperty($parent.property) ? $data[$parent.property] : null, 'data-name': $parent.property }" data-value="14.5923" data-name="returnAssets">14.592</td> 

       <td data-bind="text: $data.hasOwnProperty($parent.property) &amp;&amp; $data[$parent.property] != null? $data[$parent.property] : '-', formatNonZeroValue: 'number', attr: { 'data-value': $data.hasOwnProperty($parent.property) ? $data[$parent.property] : null, 'data-name': $parent.property }" data-value="13.0935" data-name="returnAssets">13.094</td> 

       <td data-bind="text: $data.hasOwnProperty($parent.property) &amp;&amp; $data[$parent.property] != null? $data[$parent.property] : '-', formatNonZeroValue: 'number', attr: { 'data-value': $data.hasOwnProperty($parent.property) ? $data[$parent.property] : null, 'data-name': $parent.property }" data-value="15.4657" data-name="returnAssets">15.466</td> 
      <!-- /ko --> 
      <td class="uncheck" data-bind="visible: $root.series().length > 0, click: function(data, event) { $root.handleClick($root, data, event); }" style="display: none;"> 
       <span data-bind="visible: $root.canUncheck($root, property)" style="display: none;">[UNCHART]</span> 
      </td> 
     </tr> 

     <tr data-bind="css: { 'odd': ($index() % 2 == 0) }"> 
      <td class="checkbox left"> 
       <div class="trigger" data-bind="attr: { 'data-name': property, 'data-group': group }, click: function(data, event) { $root.handleClick($root, data, event); }" data-name="returnCapital" data-group="ratio"> 
        <span class="name" data-bind="text: name">Return on Capital</span> 
        <span data-bind="visible: $data.hasOwnProperty('glossaryTerm')"> 
         <img src="img/info.png" alt="" data-bind="tooltip: $data.hasOwnProperty('glossaryTerm') ? glossaryTerm : null" tooltip-copy="Return on Capital is a measure of company profitability relative to total capitals. It is calculated by dividing tax-effective EBIT (Earnings before Interest and Tax) by Average Total Capital over a 12-months period." class="tooltip-item"> 
        </span> 
       </div> 
       <input type="checkbox"> 
      </td> 
      <!-- ko foreach : $root.dataPoints --> 
       <td data-bind="text: $data.hasOwnProperty($parent.property) &amp;&amp; $data[$parent.property] != null? $data[$parent.property] : '-', formatNonZeroValue: 'number', attr: { 'data-value': $data.hasOwnProperty($parent.property) ? $data[$parent.property] : null, 'data-name': $parent.property }" data-value="30.0726" data-name="returnCapital">30.073</td> 

       <td data-bind="text: $data.hasOwnProperty($parent.property) &amp;&amp; $data[$parent.property] != null? $data[$parent.property] : '-', formatNonZeroValue: 'number', attr: { 'data-value': $data.hasOwnProperty($parent.property) ? $data[$parent.property] : null, 'data-name': $parent.property }" data-value="25.6597" data-name="returnCapital">25.66</td> 

       <td data-bind="text: $data.hasOwnProperty($parent.property) &amp;&amp; $data[$parent.property] != null? $data[$parent.property] : '-', formatNonZeroValue: 'number', attr: { 'data-value': $data.hasOwnProperty($parent.property) ? $data[$parent.property] : null, 'data-name': $parent.property }" data-value="26.4617" data-name="returnCapital">26.462</td> 

       <td data-bind="text: $data.hasOwnProperty($parent.property) &amp;&amp; $data[$parent.property] != null? $data[$parent.property] : '-', formatNonZeroValue: 'number', attr: { 'data-value': $data.hasOwnProperty($parent.property) ? $data[$parent.property] : null, 'data-name': $parent.property }" data-value="26.0215" data-name="returnCapital">26.021</td> 

       <td data-bind="text: $data.hasOwnProperty($parent.property) &amp;&amp; $data[$parent.property] != null? $data[$parent.property] : '-', formatNonZeroValue: 'number', attr: { 'data-value': $data.hasOwnProperty($parent.property) ? $data[$parent.property] : null, 'data-name': $parent.property }" data-value="27.67" data-name="returnCapital">27.67</td> 
      <!-- /ko --> 
      <td class="uncheck" data-bind="visible: $root.series().length > 0, click: function(data, event) { $root.handleClick($root, data, event); }" style="display: none;"> 
       <span data-bind="visible: $root.canUncheck($root, property)" style="display: none;">[UNCHART]</span> 
      </td> 
     </tr> 
</tbody> 

Ausgangsprobe als Tabellenbericht

enter image description here

+0

Leider ist dies nicht XML, sondern HTML, wobei letzteres in Markup-Regeln weniger streng ist als früher und das Parsen als XML fehlschlägt. Zum Beispiel sollten die '
'-Tags selbstschließend '
' sein, um wohlgeformtes XML zu sein, und dies bricht sogar XPath-Aufrufe. – Parfait

+0

Welche anderen Methoden sollte ich verwenden, um die erforderliche Ausgabetabelle zu erhalten? –

Antwort

0

Ja, es möglich zu übertreffen ist html mit lxml.etree zu analysieren. Der genaue Code hängt jedoch vom Namespace ab, der in Ihrer Datei verwendet wird. Angenommen, Sie

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
</head> 
<body> 

am Anfang der Datei haben, dieser Code funktioniert:

from lxml import etree 

parser = etree.XMLParser(attribute_defaults=False, load_dtd=True, resolve_entities=True,remove_comments=False, ns_clean=True, recover=True) 
file = "C:\\test1.html" # your filename here 
data = etree.parse(file, parser=parser) 
headers = etree.XPath('''//h:span [@data-bind="text: absPeriod.indexOf('LTM') != -1 ? 'LTM Ending' : absPeriod"] ''', namespaces={'h':"http://www.w3.org/1999/xhtml"}) 
dates = etree.XPath('''//h:span [@data-bind="text: periodDate, format: 'date'"] ''', namespaces={'h':"http://www.w3.org/1999/xhtml"}) 
assets = etree.XPath('''//h:td [@data-name="returnAssets"]''', namespaces={'h':"http://www.w3.org/1999/xhtml"}) 
capitals = etree.XPath('''//h:td [@data-name="returnCapital"]''', namespaces={'h':"http://www.w3.org/1999/xhtml"}) 
header = [x.text for x in headers(data)] 
date = [x.text for x in dates(data)] 
asset = [x.text for x in assets(data)] 
capital = [x.text for x in capitals(data)] 
print(header) 
print(date) 
print(asset) 
print(capital) 

gibt Ihnen:

['FY2013', 'FY2014', 'FY2015', 'FY2016', 'LTM Ending'] 
['30/Jun/2013', '30/Jun/2014', '30/Jun/2015', '30/Jun/2016', '31/Dec/2016'] 
['14.693', '13.524', '14.592', '13.094', '15.466'] 
['30.073', '25.66', '26.462', '26.021', '27.67'] 

mit diesem starten, können Sie nun die Daten setzen in eine CSV (sorry, dass ich nicht darüber).

1

Ich musste dieses Problem vorher lösen und schrieb einen HTML-Parser für https://pypi.python.org/pypi/messytables, um programmatischen Zugriff auf die Tabellen zu bekommen.

Sie sollten lxml.html für html, nicht lxml.etree verwenden. Die Schnittstelle ist sehr ähnlich.

Im Wesentlichen sollten Sie Schleife über jedes table Element die Zeilen (tr) zu extrahieren, die jeweils trtd und th, zu extrahieren und den Text von jedem von ihnen bekommen. Ich würde das Element, das du zu bekommen versuchst, nicht übertreiben.

Wenn Sie ein Problem mit der Umstrukturierung der Daten, die Sie herauskommen, treffen, finden Sie möglicherweise https://github.com/sensiblecodeio/xypath nützlich. [Disclaimer: Ich habe das meiste davon geschrieben]

Verwandte Themen