2013-08-26 22 views
27

Ich arbeite an Python und Selen. Ich möchte die Datei vom Klicken Ereignis mit Selen herunterladen. Ich habe folgenden Code geschrieben.Datei mit Selen herunterladen

Ich möchte beide Dateien von Links mit dem Namen "Export Data" von angegebenen URL herunterladen Wie kann ich es erreichen, da es nur mit Klickereignis funktioniert?

Dank

+1

Ich empfehle, 'urllib' zu verwenden und' urllib.urlretrieve (url) 'zu verwenden, um den Download zu erhalten, wobei' url' die URL ist, die der Link sendet Sie zu – Serial

+0

nein, weil es nur mit Click-Ereignis funktioniert. – sam

+0

aber wenn Sie den HTML der Seite analysieren, können Sie die Verbindung erhalten, die das Klickereignis an den Browser sendet und das – Serial

Antwort

41

den Link finden find_element(s)_by_*, rufen Sie dann click Methode.

from selenium import webdriver 

# To prevent download dialog 
profile = webdriver.FirefoxProfile() 
profile.set_preference('browser.download.folderList', 2) # custom location 
profile.set_preference('browser.download.manager.showWhenStarting', False) 
profile.set_preference('browser.download.dir', '/tmp') 
profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'text/csv') 

browser = webdriver.Firefox(profile) 
browser.get("http://www.drugcite.com/?q=ACTIMMUNE") 

browser.find_element_by_id('exportpt').click() 
browser.find_element_by_id('exporthlgt').click() 

Profil-Manipulationscode hinzugefügt, um Downloaddialog zu verhindern.

+0

was sollte ich tun, wenn ich den Browser verstecken oder den Browser im verdeckten/minimierten Modus während der Verarbeitung halten wollte? – sam

+0

@sam, Suche nach 'headless' +' selen' + 'firefox'. – falsetru

+0

@sam, Oder 'phanromjs',' Ghostdriver'. – falsetru

4

Ich gebe zu, diese Lösung ist ein bisschen "hacky" als das Firefox-Profil saveToDisk Alternative, aber es funktioniert sowohl Chrome und Firefox, und verlässt sich nicht auf eine browserspezifische Funktion, die jederzeit ändern könnte . Und wenn nicht anders, vielleicht wird dies jemandem eine andere Perspektive geben, wie zukünftige Herausforderungen zu lösen sind.

Voraussetzungen: Stellen Sie sicher, Sie haben Selen und pyvirtualdisplay installiert ...

  • Python 2: sudo pip install selenium pyvirtualdisplay
  • Python 3: sudo pip3 install selenium pyvirtualdisplay

The Magic

import pyvirtualdisplay 
import selenium 
import selenium.webdriver 
import time 
import base64 
import json 

root_url = 'https://www.google.com' 
download_url = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png' 

print('Opening virtual display') 
display = pyvirtualdisplay.Display(visible=0, size=(1280, 1024,)) 
display.start() 
print('\tDone') 

print('Opening web browser') 
driver = selenium.webdriver.Firefox() 
#driver = selenium.webdriver.Chrome() # Alternately, give Chrome a try 
print('\tDone') 

print('Retrieving initial web page') 
driver.get(root_url) 
print('\tDone') 

print('Injecting retrieval code into web page') 
driver.execute_script(""" 
    window.file_contents = null; 
    var xhr = new XMLHttpRequest(); 
    xhr.responseType = 'blob'; 
    xhr.onload = function() { 
     var reader = new FileReader(); 
     reader.onloadend = function() { 
      window.file_contents = reader.result; 
     }; 
     reader.readAsDataURL(xhr.response); 
    }; 
    xhr.open('GET', %(download_url)s); 
    xhr.send(); 
""".replace('\r\n', ' ').replace('\r', ' ').replace('\n', ' ') % { 
    'download_url': json.dumps(download_url), 
}) 

print('Looping until file is retrieved') 
downloaded_file = None 
while downloaded_file is None: 
    # Returns the file retrieved base64 encoded (perfect for downloading binary) 
    downloaded_file = driver.execute_script('return (window.file_contents !== null ? window.file_contents.split(\',\')[1] : null);') 
    print(downloaded_file) 
    if not downloaded_file: 
     print('\tNot downloaded, waiting...') 
     time.sleep(0.5) 
print('\tDone') 

print('Writing file to disk') 
fp = open('google-logo.png', 'wb') 
fp.write(base64.b64decode(downloaded_file)) 
fp.close() 
print('\tDone') 
driver.close() # close web browser, or it'll persist after python exits. 
display.popen.kill() # close virtual display, or it'll persist after python exits. 

Explaination

Wir sind auf der Domäne zuerst eine URL laden wir aus einer Datei herunterladen Targeting sind. Auf diese Weise können wir eine AJAX-Anfrage für diese Domain durchführen, ohne auf cross site scripting Probleme zu stoßen.

Als nächstes injizieren wir etwas Javascript in das DOM, das eine AJAX-Anfrage auslöst. Sobald die AJAX-Anforderung eine Antwort zurückgibt, nehmen wir die Antwort und laden sie in ein FileReader-Objekt. Von dort können wir den Base64-codierten Inhalt der Datei durch Aufrufen von readAsDataUrl() extrahieren. Wir nehmen dann den base64-codierten Inhalt und fügen ihn an window an, eine Variable, die für alle zugänglich ist.

Schließlich, da die AJAX-Anfrage asynchron ist, geben wir eine Python-while-Schleife ein, die darauf wartet, dass der Inhalt an das Fenster angehängt wird. Sobald es angehängt ist, dekodieren wir den Base64-Inhalt aus dem Fenster und speichern ihn in einer Datei.

Diese Lösung sollte in allen modernen Browsern funktionieren, die von Selenium unterstützt werden, und funktioniert sowohl in Text- als auch in Binärdateien und für alle MIME-Typen.

alternativer Ansatz

Während ich dies nicht getestet haben, hat Selen Sie die Möglichkeit, sich leisten zu warten, bis ein Element im DOM vorhanden ist. Anstatt eine Schleife zu erstellen, bis eine global zugängliche Variable gefüllt ist, können Sie ein Element mit einer bestimmten ID im DOM erstellen und die Bindung dieses Elements als Auslöser zum Abrufen der heruntergeladenen Datei verwenden.

1

In Chrom, was ich tun ist, um die Dateien herunterzuladen, indem Sie auf die Links klicken, dann öffne ich chrome://downloads Seite und dann rufen Sie die heruntergeladenen Dateien Liste von Schatten DOM wie folgt aus:

docs = document 
    .querySelector('downloads-manager') 
    .shadowRoot.querySelector('#downloads-list') 
    .getElementsByTagName('downloads-item') 

Diese Lösung Chrom zurückgehalten wird enthalten die Daten auch Informationen wie Dateipfad und Downloaddatum. (beachten Sie, dass dieser Code aus JS stammt, möglicherweise nicht die korrekte Python-Syntax)