使用 chrome headless 和 selenium 下载

2024-12-31 08:37:00
admin
原创
38
摘要:问题描述:我正在使用 python-selenium 和 Chrome 59,并尝试自动执行一个简单的下载序列。当我正常启动浏览器时,下载可以正常工作,但是当我在无头模式下启动浏览器时,下载不起作用。# Headless implementation from selenium import webdrive...

问题描述:

我正在使用 python-selenium 和 Chrome 59,并尝试自动执行一个简单的下载序列。当我正常启动浏览器时,下载可以正常工作,但是当我在无头模式下启动浏览器时,下载不起作用。

# Headless implementation
from selenium import webdriver

chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument("headless")

driver = webdriver.Chrome(chrome_options=chromeOptions)

driver.get('https://www.mockaroo.com/')
driver.find_element_by_id('download').click()
# ^^^ Download doesn't start

# Normal Mode
from selenium import webdriver

driver = webdriver.Chrome()

driver.get('https://www.mockaroo.com/')
driver.find_element_by_id('download').click()
# ^^^ Download works normally

我甚至尝试添加默认路径:

prefs = {"download.default_directory" : "/Users/Chetan/Desktop/"}
chromeOptions.add_argument("headless")
chromeOptions.add_experimental_option("prefs",prefs)

在正常实现中添加默认路径是可行的,但在无头版本中仍然存在同样的问题。

如何让下载以无头模式开始?


解决方案 1:

Chromium 开发人员最近添加了第二种无头模式(2021 年)。请参阅https://bugs.chromium.org/p/chromium/issues/detail?id=706008#c36

他们后来在 2023 年为 Chrome 109 重新命名了该选项 -> https://github.com/chromium/chromium/commit/e9c516118e2e1923757ecb13e6d9fff36775d1f4

对于 Chrome 109 及更高版本,该--headless=new标志现在可让您在新的无头模式下获得 Chrome 的全部功能,甚至可以在其中运行扩展程序。(对于 Chrome 96 至 108 版本,请使用--headless=chrome

使用方法:(Chrome 109 及以上版本):

options.add_argument("--headless=new")

使用方法:(Chrome 96 至 Chrome 108):

options.add_argument("--headless=chrome")

如果某些功能在常规 Chrome 中可以运行,那么现在它也应该可以在较新的无头模式下运行。

解决方案 2:

是的,出于安全考虑,这是一个“功能”。如前所述,这里是错误讨论:https://bugs.chromium.org/p/chromium/issues/detail ?id=696481

在chrome 62.0.3196.0以上版本中添加了支持下载。

这是一个 python 实现。我必须将该命令添加到 chromedriver 命令中。我将尝试提交 PR,以便将来将其包含在库中。

def enable_download_in_headless_chrome(self, driver, download_dir):
    # add missing support for chrome "send_command"  to selenium webdriver
    driver.command_executor._commands["send_command"] = ("POST", '/session/$sessionId/chromium/send_command')

    params = {'cmd': 'Page.setDownloadBehavior', 'params': {'behavior': 'allow', 'downloadPath': download_dir}}
    command_result = driver.execute("send_command", params)

作为参考,这里有一个小仓库来演示如何使用它:
https://github.com/shawnbutton/PythonHeadlessChrome

更新 2020-05-01有评论说这个不再起作用了。鉴于这个补丁已经一年多了,他们很可能已经改变了底层库。

解决方案 3:

以下是基于Shawn Button 的回答的 Python 工作示例。我已经使用Chromium 68.0.3440.75chromedriver 2.38进行了测试

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_options = Options()
chrome_options.add_experimental_option("prefs", {
  "download.default_directory": "/path/to/download/dir",
  "download.prompt_for_download": False,
})

chrome_options.add_argument("--headless")
driver = webdriver.Chrome(chrome_options=chrome_options)

driver.command_executor._commands["send_command"] = ("POST", '/session/$sessionId/chromium/send_command')
params = {'cmd': 'Page.setDownloadBehavior', 'params': {'behavior': 'allow', 'downloadPath': "/path/to/download/dir"}}
command_result = driver.execute("send_command", params)

driver.get('http://download-page.url/')
driver.find_element_by_css_selector("#download_link").click()

解决方案 4:

这是 Chrome 的一项功能,用于阻止软件将文件下载到您的计算机。不过有一个解决方法。点击此处了解更多信息。

您需要做的是通过 DevTools 启用它,如下所示:

async function setDownload () {
  const client = await CDP({tab: 'ws://localhost:9222/devtools/browser'});
  const info =  await client.send('Browser.setDownloadBehavior', {behavior : "allow", downloadPath: "/tmp/"});
  await client.close();
}

这是某人在上述主题中给出的解决方案。以下是他的评论。

解决方案 5:

更新后的 PYTHON 解决方案 - 于 2021 年 3 月 4 日在 chromedriver v88 和 v89 上进行了测试

这将允许您以无头模式单击下载文件。

    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.chrome.options import Options

    # Instantiate headless driver
    chrome_options = Options()

    # Windows path
    chromedriver_location = 'C:\\path\\to\\chromedriver_win32\\chromedriver.exe'
    # Mac path. May have to allow chromedriver developer in os system prefs
    '/Users/path/to/chromedriver'

    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-dev-shm-usage")
    
    chrome_prefs = {"download.default_directory": r"C:path    oDownloads"} # (windows)
    chrome_options.experimental_options["prefs"] = chrome_prefs

    driver = webdriver.Chrome(chromedriver_location,options=chrome_options)

    # Download your file
    driver.get('https://www.mockaroo.com/')
    driver.find_element_by_id('download').click()

解决方案 6:

也许您处理的网站会针对不同的浏览器返回不同的 HTML 页面,这意味着您想要的 XPath 或 Id 在无头浏览器中可能有所不同。尝试在无头浏览器中下载 pageSource 并将其作为 HTML 页面打开以查看您想要的 Id 或 XPath。您可以将其视为 c# 示例如何隐藏 FirefoxDriver(使用 Selenium)而不在 PhantomDriver 中出现 findElement 函数错误?。

解决方案 7:

使用 selenium-cucumber-js / selenium-webdriver 的 JavaScript 完整工作示例:

const chromedriver = require('chromedriver');
const selenium = require('selenium-webdriver');
const command = require('selenium-webdriver/lib/command');
const chrome = require('selenium-webdriver/chrome');

module.exports = function() {

  const chromeOptions = new chrome.Options()
    .addArguments('--no-sandbox', '--headless', '--start-maximized', '--ignore-certificate-errors')
    .setUserPreferences({
      'profile.default_content_settings.popups': 0, // disable download file dialog
      'download.default_directory': '/tmp/downloads', // default file download location
      "download.prompt_for_download": false,
      'download.directory_upgrade': true,
      'safebrowsing.enabled': false,
      'plugins.always_open_pdf_externally': true,
      'plugins.plugins_disabled': ["Chrome PDF Viewer"]
    })
    .windowSize({width: 1600, height: 1200});

  const driver = new selenium.Builder()
    .withCapabilities({
      browserName: 'chrome',
      javascriptEnabled: true,
      acceptSslCerts: true,
      path: chromedriver.path
    })
    .setChromeOptions(chromeOptions)
    .build();

  driver.manage().window().maximize();

  driver.getSession()
    .then(session => {
      const cmd = new command.Command("SEND_COMMAND")
        .setParameter("cmd", "Page.setDownloadBehavior")
        .setParameter("params", {'behavior': 'allow', 'downloadPath': '/tmp/downloads'});
      driver.getExecutor().defineCommand("SEND_COMMAND", "POST", `/session/${session.getId()}/chromium/send_command`);
      return driver.execute(cmd);
    });

  return driver;
};

关键部分是:

  driver.getSession()
    .then(session => {
      const cmd = new command.Command("SEND_COMMAND")
        .setParameter("cmd", "Page.setDownloadBehavior")
        .setParameter("params", {'behavior': 'allow', 'downloadPath': '/tmp/downloads'});
      driver.getExecutor().defineCommand("SEND_COMMAND", "POST", `/session/${session.getId()}/chromium/send_command`);
      return driver.execute(cmd);
    });

已测试:

  • Chrome 67.0.3396.99

  • Chrome 驱动程序 2.36.540469

  • selenium-cucumber-js 1.5.12

  • selenium-webdriver 3.0.0

解决方案 8:

通常,看到用另一种语言编写的相同内容是多余的,但是因为这个问题让我抓狂,所以我希望我可以让别人免受痛苦......所以这里是Shawn Button 答案的 C# 版本(使用 headless chrome=71.0.3578.98、chromedriver=2.45.615279、platform=Linux 4.9.125-linuxkit x86_64 测试):

            var enableDownloadCommandParameters = new Dictionary<string, object>
            {
                { "behavior", "allow" },
                { "downloadPath", downloadDirectoryPath }
            };
            var result = ((OpenQA.Selenium.Chrome.ChromeDriver)driver).ExecuteChromeCommandWithResult("Page.setDownloadBehavior", enableDownloadCommandParameters);

解决方案 9:

以下是 Java、selenium、chromedriver 和 chrome v 71.x 中的等效代码。 中的代码是允许保存下载的关键附加 jar:com.fasterxml.jackson.core、com.fasterxml.jackson.annotation、com.fasterxml.jackson.databind

系统.setProperty(“webdriver.chrome.driver”,“C:\libraries\chromedriver.exe”);

            String downloadFilepath = "C:\\Download";
            HashMap<String, Object> chromePreferences = new HashMap<String, Object>();
            chromePreferences.put("profile.default_content_settings.popups", 0);
            chromePreferences.put("download.prompt_for_download", "false");
            chromePreferences.put("download.default_directory", downloadFilepath);
            ChromeOptions chromeOptions = new ChromeOptions();
            chromeOptions.setBinary("C:\\pathto\\Chrome SxS\\Application\\chrome.exe");

            //ChromeOptions options = new ChromeOptions();
            //chromeOptions.setExperimentalOption("prefs", chromePreferences);
            chromeOptions.addArguments("start-maximized");
            chromeOptions.addArguments("disable-infobars");


            //HEADLESS CHROME
            **chromeOptions.addArguments("headless");**

            chromeOptions.setExperimentalOption("prefs", chromePreferences);
            DesiredCapabilities cap = DesiredCapabilities.chrome();
            cap.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
            cap.setCapability(ChromeOptions.CAPABILITY, chromeOptions);

            **ChromeDriverService driverService = ChromeDriverService.createDefaultService();
            ChromeDriver driver = new ChromeDriver(driverService, chromeOptions);

            Map<String, Object> commandParams = new HashMap<>();
            commandParams.put("cmd", "Page.setDownloadBehavior");
            Map<String, String> params = new HashMap<>();
            params.put("behavior", "allow");
            params.put("downloadPath", downloadFilepath);
            commandParams.put("params", params);
            ObjectMapper objectMapper = new ObjectMapper();
            HttpClient httpClient = HttpClientBuilder.create().build();
            String command = objectMapper.writeValueAsString(commandParams);
            String u = driverService.getUrl().toString() + "/session/" + driver.getSessionId() + "/chromium/send_command";
            HttpPost request = new HttpPost(u);
            request.addHeader("content-type", "application/json");
            request.setEntity(new StringEntity(command));**
            try {
                httpClient.execute(request);
            } catch (IOException e2) {
                // TODO Auto-generated catch block
                e2.printStackTrace();
            }**

        //Continue using the driver for automation  
    driver.manage().window().maximize();

解决方案 10:

我使用 @Shawn Button 分享的解决方法并使用“downloadPath”参数的完整路径解决了这个问题。使用相对路径不起作用,并给出错误。

版本:

Chrome 版本 75.0.3770.100(官方版本)(32 位)

ChromeDriver 75.0.3770.90

解决方案 11:

使用:google-chrome-stable amd64 86.0.4240.111-1chromedriver 86.0.4240.22selenium 3.141.0 python 3.8.3

尝试了多种建议的解决方案,但对于 chrome headless 来说没有一个真正起作用,而且我的测试网站打开了一个新的空白标签,然后下载了数据。

最后放弃了无头并实现了pyvirtualdisplay并xvfd模拟 X 服务器,如下所示:

from selenium.webdriver.chrome.options import Options # and other imports
import selenium.webdriver as webdriver
import tempfile

url = "https://really_badly_programmed_website.org"

tmp_dir = tempfile.mkdtemp(prefix="hamster_")

driver_path="/usr/bin/chromedriver"

chrome_options = Options() 
chrome_options.binary_location = "/usr/bin/google-chrome"

prefs = {'download.default_directory': tmp_dir,}
chrome_options.add_experimental_option("prefs", prefs)

with Display(backend="xvfb",size=(1920,1080),color_depth=24) as disp:

    driver = webdriver.Chrome(options=chrome_options, executable_path=driver_path)
    driver.get(url)

最后一切正常,并将下载文件放在 tmp 文件夹中。

解决方案 12:

我终于通过升级到 Chromium 90 让它正常工作了!我之前使用的是 72-78 版本,但我发现它最近已修复: https ://bugs.chromium.org/p/chromium/issues/detail ?id=696481 所以我决定试一试。

因此,在升级之后,这花了一段时间(MacOS 中的 home brew 太慢了......),我只是做了一些操作,没有设置选项或任何东西(这是一个 JavaScript 示例):

await driver.findElement(By.className('download')).click();

成功了!我在一直想下载的同一个工作文件夹中看到了下载的 PDF...

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   997  
  在项目管理领域,CDCP(Certified Data Center Professional)认证评审是一个至关重要的环节,它不仅验证了项目团队的专业能力,还直接关系到项目的成功与否。在这一评审过程中,沟通技巧的运用至关重要。有效的沟通不仅能够确保信息的准确传递,还能增强团队协作,提升评审效率。本文将深入探讨CDCP...
华为IPD流程   34  
  IPD(Integrated Product Development,集成产品开发)是一种以客户需求为核心、跨部门协同的产品开发模式,旨在通过高效的资源整合和流程优化,提升产品开发的成功率和市场竞争力。在IPD培训课程中,掌握关键成功因素是确保团队能够有效实施这一模式的核心。以下将从五个关键成功因素展开讨论,帮助企业和...
IPD项目流程图   40  
  华为IPD(Integrated Product Development,集成产品开发)流程是华为公司在其全球化进程中逐步构建和完善的一套高效产品开发管理体系。这一流程不仅帮助华为在技术创新和产品交付上实现了质的飞跃,还为其在全球市场中赢得了显著的竞争优势。IPD的核心在于通过跨部门协作、阶段性评审和市场需求驱动,确保...
华为IPD   39  
  华为作为全球领先的通信技术解决方案提供商,其成功的背后离不开一套成熟的管理体系——集成产品开发(IPD)。IPD不仅是一种产品开发流程,更是一种系统化的管理思想,它通过跨职能团队的协作、阶段评审机制和市场需求驱动的开发模式,帮助华为在全球市场中脱颖而出。从最初的国内市场到如今的全球化布局,华为的IPD体系在多个领域展现...
IPD管理流程   71  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用