2013-08-26 17 views
27

私はpythonとセレンに取り組んでいます。セレンを使ってイベントをクリックしてファイルをダウンロードしたい私は次のコードを書いた。セレンを使ってファイルをダウンロード

from selenium import webdriver 
from selenium.common.exceptions import NoSuchElementException 
from selenium.webdriver.common.keys import Keys 

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

browser.close() 

指定したURLから「Export Data」という名前のリンクから両方のファイルをダウンロードしたいとします。クリックイベントでのみ動作するので、どのように達成できますか?

おかげ

+1

私は 'urllib'を使用して、' urll'がリンクが送るURLである 'urllib.urlretrieve(url)'を使ってダウンロードを取得することをお勧めしますクリックイベントでのみ機能するため、 – Serial

+0

は使用できません。 – sam

+0

ページのHTMLを解析すると、クリックイベントがブラウザに送信するリンクを取得し、それを使用することができます。 – Serial

答えて

41

find_element(s)_by_*を使用してリンクを見つけ、その後、clickメソッドを呼び出します。

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() 

ダウンロードダイアログを防止するためのプロファイル操作コードが追加されました。

+0

処理中にブラウザを非表示にするか、ブラウザを非表示/最小化モードにしたい場合はどうすればよいですか? – sam

+0

@sam、 'headless' +' selenium' + 'firefox'を検索してください。 – falsetru

+0

@sam、または 'phanromjs'、' ghostdriver'です。 – falsetru

4

FirefoxのsaveToDiskの代わりに、このソリューションはもう少し "ハッキー"ですが、ChromeとFirefoxの両方で動作し、いつでも変更できるブラウザ固有の機能には依存しません。それ以外のものがあれば、将来の課題を解決する方法について、誰かに少し違った視点を与えるでしょう。

前提条件

  • あなたはセレンを持っていることを確認し、インストールpyvirtualdisplay ...

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

マジック

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. 

我々は最初から私たちは、ファイルのダウンロードをターゲットにしているドメイン上のURLをロード

、について説明。これにより、cross site scriptingの問題が発生することなく、そのドメインでAJAXリクエストを実行できます。

次に、AJAXリクエストを発生させるDOMにjavascriptを注入しています。 AJAXリクエストがレスポンスを返すと、レスポンスを取得してFileReaderオブジェクトにロードします。そこから、readAsDataUrl()を呼び出して、ファイルのbase64でコード化されたコンテンツを抽出することができます。次に、base64でエンコードされたコンテンツを取り出し、それを曖昧にアクセス可能な変数windowに追加します。

最後に、AJAXリクエストが非同期であるため、コンテンツをウィンドウに追加するのを待っている間にPythonを入力します。追加されると、ウィンドウから取得したbase64コンテンツをデコードし、ファイルに保存します。

このソリューションは、Seleniumでサポートされているすべての最新のブラウザで動作し、テキストまたはバイナリ、およびすべてのMIMEタイプに対応しています。

代替アプローチ

私はこれをテストしていませんが、セレンはあなたに要素がDOMに存在するまで待機する能力を買う余裕はありません。グローバルにアクセス可能な変数が移入されるまでループするのではなく、DOMに特定のIDを持つ要素を作成し、その要素のバインディングをトリガーとして使用してダウンロードしたファイルを取得することができます。

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

この溶液をクロムに拘束されている:私はその後、私はこのようなシャドウDOMからダウンロードしたファイルの一覧を取得し、その後chrome://downloadsページを開くと、リンクをクリックしてファイルをダウンロードしてくださいChromeで

1

データには、ファイルパスやダウンロード日付などの情報も含まれています。 (このコードはJSのものであり、正しいPythonの構文ではないかもしれません)

関連する問題