相关文章推荐
奔放的楼房  ·  使用Google Chrome ...·  1 月前    · 
儒雅的针织衫  ·  python 报 ...·  1 月前    · 
八块腹肌的单杠  ·  jquery select 绑定 ...·  1 年前    · 

用chrome headless和selenium进行下载

71 人关注

我正在使用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
prefs = {"download.default_directory" : "/Users/Chetan/Desktop/"}
chromeOptions.add_argument("headless")
chromeOptions.add_experimental_option("prefs",prefs)

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

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

5 个评论
我也试过使用 submit 和发送 Keys.ENTER 。它对普通浏览器有效,但对无头浏览器无效。
你希望只用chrome来完成吗?还是firefox也可以?
首选chrome或phantomjs
为什么不直接使用urllib来下载文件呢?点击文件来模拟下载只能算作一些用户的情况。我使用过的浏览器在开始下载之前会打开一个 "另存为 "窗口。如果你点击查看它是否存在于服务器上,或者验证文件的内容,urllib可能是你最好的选择。
@TehTris 问题是,我是在另一个需要我提前登录的网站上做的。它同时设置了头信息和cookies,所以我需要在使用它之前设置这两者。但只使用js,似乎没有办法从客户端获得请求头信息......。所以我不能使用urlllib
python
google-chrome
selenium
google-chrome-headless
TheChetan
TheChetan
发布于 2017-08-11
11 个回答
Shawn Button
Shawn Button
发布于 2021-04-18
已采纳
0 人赞同

是的,这是一个 "功能",为了安全。如前所述,这里是错误讨论。 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)

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

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

我试过这个方法,但对我不起作用 :( 当我完全像这样尝试时,我什么也得不到,而当我只是关闭 "无头 "模式时,我得到了文件,但随后Chrome崩溃了。如果我把这个答案中的代码和无头模式一起完全删除,Chrome就能像预期的那样工作。我猜Chrome的API已经改变了?
@比特流 它对我来说是在 Chromium 68.0.3440.75 & chromedriver 2.38 , 查看我的完整例子
@shawn-button 如何下载视频......似乎HTML5视频默认在chrome上播放
你说,在Chrome 62.0.3196.0或以上版本中增加了支持,以实现下载。但我目前使用的是Chrome 71,但它在那里也不工作。需要遵循同样的解决方法。
这是否仍然是最新的?我试了一下github上的方法,它没有下载文件。我测试了该代码在非无头模式下可以下载文件,打印结果显示:来自浏览器的响应:结果:值:无
Fayçal
Fayçal
发布于 2021-04-18
0 人赞同

下面是一个基于Python的工作实例 肖恩-巴顿的回答 . I've tested this with Chromium 68.0.3440.75 & chromedriver 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()
    
还要注意元素目标没有设置为"_blank",否则切换标签并试图下载文件将无法工作。
谢谢你的发帖。我还需要添加 chromedriver_location = "/path/to/chromedriver" ,然后在驱动定义中引用它,即 driver = webdriver.Chrome(chromedriver_location,options=chrome_options) 附注: chrome_options 参数很快就会被淘汰,并且已经被 options 参数取代,正如我在这里的小例子中所展示的那样。
Some1Else
Some1Else
发布于 2021-04-18
0 人赞同

这是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();

这就是有人在上述主题中给出的解决方案。Here is his comment.

这个解决方案需要给Chrome浏览器打补丁,这不是一个变通的办法。命令 Browser.setDownloadBehavior not present in Chrome v62.0.3186.0.
几个月前我也跳进了同样的问题。直到今天才找到任何解决方案,感谢一位老兄评论了我的问题并把我引到这里。阅读这个答案让我很高兴,但我真的不知道如何在我的源代码中复制或改编这段代码。
@TheChetan 谢谢!有趣的链接,虽然我是用java开发的, chromePrefs.put("Browser.setDownloadBehavior", "allow"); 会有更多的帮助,如果这个字符串是真实的,并且可以工作的话。 )。
How would you do it in Python with selenium?
@Nihvel 你能在Java中解决这个问题吗? 你能公布解决方案吗?
gannagainz
gannagainz
发布于 2021-04-18
0 人赞同

更新的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\to\Downloads"} # (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()
    
这应该是公认的答案,只在chrome_prefs中添加了下载路径为experimental_options,就做到了,谢谢!
Hazem
Hazem
发布于 2021-04-18
0 人赞同

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

在我得到这个页面并进行 driver.get_screenshot_as_file('foo.png') 后,我得到了一个实际的图像,它看起来还不错。而且,驱动程序能够找到这个按钮。正在调查这个问题。
victorvartan
victorvartan
发布于 2021-04-18
0 人赞同

通常情况下,看到同样的东西用另一种语言写出来是多余的,但因为这个问题把我逼疯了,我希望我可以把别人从痛苦中拯救出来......所以这里是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);
    
Mykhailo
Mykhailo
发布于 2021-04-18
0 人赞同

一个使用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);

Tested with:

  • Chrome 67.0.3396.99
  • Chromedriver 2.36.540469
  • selenium-cucumber-js 1.5.12
  • selenium-webdriver 3.0.0
  • 谢谢你发布的JavaScript解决方案。如何执行该命令并不完全明显。
    Manasi Vora
    Manasi Vora
    发布于 2021-04-18
    0 人赞同

    以下是在Java、selenium、chromedriver和chrome v 71.x中的等效代码,其中的代码是允许保存下载的关键 额外的罐子:com.fasterxml.jackson.core,com.fasterxml.jackson.annotation,com.fasterxml.jackson.databind

    System.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();
        
    Matheus Araujo
    Matheus Araujo
    发布于 2021-04-18
    0 人赞同

    我通过使用@Shawn Button分享的变通方法和使用 完整路径 为 "downloadPath "参数。使用一个 相对路径 没有工作,给我带来了错误。

    Versions:
    Chrome版本75.0.3770.100(官方版本)(32位)
    ChromeDriver 75.0.3770.90

    请写出你的chrome和chrome驱动版本。每个版本都在做重大改变,解决方法可能是无用的。比如说 bugs.chromium.org/p/chromium/issues/detail?id=696481#c198
    Jorge Mendes
    Jorge Mendes
    发布于 2021-04-18
    0 人赞同

    Using: google-chrome-stable amd64 86.0.4240.111-1 , chromedriver 86.0.4240.22 , selenium 3.141.0 python 3.8.3

    尝试了多种建议的解决方案,没有任何东西真正对chrome headless起作用,同时我的测试网站打开了一个新的空白标签,然后数据被下载。

    最后放弃了无头,实施了 视觉效果 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)
    

    最后,一切都成功了,并且在临时文件夹上有了下载文件。

    Jason
    Jason
    发布于 2021-04-18
    0 人赞同