【发布时间】:2016-03-24 04:13:03
【问题描述】:
我使用 selenium 来启动下载。下载完成后,需要采取一些措施,有没有什么简单的方法可以判断下载完成的时间? (我使用的是 FireFox 驱动)
【问题讨论】:
我使用 selenium 来启动下载。下载完成后,需要采取一些措施,有没有什么简单的方法可以判断下载完成的时间? (我使用的是 FireFox 驱动)
【问题讨论】:
我最近遇到了这个问题。我一次下载多个文件,如果下载失败,我必须以超时的方式构建。
代码每秒检查某个下载目录中的文件名,并在完成或完成时间超过 20 秒后退出。返回的下载时间用于检查下载是否成功或是否超时。
import time
import os
def download_wait(path_to_downloads):
seconds = 0
dl_wait = True
while dl_wait and seconds < 20:
time.sleep(1)
dl_wait = False
for fname in os.listdir(path_to_downloads):
if fname.endswith('.crdownload'):
dl_wait = True
seconds += 1
return seconds
我相信这仅适用于 chrome 文件,因为它们以 .crdownload 扩展名结尾。可能有类似的方法可以在其他浏览器中进行检查。
编辑:我最近更改了使用此功能的方式,因为.crdownload 没有作为扩展名出现。本质上,这也只是等待正确数量的文件。
def download_wait(directory, timeout, nfiles=None):
"""
Wait for downloads to finish with a specified timeout.
Args
----
directory : str
The path to the folder where the files will be downloaded.
timeout : int
How many seconds to wait until timing out.
nfiles : int, defaults to None
If provided, also wait for the expected number of files.
"""
seconds = 0
dl_wait = True
while dl_wait and seconds < timeout:
time.sleep(1)
dl_wait = False
files = os.listdir(directory)
if nfiles and len(files) != nfiles:
dl_wait = True
for fname in files:
if fname.endswith('.crdownload'):
dl_wait = True
seconds += 1
return seconds
【讨论】:
没有内置到 selenium 的方式来等待下载完成。
这里的一般想法是等到文件出现在您的“下载”目录中。
这可以通过一遍又一遍地检查文件是否存在来实现:
或者,通过使用 watchdog 之类的东西来监控目录:
【讨论】:
import os
import time
def latest_download_file():
path = r'Downloads folder file path'
os.chdir(path)
files = sorted(os.listdir(os.getcwd()), key=os.path.getmtime)
newest = files[-1]
return newest
fileends = "crdownload"
while "crdownload" == fileends:
time.sleep(1)
newest_file = latest_download_file()
if "crdownload" in newest_file:
fileends = "crdownload"
else:
fileends = "none"
这是几种解决方案的组合。我不喜欢我必须扫描整个下载文件夹以查找以“crdownload”结尾的文件。此代码实现了一个功能,该功能可在下载文件夹中提取最新文件。然后它只是检查该文件是否仍在下载。将它用于我正在构建的 Selenium 工具,效果很好。
【讨论】:
我知道答案为时已晚,但想为未来的读者分享一个技巧。
您可以从主线程创建一个线程,例如 thread1 并在此处启动您的下载。 现在,创建另一个线程,比如 thread2 并在那里,让它等到 thread1 使用 join() 方法完成。现在,您可以在之后继续执行流程下载完成。
仍然确保您不使用 selenium 启动下载,而是使用 selenium 提取链接并使用 requests 模块进行下载。
Download using requests module
例如:
def downloadit():
#download code here
def after_dwn():
dwn_thread.join() #waits till thread1 has completed executing
#next chunk of code after download, goes here
dwn_thread = threading.Thread(target=downloadit)
dwn_thread.start()
metadata_thread = threading.Thread(target=after_dwn)
metadata_thread.start()
【讨论】:
如前所述,没有本地方法可以检查下载是否完成。所以这里有一个辅助函数可以为 Firefox 和 Chrome 完成这项工作。一个技巧是在开始新下载之前清除临时下载文件夹。此外,使用原生 pathlib 进行跨平台使用。
from pathlib import Path
def is_download_finished(temp_folder):
firefox_temp_file = sorted(Path(temp_folder).glob('*.part'))
chrome_temp_file = sorted(Path(temp_folder).glob('*.crdownload'))
downloaded_files = sorted(Path(temp_folder).glob('*.*'))
if (len(firefox_temp_file) == 0) and \
(len(chrome_temp_file) == 0) and \
(len(downloaded_files) >= 1):
return True
else:
return False
【讨论】:
在下载目录的文件名中检查“Unconfirmed”关键字:
# wait for download complete
wait = True
while(wait==True):
for fname in os.listdir('\path\to\download directory'):
if ('Unconfirmed') in fname:
print('downloading files ...')
time.sleep(10)
else:
wait=False
print('finished downloading all files ...')
文件下载完成后立即退出while循环。
【讨论】:
x1=0
while x1==0:
count=0
li = os.listdir("directorypath")
for x1 in li:
if x1.endswith(".crdownload"):
count = count+1
if count==0:
x1=1
else:
x1=0
如果您尝试检查一组文件(多个)是否已完成下载,则此方法有效。
【讨论】:
这对我有用:
fileends = "crdownload"
while "crdownload" in fileends:
sleep(1)
for fname in os.listdir(some_path):
print(fname)
if "crdownload" in fname:
fileends = "crdownload"
else:
fileends = "None"
【讨论】:
如果使用 Selenium 和 Chrome,您可以编写自定义等待条件,例如:
class file_has_been_downloaded(object):
def __init__(self, dir, number):
self.dir = dir
self.number = number
def __call__(self, driver):
print(count_files(dir), '->', self.number)
return count_files(dir) > self.number
count_files 函数只是验证文件是否已添加到文件夹中
def count_files(direct):
for root, dirs, files in os.walk(direct):
return len(list(f for f in files if f.startswith('MyPrefix') and (
not f.endswith('.crdownload')) ))
然后在你的代码中实现这个:
files = count_files(dir)
<< copy the file. Possibly use shutil >>
WebDriverWait(driver, 30).until(file_has_been_downloaded(dir, files))
【讨论】:
对于 Chrome,未完成下载的文件具有扩展名 .crdownload。如果你 set your download directory 正确,那么你可以等到你想要的文件不再有这个扩展名。原则上,这与等待文件存在(如suggested by alecxe)没有太大区别——但至少您可以通过这种方式监控进度。
【讨论】:
我有一个更好的:
所以重定向开始下载的函数。例如download_function= lambda: element.click()
检查目录中的文件数并等待没有下载扩展名的新文件。之后重命名它。 (可以更改以移动文件而不是在同一目录中重命名)
def save_download(self, directory, download_function, new_name, timeout=30):
"""
Download a file and rename it
:param directory: download location that is set
:param download_function: function to start download
:param new_name: the name that the new download gets
:param timeout: number of seconds to wait for download
:return: path to downloaded file
"""
self.logger.info("Downloading " + new_name)
files_start = os.listdir(directory)
download_function()
wait = True
i = 0
while (wait or len(os.listdir(directory)) == len(files_start)) and i < timeout * 2:
sleep(0.5)
wait = False
for file_name in os.listdir(directory):
if file_name.endswith('.crdownload'):
wait = True
if i == timeout * 2:
self.logger.warning("Documents not downloaded")
raise TimeoutError("File not downloaded")
else:
self.logger.info("Downloading done")
new_file = [name for name in os.listdir(directory) if name not in files_start][0]
self.logger.info("New file found renaming " + new_file + " to " + new_name)
while not os.access(directory + r"\\" + new_file, os.W_OK):
sleep(0.5)
self.logger.info("Waiting for write permission")
os.rename(directory + "\\" + new_file, directory + "\\" + new_name)
return directory + "\\" + new_file
【讨论】:
创建一个使用“请求”获取文件内容并调用该函数的函数,除非文件被下载,否则您的程序将不会前进
import requests
from selenium import webdriver
driver = webdriver.Chrome()
# Open the website
driver.get(website_url_)
x = driver.find_element_by_partial_link_text('download')
y = x.get_attribute("href")
fc = requests.get(y)
fname = x.text
with open(fname, 'wb') as f:
f.write(fc.content)
【讨论】: