簡體   English   中英

如何使用 selenium 在點擊事件中下載文件?

[英]How can I download a file on a click event using selenium?

我正在研究 python 和 selenium。 我想使用 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 的名稱為“導出數據”的鏈接下載這兩個文件。 我怎樣才能實現它,因為它只適用於點擊事件?

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

添加了配置文件操作代碼以防止下載對話框。

我承認這個解決方案比 Firefox Profile saveToDisk 替代方案更“hacky”,但它適用於 Chrome 和 Firefox,並且不依賴於隨時可能更改的特定於瀏覽器的功能。 如果不出意外,也許這會讓某人對如何解決未來的挑戰有一些不同的看法。

先決條件:確保您已安裝 selenium 和 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。 這允許我們在該域上執行 AJAX 請求,而不會遇到跨站點腳本問題。

接下來,我們將一些 javascript 注入到觸發 AJAX 請求的 DOM 中。 一旦 AJAX 請求返回響應,我們就獲取響應並將其加載到 FileReader 對象中。 從那里我們可以通過調用 readAsDataUrl() 提取文件的 base64 編碼內容。 然后我們將 base64 編碼的內容附加到window ,這是一個全局可訪問的變量。

最后,因為 AJAX 請求是異步的,我們進入了一個 Python while 循環,等待將內容追加到窗口中。 附加后,我們解碼從窗口中檢索到的 base64 內容並將其保存到文件中。

此解決方案應適用於 Selenium 支持的所有現代瀏覽器,並且適用於文本或二進制以及所有 MIME 類型。

替代方法

雖然我還沒有對此進行測試,但 Selenium 確實為您提供了等待元素出現在 DOM 中的能力。 您可以在 DOM 中創建一個具有特定 ID 的元素,並使用該元素的綁定作為觸發器來檢索下載的文件,而不是循環直到填充一個全局可訪問的變量。

在 chrome 中,我所做的是通過單擊鏈接下載文件,然后打開chrome://downloads頁面,然后從 shadow DOM 中檢索下載的文件列表,如下所示:

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

此解決方案僅限於 chrome,數據還包含文件路徑和下載日期等信息。 (注意這段代碼來自JS,可能不是正確的python語法)

這是完整的工作代碼。 您可以使用網頁抓取來輸入用戶名密碼和其他字段。 要獲取網頁上顯示的字段名稱,請使用檢查元素。 元素名稱(用戶名、密碼或單擊按鈕)可以通過類或名稱輸入。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM