playwright-python icon indicating copy to clipboard operation
playwright-python copied to clipboard

[Feature]: Add BrowserContext expect_download Methods support

Open baijiu-in-my-cup opened this issue 3 months ago • 4 comments

🚀 Feature Request

Performs action and waits for a new Download on BrowserContext.

Example

No response

Motivation

The page.expect_download() method seens cannot handle scenarios where the download is triggered from a newly opened popup window.

To work around this, I'm currently using page.context.expect_event('page') to capture the new page and then active trigger the download in this page. However, this bring about a new question,I will trigger downloads repeatedly.

    def _download_file(self) -> str:
        def download_page_handler(page: Page):
            with page.expect_download() as download_info:
                page.reload()
            download = download_info.value
            self.logger.debug(f"Suggested Filename:{download.suggested_filename}")
            suffix = pathlib.Path(download.suggested_filename).suffix
            download_path: pathlib.Path = (
                generate_filepath(
                    out_dirs=[self.params.base_output_path,
                              self.params.account_number],
                    suffix=suffix,
                )
                if not self.params.output_path.suffix
                else self.params.output_path.with_suffix(suffix)
            )
            download.save_as(download_path)
            self.logger.info(f"[{self.params.account_number}] Save To {download_path}")
            page.close()
            return str(download_path)

        with self.page.context.expect_event('page') as event_info:
            self.win_frame.locator('.tableFooter').get_by_text(
                'Download all', exact=True).click(no_wait_after=True)
            self.win_frame.get_by_role("listitem").filter(
            has_text="Excel").click()

        return download_page_handler(event_info.value)

baijiu-in-my-cup avatar Sep 19 '25 09:09 baijiu-in-my-cup

I have also tried using the downloads_path parameter in BrowserType, but the temporary filenames downloaded in the global environment are not user-friendly. I'm unsure how I should proceed with this operation. please save me,thank u!

baijiu-in-my-cup avatar Sep 19 '25 10:09 baijiu-in-my-cup

def _download_file(self) -> str:
    def download_page_handler(page: Page):
        with page.expect_download() as download_info:
            page.reload()
        download = download_info.value
        self.logger.debug(f"Suggested Filename: {download.suggested_filename}")
        suffix = pathlib.Path(download.suggested_filename).suffix
        download_path: pathlib.Path = (
            generate_filepath(
                out_dirs=[self.params.base_output_path,
                          self.params.account_number],
                suffix=suffix,
            )
            if not self.params.output_path.suffix
            else self.params.output_path.with_suffix(suffix)
        )
        download.save_as(download_path)
        self.logger.info(f"[{self.params.account_number}] Save To {download_path}")
        page.close()
        return str(download_path)

    # Handle both cases: direct download on current page OR popup
    with self.page.expect_download() as direct_download, \
         self.page.context.expect_event("page") as popup_info:
        self.win_frame.locator(".tableFooter").get_by_text(
            "Download all", exact=True
        ).click(no_wait_after=True)
        self.win_frame.get_by_role("listitem").filter(
            has_text="Excel"
        ).click()

    # Case 1: download triggered directly (no popup)
    if direct_download.value:
        download = direct_download.value
        self.logger.debug(f"Suggested Filename: {download.suggested_filename}")
        suffix = pathlib.Path(download.suggested_filename).suffix
        download_path: pathlib.Path = (
            generate_filepath(
                out_dirs=[self.params.base_output_path,
                          self.params.account_number],
                suffix=suffix,
            )
            if not self.params.output_path.suffix
            else self.params.output_path.with_suffix(suffix)
        )
        download.save_as(download_path)
        self.logger.info(f"[{self.params.account_number}] Save To {download_path}")
        return str(download_path)

    # Case 2: popup opened, so hand it to handler
    popup = popup_info.value
    return download_page_handler(popup)

Problem: page.expect_download() fails when the download is triggered from a new popup window. It only works if the download happens on the same page.

Suggestion Add a context.expect_download() method so downloads can be caught regardless of whether they start in the main page or a popup.

Alphaboy20023 avatar Sep 21 '25 09:09 Alphaboy20023

def _download_file(self) -> str: def download_page_handler(page: Page): with page.expect_download() as download_info: page.reload() download = download_info.value self.logger.debug(f"Suggested Filename: {download.suggested_filename}") suffix = pathlib.Path(download.suggested_filename).suffix download_path: pathlib.Path = ( generate_filepath( out_dirs=[self.params.base_output_path, self.params.account_number], suffix=suffix, ) if not self.params.output_path.suffix else self.params.output_path.with_suffix(suffix) ) download.save_as(download_path) self.logger.info(f"[{self.params.account_number}] Save To {download_path}") page.close() return str(download_path)

# Handle both cases: direct download on current page OR popup
with self.page.expect_download() as direct_download, \
     self.page.context.expect_event("page") as popup_info:
    self.win_frame.locator(".tableFooter").get_by_text(
        "Download all", exact=True
    ).click(no_wait_after=True)
    self.win_frame.get_by_role("listitem").filter(
        has_text="Excel"
    ).click()

# Case 1: download triggered directly (no popup)
if direct_download.value:
    download = direct_download.value
    self.logger.debug(f"Suggested Filename: {download.suggested_filename}")
    suffix = pathlib.Path(download.suggested_filename).suffix
    download_path: pathlib.Path = (
        generate_filepath(
            out_dirs=[self.params.base_output_path,
                      self.params.account_number],
            suffix=suffix,
        )
        if not self.params.output_path.suffix
        else self.params.output_path.with_suffix(suffix)
    )
    download.save_as(download_path)
    self.logger.info(f"[{self.params.account_number}] Save To {download_path}")
    return str(download_path)

# Case 2: popup opened, so hand it to handler
popup = popup_info.value
return download_page_handler(popup)

Problem:  问题: page.expect_download() fails when the download is triggered from a new popup window. It only works if the download happens on the same page.当下载由新弹窗触发时,page.expect_download() 失败。只有当下载发生在同一页面上时,它才能正常工作。

Suggestion  建议 Add a context.expect_download() method so downloads can be caught regardless of whether they start in the main page or a popup.添加一个 context.expect_download() 方法,以便无论下载是从主页面还是弹窗开始,都能捕获下载。

Thank you! My English is not good, and my expression of questions and requests is problematic. Thank you!

baijiu-in-my-cup avatar Sep 21 '25 10:09 baijiu-in-my-cup

do you still have any problems?

Alphaboy20023 avatar Sep 21 '25 14:09 Alphaboy20023