【问题标题】:Download a file to a specific path using Selenium WebDriver使用 Selenium WebDriver 将文件下载到特定路径
【发布时间】:2012-01-09 02:24:43
【问题描述】:

我需要将文件下载到非本地计算机上的给定位置。这是我会这样做的网络浏览器的正常流程:

  • 访问网站
  • 点击按钮下载文件(是生成文件的表单,不是下载链接)
  • 网站提示“是否要下载此文件?”等提示窗口。

我希望能够绕过该文件并执行以下操作:

>>> path_to_download_path = PATH
>>> button = driver.find_element_by_css("...")
>>> button.click()

--> And the file is automatically downloaded to my PATH (or wherever I choose)

或者有没有更简单的方法click,可以自动下载文件内容?

我该怎么做?

【问题讨论】:

  • 我认为你只能设置下载路径,如果有一个输入字段或类似的东西可以设置路径 - webdriver 只能与用户可以在网站上看到的元素交互跨度>
  • 可能有助于了解您使用的浏览器,因为它们处理文件下载的方式往往不同

标签: python selenium webdriver


【解决方案1】:

初始化驱动程序时,请务必设置下载首选项。

对于火狐:

ff_prof.set_preference( "browser.download.manager.showWhenStarting", False )
ff_prof.set_preference( "browser.download.folderList", 2 )
ff_prof.set_preference( "browser.download.useDownloadDir", True )
ff_prof.set_preference( "browser.download.dir", self.driver_settings['download_folder'] )

##
# if FF still shows the download dialog, make sure that the filetype is included below
# filetype string options can be found in '~/.mozilla/$USER_PROFILE/mimeTypes.rdf'
##
mime_types = ("application/pdf", "text/html")

ff_prof.set_preference( "browser.helperApps.neverAsk.saveToDisk", (", ".join( mime_types )) )
ff_prof.set_preference( "browser.helperApps.neverAsk.openFile", (", ".join( mime_types )) )

对于 Chrome:

capabilities['chromeOptions']['prefs']['download.prompt_for_download'] = False
capabilities['chromeOptions']['prefs']['download.default_directory'] = self.driver_settings['download_folder']

转发下载:

下面是我用来将文件从self.driver_settings['download_folder'](如上设置)重定向到您实际想要文件的位置(to_path 可以是现有文件夹或文件路径)的代码。如果您使用的是 linux,我建议使用 tmpfs 以便将 /tmp 保存在 ram 中,然后将 self.driver_settings['download_folder'] 设置为 "/tmp/driver_downloads/"。请注意,以下函数假定 self.driver_settings['download_folder'] 始终以空文件夹开头(这是它定位正在下载的文件的方式,因为它是目录中唯一的文件)。

def moveDriverDownload(self, to_path, allowable_extensions, allow_rename_if_exists=False, timeout_seconds=None):
    if timeout_seconds is None:
        timeout_seconds = 30
    wait_delta = timedelta( seconds=timeout_seconds )
    start_download_time = datetime.now()
    hasTimedOut = lambda: datetime.now() - start_download_time > wait_delta

    assert isinstance(allowable_extensions, list) or isinstance(allowable_extensions, tuple) or isinstance(allowable_extensions, set), "instead of a list, found allowable_extensions type of '{}'".format(type(allowable_extensions))
    allowable_extensions = [ elem.lower().strip() for elem in allowable_extensions ]
    allowable_extensions = [ elem if elem.startswith(".") else "."+elem for elem in allowable_extensions ]

    if not ".part" in allowable_extensions:
        allowable_extensions.append( ".part" )

    re_extension_str = "(?:" + ("$)|(?:".join( re.escape(elem) for elem in allowable_extensions )) + "$)"

    getFiles = lambda: next( os.walk( self.driver_settings['download_folder'] ) )[2]

    while True:
        if hasTimedOut():
            del allowable_extensions[ allowable_extensions.index(".part") ]
            raise DownloadTimeoutError( "timed out after {} seconds while waiting on file download with extension in {}".format(timeout_seconds, allowable_extensions) )

        time.sleep( 0.5 )

        file_list = [ elem for elem in getFiles() if re.search( re_extension_str, elem ) ]
        if len(file_list) > 0:
            break

    file_list = [ re.search( r"(?i)^(.*?)(?:\.part)?$", elem ).groups()[0] for elem in file_list ]

    if len(file_list) > 1:
        if len(file_list) == 2:
            if file_list[0] != file_list[1]:
                raise Exception( "file_list[0] != file_list[1] <==> {} != {}".format(file_list[0], file_list[1]) )
        else:
            raise Exception( "len(file_list) > 1. found {}".format(file_list) )

    file_path = "%s%s" %(self.driver_settings['download_folder'], file_list[0])

    # see if the file is still being downloaded by checking if it's open by any programs
    if platform.system() == "Linux":
        openProcess = lambda: subprocess.Popen( 'lsof | grep "%s"' %file_path, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE )
        fileIsFinished = lambda txt: txt.strip() == ""
    elif platform.system() == "Windows":
        # 'handle' program must be in PATH
        # https://technet.microsoft.com/en-us/sysinternals/bb896655
        openProcess = lambda: subprocess.Popen( 'handle "%s"' %file_path.replace("/", "\\"), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE )
        fileIsFinished = lambda txt: bool( re.search("(?i)No matching handles found", txt) )
    else:
        raise Exception( "unrecognised platform.system() of '{}'".format(platform.system()) )

    while True:
        lsof_process = openProcess()
        lsof_result = lsof_process.communicate()

        if len(lsof_result) != 2:
            raise Exception( "len(lsof_result) != 2. found {}".format(lsof_result) )
        if lsof_result[1].strip() != "":
            raise Exception( 'lsof_result[1].strip() != "". found {}'.format(lsof_result) )
        if fileIsFinished( lsof_result[0] ):
            break

        if hasTimedOut():
            raise Exception( "timed out after {} seconds waiting for '{}' to be freed from writing. found lsof/handle of '{}'".format(timeout_seconds, file_path, lsof_result[0]) )

        time.sleep( 0.5 )

    to_path = to_path.replace("\\", "/")
    if os.path.isdir( to_path ):
        if not to_path.endswith("/"):
            to_path += "/"

        to_path += file_list[0]

    i = 2
    while os.path.exists( to_path ):
        if not allow_rename_if_exists:
            raise Exception( "{} already exists".format(to_path) )

        to_path = re.sub( "^(.*/)(.*?)(?:-" + str(i-1) + r")?(|\..*?)?$", r"\1\2-%i\3" %i, to_path )
        i += 1

    shutil.move( file_path, to_path )

    return to_path[ to_path.rindex("/")+1: ]

【讨论】:

    【解决方案2】:

    使用 selenium 网络驱动程序

    使用 Firefox 配置文件下载您的文件。此配置文件跳过 Firefox 的对话框。 在线:-

       pro.setPreference("browser.downLoad.folderList", 0);
    

    browser.download.folderList 的值可以设置为 0、1 或 2。设置为 0 时,Firefox 会将通过浏览器下载的所有文件保存在用户桌面上。设置为 1 时,这些下载内容存储在 Downloads 文件夹中。设置为 2 时,将再次使用为最近下载指定的位置。

    您需要实现的 Firefox 配置文件代码:-

            FirefoxProfile pro=new FirefoxProfile();
            pro.setPreference("browser.downLoad.folderList", 0);
            pro.setPreference("browser.helperApps.neverAsk.saveToDisk", "Applications/zip");
            WebDriver driver=new FirefoxDriver(pro);
            driver.get("http://selenium-release.storage.googleapis.com/2.47/selenium-java-2.47.1.zip");
    

    希望对你有帮助:)

    【讨论】:

    • 对“browser.downLoad.folderList”中0,1,2选项的有用解释
    • 但是如果我将 0 更改为 2 并指定 PATH 来保存下载的文件,为什么所有文件都存储到 /tmp/mozilla_[user]0/
    【解决方案3】:

    您必须先检查网站上的 javascript 并了解它的工作原理,然后才能覆盖它以执行类似操作,但即便如此,浏览器安全性始终会弹出一个对话框,要求您确认下载。这给你留下了两个选择(据我所知):

    • 确认警报对话框
    • 确定文件在远程服务器上的位置,并使用 GET 下载文件

    因为我不懂python,所以我真的无法提供任何细节方面的帮助,但希望这会有所帮助......

    【讨论】:

      猜你喜欢
      • 2019-12-28
      • 1970-01-01
      • 2014-05-08
      • 1970-01-01
      • 1970-01-01
      • 2019-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多