2016-05-06 6 views
2

Ich bekomme Werte von Header der HTML-Tabelle unter Verwendung von Lxml, aber wenn ich versuche, den Inhalt der Tds in Tr zu analysieren, die in Tbody mit XPath ist es gibt mir leerer Wert, da die Daten dynamisch generiert werden. Unten ist mein Python-Code mit seinem Ausgabewert, den ich bekomme. Wie kann ich die Werte bekommen?Get alle TD-Inhalt in tbody von tr in Python mit lxml

<table id="datatabl" class="display compact cell-border dataTable no-footer" role="grid" aria-describedby="datatabl_info"> 
    <thead> 
     <tr role="row"> 
       <th class="dweek sorting_desc" tabindex="0" aria-controls="datatabl" rowspan="1" colspan="1" style="width: 106px;" aria-label="Week: activate to sort column ascending" aria-sort="descending">Week</th> 
    <th class="dnone sorting" tabindex="0" aria-controls="datatabl" rowspan="1" colspan="1" style="width: 100px;" aria-label="None: activate to sort column ascending">None</th> 
     </tr> 
    </thead> 


    <tbody> 
     <tr class="odd" role="row"> 
      <td class="sorting_1">2016-05-03</td> 
      <td>4.27</td> 
      <td>21.04</td> 
     </tr> 
     <tr class="even" role="row"> 
      <td class="sorting_1">2016-04-26</td> 
      <td>4.24</td> 
      <td>95.76</td> 
      <td>21.04</td> 
     </tr> 
     </tbody> 

My Python Code

from lxml import etree 
    import urllib 

    web = urllib.urlopen("http://droughtmonitor.unl.edu/MapsAndData/DataTables.aspx") 
    s = web.read() 

    html = etree.HTML(s) 

    ## Get all 'tr' 
    tr_nodes = html.xpath('//table[@id="datatabl"]/thead') 
    print tr_nodes 

    ## 'th' is inside first 'tr' 
    header = [i[0].text for i in tr_nodes[0].xpath("tr")] 
    print header 

    ## tbody 
    tr_nodes_content = html.xpath('//table[@id="datatabl"]/tbody') 
    print tr_nodes_content 

    td_content = [[td[0].text for td in tr.xpath('td')] for tr in tr_nodes_content[0]] 
    print td_content 

Ausgangsklemme:

[<Element thead at 0xb6b250ac>] 
    ['Week'] 
    [<Element tbody at 0xb6ad20cc>] 
    [] 
+0

Können Sie den HTML-Code aus dem Python-Code trennen (und auch richtig formatieren Sie bitte) – Adib

+0

Die Daten werden dynamisch generiert, auch tbody wird normalerweise vom Browser so nicht wirklich in der Quelle hinzugefügt, '.xpath ('// table [@ id = "datatabl"]/thead // text() ') 'würde die Überschrift bekommen –

+0

ja @PadraicCunningham – shanky

Antwort

2

Dadurch werden die Daten erhalten aus die Anfrage in ajax json Format:

import requests 

headers = { 
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36', 
    'Content-Type': 'application/json', 
    'Referer': 'http://droughtmonitor.unl.edu/MapsAndData/DataTables.aspx', 
    'X-Requested-With': 'XMLHttpRequest', 
} 
import json 
data = json.dumps({'area':'conus', 'type':'conus', 'statstype':'1'}) 

ajax = requests.post("http://droughtmonitor.unl.edu/Ajax.aspx/ReturnTabularDM", 
        data=data, 
        headers=headers) 
from pprint import pprint as pp 

pp(ajax.json()) 

ein Ausschnitt aus der Ausgabe:

{u'd': [{u'D0': 33.89, 
     u'D1': 14.56, 
     u'D2': 5.46, 
     u'D3': 3.44, 
     u'D4': 1.11, 
     u'Date': u'2016-05-03', 
     u'FileDate': u'20160503', 
     u'None': 66.11, 
     u'ReleaseID': 890, 
     u'__type': u'DroughtMonitorData.DmData'}, 
     {u'D0': 39.64, 
     u'D1': 15.38, 
     u'D2': 5.89, 
     u'D3': 3.44, 
     u'D4': 1.11, 
     u'Date': u'2016-04-26', 
     u'FileDate': u'20160426', 
     u'None': 60.36, 
     u'ReleaseID': 889, 
     u'__type': u'DroughtMonitorData.DmData'}, 
     {u'D0': 39.28, 
     u'D1': 15.44, 
     u'D2': 5.94, 
     u'D3': 3.44, 
     u'D4': 1.11, 
     u'Date': u'2016-04-19', 
     u'FileDate': u'20160419', 
     u'None': 60.72, 
     u'ReleaseID': 888, 
     u'__type': u'DroughtMonitorData.DmData'}, 
     {u'D0': 39.2, 
     u'D1': 17.75, 
     u'D2': 6.1, 
     u'D3': 3.76, 
     u'D4': 1.71, 
     u'Date': u'2016-04-12', 
     u'FileDate': u'20160412', 
     u'None': 60.8, 
     u'ReleaseID': 887, 
     u'__type': u'DroughtMonitorData.DmData'}, 
     {u'D0': 37.86, 
     u'D1': 16.71, 
     u'D2': 5.95, 
     u'D3': 3.76, 
     u'D4': 1.71, 
     u'Date': u'2016-04-05', 
     u'FileDate': u'20160405', 
     u'None': 62.14, 
     u'ReleaseID': 886, 
     u'__type': u'DroughtMonitorData.DmData'}, 

Sie können alle Daten, erhalten Sie von der json wollen zurückgegeben, wenn Sie print(len(cont.json()["d"])) Sie Sie 853 Zeilen erhalten werden sehen, zurückgeführt, so scheinen Sie tatsächlich yo alle Daten aus den 35 Seiten in einem Rutsch zu bekommen. Selbst wenn Sie die Seite analysiert haben, müssten Sie es noch 34 Mal machen, um den JSON von der Ajax-Anfrage zu bekommen, macht es leicht zu analysieren und alles aus einem einzigen Beitrag.

von Staat zu filtern, müssen wir die type zu state und den area-CA einzustellen:

data = json.dumps({'type':'state', 'statstype':'1','area':'CA'}) 

ajax = requests.post("http://droughtmonitor.unl.edu/Ajax.aspx/ReturnTabularDM", 
        data=data, 
        headers=headers) 
from pprint import pprint as pp 

pp(ajax.json()) 

Wieder einen kurzen Ausschnitt:

{u'd': [{u'D0': 95.73, 
     u'D1': 89.68, 
     u'D2': 74.37, 
     u'D3': 49.15, 
     u'D4': 21.04, 
     u'Date': u'2016-05-03', 
     u'FileDate': u'20160503', 
     u'None': 4.27, 
     u'ReleaseID': 890, 
     u'__type': u'DroughtMonitorData.DmData'}, 
     {u'D0': 95.76, 
     u'D1': 90.09, 
     u'D2': 74.37, 
     u'D3': 49.15, 
     u'D4': 21.04, 
     u'Date': u'2016-04-26', 
     u'FileDate': u'20160426', 
     u'None': 4.24, 
     u'ReleaseID': 889, 
     u'__type': u'DroughtMonitorData.DmData'}, 

Welche Sie Spiele werden sehen, was angezeigt wird, auf der Seite.

+0

Hallo @Padraic Cunningham, wenn Sie die Webseite sehen, kann es auch die Daten auf der Grundlage von Zuständen filtern und in meinem Fall will ich nur kalifornische Daten, damit ich die Daten basierend auf dem Stand bekommen kann? – shanky

+0

Danke gerade jetzt sah ich in meinem firebug. – shanky

+0

Keine Sorge, was am wichtigsten ist, ist 'Content-Type': 'application/json'' und übergeben Sie die Daten als json oder Sie erhalten das Formular html zurück, wenn Sie ''' Content-Type 'nicht übergeben: 'application/json'' und ein Fehler, wenn Sie es übergeben und übergeben Sie die Daten nicht als JSON –

2

Die Daten werden von dem Endpunkt http://droughtmonitor.unl.edu/Ajax.aspx/ReturnTabularDM dynamisch geladen. Eine Option wäre, zu versuchen, diese Anfrage nachzuahmen und die Daten von der JSON-Antwort zu erhalten.

Oder Sie können auf einem hohem Niveau bleiben und lösen es über selenium:

from selenium import webdriver 
from selenium.webdriver.common.by import By 
from selenium.webdriver.support.ui import WebDriverWait 
from selenium.webdriver.support import expected_conditions as EC 


driver = webdriver.Firefox() 
driver.maximize_window() 

wait = WebDriverWait(driver, 10) 

url = 'http://droughtmonitor.unl.edu/MapsAndData/DataTables.aspx' 
driver.get(url) 

# wait for the table to load 
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "table#datatabl tr[role=row]"))) 
rows = driver.find_elements_by_css_selector("table#datatabl tr[role=row]")[1:] 

for row in rows: 
    cells = row.find_elements_by_tag_name("td") 
    print(cells[2].text) 

driver.close() 

Druckt den Inhalt der D0-D4 Säule:

33.89 
39.64 
39.28 
39.20 
... 
36.74 
38.45 
43.61 
Verwandte Themen