56

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

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から「データのエクスポート」という名前のリンクから両方のファイルをダウンロードしたい。クリックイベントのみで動作するため、どうすれば達成できますか?

4

4 に答える 4

16

このソリューションは、Firefox Profile saveToDisk の代替手段よりも少し「ハッキー」ですが、Chrome と Firefox の両方で機能し、いつでも変更される可能性のあるブラウザー固有の機能に依存していません。そして、少なくとも、これは将来の課題を解決する方法について、少し異なる視点を誰かに与えるでしょう.

前提条件:セレンとpyvirtualdisplayがインストールされていることを確認してください...

  • パイソン 2:sudo pip install selenium pyvirtualdisplay
  • パイソン 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 を読み込みます。これにより、クロスサイト スクリプティングの問題に遭遇することなく、そのドメインで AJAX リクエストを実行できます。

次に、AJAX リクエストを起動する JavaScript を DOM に挿入します。AJAX 要求が応答を返したら、応答を取得して FileReader オブジェクトに読み込みます。そこから、readAsDataUrl() を呼び出して、base64 でエンコードされたファイルのコンテンツを抽出できます。次に、base64 でエンコードされたコンテンツを取得し、それをwindowグローバルにアクセス可能な変数である に追加します。

最後に、AJAX 要求は非同期であるため、コンテンツがウィンドウに追加されるのを待機する Python の while ループに入ります。追加したら、ウィンドウから取得した base64 コンテンツをデコードし、ファイルに保存します。

このソリューションは、Selenium でサポートされている最新のすべてのブラウザーで機能し、テキストかバイナリかに関係なく、すべての MIME タイプで機能します。

別のアプローチ

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

于 2016-04-14T03:50:00.460 に答える
1

これが完全な作業コードです。Webスクレイピングを使用して、ユーザー名パスワードおよびその他のフィールドを入力できます。Web ページに表示されるフィールド名を取得するには、inspect 要素を使用します。要素名 (ユーザー名、パスワード、またはクリック ボタン) は、クラスまたは名前で入力できます。

from selenium import webdriver
# Using Chrome to access web
options = webdriver.ChromeOptions() 
options.add_argument("download.default_directory=C:/Test") # Set the download Path
driver = webdriver.Chrome(options=options)
# Open the website
try:
    driver.get('xxxx') # Your Website Address
    password_box = driver.find_element_by_name('password')
    password_box.send_keys('xxxx') #Password
    download_button = driver.find_element_by_class_name('link_w_pass')
    download_button.click()
    driver.quit()
except:
    driver.quit()
    print("Faulty URL")
于 2019-09-08T11:05:59.197 に答える