我正在研究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()
我想从给定网址名称为“导出数据”的链接下载这两个文件。我如何才能实现它,因为它只适用于点击事件?
答案 0 :(得分:55)
使用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()
添加了配置文件操作代码以防止下载对话框。
答案 1 :(得分:6)
我承认这个解决方案比Firefox Profile saveToDisk更加“hacky”,但它适用于Chrome和Firefox,并且不依赖于可能随时更改的浏览器特定功能。如果不出意外,也许这会让人对如何解决未来的挑战有不同的看法。
先决条件:确保您安装了selenium和pyvirtualdisplay ......
sudo pip install selenium pyvirtualdisplay
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.
<强>释强>
我们首先在我们定位文件下载的域上加载网址。这允许我们在该域上执行AJAX请求,而不会遇到cross site scripting问题。
接下来,我们将一些javascript注入DOM,从而触发AJAX请求。一旦AJAX请求返回响应,我们将获取响应并将其加载到FileReader对象中。从那里我们可以通过调用readAsDataUrl()来提取文件的base64编码内容。然后我们将base64编码的内容添加到window
,这是一个可以访问的变量。
最后,因为AJAX请求是异步的,所以我们进入Python while循环,等待将内容附加到窗口。一旦附加,我们解码从窗口检索到的base64内容并将其保存到文件中。
此解决方案适用于Selenium支持的所有现代浏览器,无论是文本还是二进制,以及所有mime类型都可以使用。
替代方法
虽然我没有对此进行测试,但Selenium确实让您能够等到DOM中存在元素。您可以在DOM中创建一个具有特定ID的元素,并使用该元素的绑定作为检索下载文件的触发器,而不是循环直到填充全局可访问变量。
答案 2 :(得分:3)
在chrome中,我所做的是通过单击链接下载文件,然后打开chrome://downloads
页面,然后从shadow DOM中检索下载的文件列表,如下所示:
docs = document
.querySelector('downloads-manager')
.shadowRoot.querySelector('#downloads-list')
.getElementsByTagName('downloads-item')
此解决方案仅限于chrome,数据还包含文件路径和下载日期等信息。 (注意这段代码来自JS,可能不是正确的python语法)
答案 3 :(得分:-1)
这是完整的工作代码。您可以使用网页抓取输入用户名密码和其他字段。要使字段名称显示在网页上,请使用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")