Headless Chrome 入门
创始人
2024-03-01 20:30:20
0

摘要

在 Chrome 59 中开始搭载 Headless Chrome。这是一种在 无需显示 headless 的环境下运行 Chrome 浏览器的方式。从本质上来说,就是不用 chrome 浏览器来运行 Chrome 的功能!它将 Chromium 和 Blink 渲染引擎提供的所有现代 Web 平台的功能都带入了命令行。

它有什么用?

无需显示 headless 的浏览器对于自动化测试和不需要可视化 UI 界面的服务器环境是一个很好的工具。例如,你可能需要对真实的网页运行一些测试,创建一个 PDF,或者只是检查浏览器如何呈现 URL。

注意: Mac 和 Linux 上的 Chrome 59 都可以运行无需显示模式。对 Windows 的支持将在 Chrome 60 中提供。要检查你使用的 Chrome 版本,请在浏览器中打开 chrome://version

开启 无需显示 headless 模式(命令行界面)

开启 无需显示 headless 模式最简单的方法是从命令行打开 Chrome 二进制文件。如果你已经安装了 Chrome 59 以上的版本,请使用 --headless 标志启动 Chrome:

chrome \
  --headless \                   # Runs Chrome in headless mode.
  --disable-gpu \                # Temporarily needed for now.
  --remote-debugging-port=9222 \
  https://www.chromestatus.com   # URL to open. Defaults to about:blank.

**注意:**目前你仍然需要使用 --disable-gpu 标志。但它最终会不需要的。

chrome 二进制文件应该指向你安装 Chrome 的位置。确切的位置会因平台差异而不同。当前我在 Mac 上操作,所以我为安装的每个版本的 Chrome 都创建了方便使用的别名。

如果您使用 Chrome 的稳定版,并且无法获得测试版,我建议您使用 chrome-canary 版本:

alias chrome="/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome"
alias chrome-canary="/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary"
alias chromium="/Applications/Chromium.app/Contents/MacOS/Chromium"

这里下载 Chrome Cannary。

命令行的功能

在某些情况下,你可能不需要以脚本编程的方式操作 Headless Chrome。可以使用一些有用的命令行标志来执行常见的任务。

打印 DOM

--dump-dom 标志将打印 document.body.innerHTML 到标准输出:

chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/

创建一个 PDF

--print-to-pdf 标志将页面转出为 PDF 文件:

chrome --headless --disable-gpu --print-to-pdf https://www.chromestatus.com/

截图

要捕获页面的屏幕截图,请使用 --screenshot 标志:

chrome --headless --disable-gpu --screenshot https://www.chromestatus.com/

# Size of a standard letterhead.
chrome --headless --disable-gpu --screenshot --window-size=1280,1696 https://www.chromestatus.com/

# Nexus 5x
chrome --headless --disable-gpu --screenshot --window-size=412,732 https://www.chromestatus.com/

使用 --screenshot 标志运行 Headless Chrome 将在当前工作目录中生成一个名为 screenshot.png 的文件。如果你正在寻求整个页面的截图,那么会涉及到很多事情。来自 David Schnurr 的一篇很棒的博文已经介绍了这一内容。请查看 使用 headless Chrome 作为自动截屏工具

REPL 模式 (read-eval-print loop)

--repl 标志可以使 Headless Chrome 运行在一个你可以使用浏览器评估 JS 表达式的模式下。执行下面的命令:

$ chrome --headless --disable-gpu --repl https://www.chromestatus.com/
[0608/112805.245285:INFO:headless_shell.cc(278)] Type a Javascript expression to evaluate or "quit" to exit.
>>> location.href
{"result":{"type":"string","value":"https://www.chromestatus.com/features"}}
>>> quit

在没有浏览器界面的情况下调试 Chrome

当你使用 --remote-debugging-port=9222 运行 Chrome 时,它会启动一个支持 DevTools 协议的实例。该协议用于与 Chrome 进行通信,并且驱动 Headless Chrome 浏览器实例。它也是一个类似 Sublime、VS Code 和 Node 的工具,可用于应用程序的远程调试。#协同效应

由于你没有浏览器用户界面可用来查看网页,请在另一个浏览器中输入 http://localhost:9222,以检查一切是否正常。你将会看到一个 可检查的 inspectable 页面的列表,可以点击它们来查看 Headless Chrome 正在呈现的内容:

DevTools 远程调试界面

从这里,你就可以像往常一样使用熟悉的 DevTools 来检查、调试和调整页面了。如果你以编程方式使用 Headless Chrome,这个页面也是一个功能强大的调试工具,用于查看所有通过网络与浏览器交互的原始 DevTools 协议命令。

使用编程模式 (Node)

Puppeteer 库 API

Puppeteer 是一个由 Chrome 团队开发的 Node 库。它提供了一个高层次的 API 来控制无需显示版(或 完全版)的 Chrome。它与其他自动化测试库,如 Phantom 和 NightmareJS 相类似,但是只适用于最新版本的 Chrome。

除此之外,Puppeteer 还可用于轻松截取屏幕截图,创建 PDF,页面间导航以及获取有关这些页面的信息。如果你想快速地自动化进行浏览器测试,我建议使用该库。它隐藏了 DevTools 协议的复杂性,并可以处理诸如启动 Chrome 调试实例等繁冗的任务。

安装:

yarn add puppeteer

例子 - 打印用户代理:

const puppeteer = require('puppeteer');

(async() => {
  const browser = await puppeteer.launch();
  console.log(await browser.version());
  browser.close();
})();

例子 - 获取页面的屏幕截图:

const puppeteer = require('puppeteer');

(async() => {

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://www.chromestatus.com', {waitUntil: 'networkidle'});
await page.pdf({path: 'page.pdf', format: 'A4'});

browser.close();
})();

查看 Puppeteer 的文档,了解完整 API 的更多信息。

CRI 库

chrome-remote-interface 是一个比 Puppeteer API 更低层次的库。如果你想要更接近原始信息和更直接地使用 DevTools 协议的话,我推荐使用它。

启动 Chrome

chrome-remote-interface 不会为你启动 Chrome,所以你要自己启动它。

在前面的 CLI 章节中,我们使用 --headless --remote-debugging-port=9222 手动启动了 Chrome。但是,要想做到完全自动化测试,你可能希望从你的应用程序中启动 Chrome。

其中一种方法是使用 child_process

const execFile = require('child_process').execFile;

function launchHeadlessChrome(url, callback) {
  // Assuming MacOSx.
  const CHROME = '/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome';
  execFile(CHROME, ['--headless', '--disable-gpu', '--remote-debugging-port=9222', url], callback);
}

launchHeadlessChrome('https://www.chromestatus.com', (err, stdout, stderr) => {
  ...
});

但是如果你想要在多个平台上运行可移植的解决方案,事情会变得很棘手。请注意 Chrome 的硬编码路径:

使用 ChromeLauncher

Lighthouse 是一个令人称奇的网络应用的质量测试工具。Lighthouse 内部开发了一个强大的用于启动 Chrome 的模块,现在已经被提取出来单独使用。chrome-launcher NPM 模块 可以找到 Chrome 的安装位置,设置调试实例,启动浏览器和在程序运行完之后将其杀死。它最好的一点是可以跨平台工作,感谢 Node!

默认情况下,chrome-launcher 会尝试启动 Chrome Canary(如果已经安装),但是你也可以更改它,手动选择使用的 Chrome 版本。要想使用它,首先从 npm 安装:

yarn add chrome-launcher

例子 - 使用 chrome-launcher 启动 Headless Chrome:

const chromeLauncher = require('chrome-launcher');

// Optional: set logging level of launcher to see its output.
// Install it using: yarn add lighthouse-logger
// const log = require('lighthouse-logger');
// log.setLevel('info');

/**
 * Launches a debugging instance of Chrome.
 * @param {boolean=} headless True (default) launches Chrome in headless mode.
 *     False launches a full version of Chrome.
 * @return {Promise}
 */
function launchChrome(headless=true) {
  return chromeLauncher.launch({
    // port: 9222, // Uncomment to force a specific port of your choice.
    chromeFlags: [
      '--window-size=412,732',
      '--disable-gpu',
      headless ? '--headless' : ''
    ]
  });
}

launchChrome().then(chrome => {
  console.log(`Chrome debuggable on port: ${chrome.port}`);
  ...
  // chrome.kill();
});

运行这个脚本没有做太多的事情,但你应该能在任务管理器中看到启动了一个 Chrome 的实例,它加载了页面 about:blank。记住,它不会有任何的浏览器界面,我们是无需显示的。

为了控制浏览器,我们需要 DevTools 协议!

检索有关页面的信息

警告: DevTools 协议可以做一些有趣的事情,但是起初可能有点令人生畏。我建议先花点时间浏览 DevTools 协议查看器。然后,转到 chrome-remote-interface 的 API 文档,看看它是如何包装原始协议的。

我们来安装该库:

yarn add chrome-remote-interface

例子 - 打印用户代理:

const CDP = require('chrome-remote-interface');

...

launchChrome().then(async chrome => {
  const version = await CDP.Version({port: chrome.port});
  console.log(version['User-Agent']);
});

结果是类似这样的东西:HeadlessChrome/60.0.3082.0

例子 - 检查网站是否有 Web 应用程序清单

const CDP = require('chrome-remote-interface');

...

(async function() {

const chrome = await launchChrome();
const protocol = await CDP({port: chrome.port});

// Extract the DevTools protocol domains we need and enable them.
// See API docs: https://chromedevtools.github.io/devtools-protocol/
const {Page} = protocol;
await Page.enable();

Page.navigate({url: 'https://www.chromestatus.com/'});

// Wait for window.onload before doing stuff.
Page.loadEventFired(async () => {
  const manifest = await Page.getAppManifest();

  if (manifest.url) {
    console.log('Manifest: ' + manifest.url);
    console.log(manifest.data);
  } else {
    console.log('Site has no app manifest');
  }

  protocol.close();
  chrome.kill(); // Kill Chrome.
});

})();

例子 - 使用 DOM API 提取页面的 </code>:</p><pre tabindex=0><code>const CDP = require('chrome-remote-interface'); ... (async function() { const chrome = await launchChrome(); const protocol = await CDP({port: chrome.port}); // Extract the DevTools protocol domains we need and enable them. // See API docs: https://chromedevtools.github.io/devtools-protocol/ const {Page, Runtime} = protocol; await Promise.all([Page.enable(), Runtime.enable()]); Page.navigate({url: 'https://www.chromestatus.com/'}); // Wait for window.onload before doing stuff. Page.loadEventFired(async () => { const js = "document.querySelector('title').textContent"; // Evaluate the JS expression in the page. const result = await Runtime.evaluate({expression: js}); console.log('Title of page: ' + result.result.value); protocol.close(); chrome.kill(); // Kill Chrome. }); })(); </code></pre><h3 id=使用-seleniumwebdriver-和-chromedriver>使用 Selenium、WebDriver 和 ChromeDriver</h3><p>现在,Selenium 开启了 Chrome 的完整实例。换句话说,这是一个自动化的解决方案,但不是完全无需显示的。但是,Selenium 只需要进行小小的配置即可运行 Headless Chrome。如果你想要关于如何自己设置的完整说明,我建议你阅读“<a href=https://intoli.com/blog/running-selenium-with-headless-chrome/>使用 Headless Chrome 来运行 Selenium</a>”,不过你可以从下面的一些示例开始。</p><h4 id=使用-chromedriver>使用 ChromeDriver</h4><p><a href=https://sites.google.com/a/chromium.org/chromedriver/>ChromeDriver</a> 2.3.0 支持 Chrome 59 及更新版本,可与 Headless Chrome 配合使用。在某些情况下,你可能需要等到 Chrome 60 以解决 bug。例如,Chrome 59 中屏幕截图已知存在问题。</p><p>安装:</p><pre tabindex=0><code>yarn add selenium-webdriver chromedriver </code></pre><p>例子:</p><pre tabindex=0><code>const fs = require('fs'); const webdriver = require('selenium-webdriver'); const chromedriver = require('chromedriver'); // This should be the path to your Canary installation. // I'm assuming Mac for the example. const PATH_TO_CANARY = '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'; const chromeCapabilities = webdriver.Capabilities.chrome(); chromeCapabilities.set('chromeOptions', { binary: PATH_TO_CANARY // Screenshots require Chrome 60\. Force Canary. 'args': [ '--headless', ] }); const driver = new webdriver.Builder() .forBrowser('chrome') .withCapabilities(chromeCapabilities) .build(); // Navigate to google.com, enter a search. driver.get('https://www.google.com/'); driver.findElement({name: 'q'}).sendKeys('webdriver'); driver.findElement({name: 'btnG'}).click(); driver.wait(webdriver.until.titleIs('webdriver - Google Search'), 1000); // Take screenshot of results page. Save to disk. driver.takeScreenshot().then(base64png => { fs.writeFileSync('screenshot.png', new Buffer(base64png, 'base64')); }); driver.quit(); </code></pre><h4 id=使用-webdriverio>使用 WebDriverIO</h4><p><a href=http://webdriver.io/>WebDriverIO</a> 是一个在 Selenium WebDrive 上构建的更高层次的 API。</p><p>安装:</p><pre tabindex=0><code>yarn add webdriverio chromedriver </code></pre><p>例子:过滤 chromestatus.com 上的 CSS 功能:</p><pre tabindex=0><code>const webdriverio = require('webdriverio'); const chromedriver = require('chromedriver'); // This should be the path to your Canary installation. // I'm assuming Mac for the example. const PATH_TO_CANARY = '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'; const PORT = 9515; chromedriver.start([ '--url-base=wd/hub', `--port=${PORT}`, '--verbose' ]); (async () => { const opts = { port: PORT, desiredCapabilities: { browserName: 'chrome', chromeOptions: { binary: PATH_TO_CANARY // Screenshots require Chrome 60\. Force Canary. args: ['--headless'] } } }; const browser = webdriverio.remote(opts).init(); await browser.url('https://www.chromestatus.com/features'); const title = await browser.getTitle(); console.log(`Title: ${title}`); await browser.waitForText('.num-features', 3000); let numFeatures = await browser.getText('.num-features'); console.log(`Chrome has ${numFeatures} total features`); await browser.setValue('input[type="search"]', 'CSS'); console.log('Filtering features...'); await browser.pause(1000); numFeatures = await browser.getText('.num-features'); console.log(`Chrome has ${numFeatures} CSS features`); const buffer = await browser.saveScreenshot('screenshot.png'); console.log('Saved screenshot...'); chromedriver.stop(); browser.end(); })(); </code></pre><h3 id=更多资源>更多资源</h3><p>以下是一些可以带你入门的有用资源:</p><p>文档</p><ul><li><a href=https://chromedevtools.github.io/devtools-protocol/>DevTools Protocol Viewer</a> - API 参考文档</li></ul><p>工具</p><ul><li><a href=https://www.npmjs.com/package/chrome-remote-interface>chrome-remote-interface</a> - 基于 DevTools 协议的 node 模块</li><li><a href=https://github.com/GoogleChrome/lighthouse>Lighthouse</a> - 测试 Web 应用程序质量的自动化工具;大量使用了协议</li><li><a href=https://github.com/GoogleChrome/lighthouse/tree/master/chrome-launcher>chrome-launcher</a> - 用于启动 Chrome 的 node 模块,可以自动化</li></ul><p>样例</p><ul><li>“<a href=https://paul.kinlan.me/the-headless-web/>The Headless Web</a>” - Paul Kinlan 发布的使用了 Headless 和 api.ai 的精彩博客</li></ul><h3 id=常见问题>常见问题</h3><p><strong>我需要 <code>--disable-gpu</code> 标志吗?</strong></p><p>目前是需要的。<code>--disable-gpu</code> 标志在处理一些 bug 时是需要的。在未来版本的 Chrome 中就不需要了。查看 <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=546953">https://crbug.com/546953#c152</a> 和 <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=695212">https://crbug.com/695212</a> 获取更多信息。</p><p><strong>所以我仍然需要 Xvfb 吗?</strong></p><p>不。Headless Chrome 不使用窗口,所以不需要像 Xvfb 这样的显示服务器。没有它你也可以愉快地运行你的自动化测试。</p><p>什么是 Xvfb?Xvfb 是一个用于类 Unix 系统的运行于内存之内的显示服务器,可以让你运行图形应用程序(如 Chrome),而无需附加的物理显示器。许多人使用 Xvfb 运行早期版本的 Chrome 进行 “headless” 测试。</p><p><strong>如何创建一个运行 Headless Chrome 的 Docker 容器?</strong></p><p>查看 <a href=https://github.com/ebidel/lighthouse-ci>lighthouse-ci</a>。它有一个使用 Ubuntu 作为基础镜像的 <a href=https://github.com/ebidel/lighthouse-ci/blob/master/builder/Dockerfile.headless>Dockerfile 示例</a>,并且在 App Engine Flexible 容器中安装和运行了 Lighthouse。</p><p><strong>我可以把它和 Selenium / WebDriver / ChromeDriver 一起使用吗?</strong></p><p>是的。查看 <a href=https://developers.google.com/web/updates/2017/04/headless-chrome>Using Selenium, WebDrive, or ChromeDriver</a>。</p><p><strong>它和 PhantomJS 有什么关系?</strong></p><p>Headless Chrome 和 <a href=http://phantomjs.org/>PhantomJS</a> 是类似的工具。它们都可以用来在无需显示的环境中进行自动化测试。两者的主要不同在于 Phantom 使用了一个较老版本的 WebKit 作为它的渲染引擎,而 Headless Chrome 使用了最新版本的 Blink。</p><p>目前,Phantom 提供了比 <a href=https://chromedevtools.github.io/devtools-protocol/>DevTools protocol</a> 更高层次的 API。</p><p><strong>我在哪儿提交 bug?</strong></p><p>对于 Headless Chrome 的 bug,请提交到 <a href="https://bugs.chromium.org/p/chromium/issues/entry?components=Blink&blocking=705916&cc=skyostil%40chromium.org&Proj=Headless">crbug.com</a>。</p><p>对于 DevTools 协议的 bug,请提交到 <a href=https://github.com/ChromeDevTools/devtools-protocol/issues/new>github.com/ChromeDevTools/devtools-protocol</a>。</p><hr><p>作者简介</p><p><a href=https://developers.google.com/web/resources/contributors>Eric Bidelman</a> 谷歌工程师,Lighthouse 开发,Web 和 Web 组件开发,Chrome 开发</p><hr><p>via: <a href=https://developers.google.com/web/updates/2017/04/headless-chrome>https://developers.google.com/web/updates/2017/04/headless-chrome</a></p><p>作者:<a href=https://developers.google.com/web/resources/contributors>Eric Bidelman</a> 译者:<a href=https://github.com/firmianay>firmianay</a> 校对:<a href=https://github.com/wxy>wxy</a></p><p>本文由 <a href=https://github.com/LCTT/TranslateProject>LCTT</a> 原创编译,<a href=https://linux.cn/>Linux中国</a> 荣誉推出</p> <!--end::Text--> </div> <!--end::Description--> <div class="mt-5"> <!--关键词搜索--> <a href="/index.php?s=news&c=search&keyword=%E6%B5%8F%E8%A7%88%E5%99%A8" class="badge badge-light-primary fw-bold my-2" target="_blank">浏览器</a> <a href="/index.php?s=news&c=search&keyword=Chrome" class="badge badge-light-primary fw-bold my-2" target="_blank">Chrome</a> <a href="/index.php?s=news&c=search&keyword=Headless" class="badge badge-light-primary fw-bold my-2" target="_blank">Headless</a> </div> <div class="mt-5"> <p class="fc-show-prev-next"> <strong>上一篇:</strong><a href="/linuxzg/3433.html">一个开源软件许可证合规的经济高效模式</a><br> </p> <p class="fc-show-prev-next"> <strong>下一篇:</strong><a href="/linuxzg/3435.html">ImageMagick 入门:使用命令行来编辑图片</a> </p> </div> <!--begin::Block--> <div class="d-flex flex-stack mb-2 mt-10"> <!--begin::Title--> <h3 class="text-dark fs-5 fw-bold text-gray-800">相关内容</h3> <!--end::Title--> </div> <div class="separator separator-dashed mb-9"></div> <!--end::Block--> <div class="row g-10"> <!--begin::Col--> <div class="col-md-4"> <!--begin::Feature post--> <div class="card-xl-stretch me-md-6"> <!--begin::Image--> <a class="d-block bgi-no-repeat bgi-size-cover bgi-position-center card-rounded position-relative min-h-175px mb-5" style="background-image:url('/static/assets/images/nopic.gif')" href="/news/203281.html"> </a> <!--end::Image--> <!--begin::Body--> <div class="m-0"> <!--begin::Title--> <a href="/news/203281.html" class="fs-5 text-dark fw-bold text-hover-primary text-dark lh-base">张雪峰退网!AI填报志愿哪...</a> <!--end::Title--> <!--begin::Text--> <div class="fw-semibold fs-8 text-gray-600 text-dark my-2">高考很重要,选对学校和专业也很重要。 前段时间,张雪峰老师在直播时...</div> <!--end::Text--> <!--begin::Content--> <div class="fs-6 fw-bold"> <!--begin::Date--> <span class="text-muted">2025-06-07 22:43:32</span> <!--end::Date--> </div> <!--end::Content--> </div> <!--end::Body--> </div> <!--end::Feature post--> </div> <!--end::Col--> <!--begin::Col--> <div class="col-md-4"> <!--begin::Feature post--> <div class="card-xl-stretch me-md-6"> <!--begin::Image--> <a class="d-block bgi-no-repeat bgi-size-cover bgi-position-center card-rounded position-relative min-h-175px mb-5" style="background-image:url('/uploadfile/202505/5aba3dc5c5f7535.png')" href="/code/202713.html"> </a> <!--end::Image--> <!--begin::Body--> <div class="m-0"> <!--begin::Title--> <a href="/code/202713.html" class="fs-5 text-dark fw-bold text-hover-primary text-dark lh-base">解决win10任何程序打开...</a> <!--end::Title--> <!--begin::Text--> <div class="fw-semibold fs-8 text-gray-600 text-dark my-2">文章目录一、问题与修改原因1、着手修改吧2、弯路上探索3、发现祸根...</div> <!--end::Text--> <!--begin::Content--> <div class="fs-6 fw-bold"> <!--begin::Date--> <span class="text-muted">2025-05-31 06:59:12</span> <!--end::Date--> </div> <!--end::Content--> </div> <!--end::Body--> </div> <!--end::Feature post--> </div> <!--end::Col--> <!--begin::Col--> <div class="col-md-4"> <!--begin::Feature post--> <div class="card-xl-stretch me-md-6"> <!--begin::Image--> <a class="d-block bgi-no-repeat bgi-size-cover bgi-position-center card-rounded position-relative min-h-175px mb-5" style="background-image:url('/uploadfile/202505/e39e900ead96d48.png')" href="/code/201941.html"> </a> <!--end::Image--> <!--begin::Body--> <div class="m-0"> <!--begin::Title--> <a href="/code/201941.html" class="fs-5 text-dark fw-bold text-hover-primary text-dark lh-base">Chrome 浏览器获取网...</a> <!--end::Title--> <!--begin::Text--> <div class="fw-semibold fs-8 text-gray-600 text-dark my-2">解析阶段详细流程说明 步骤说明①浏览器输入:http...</div> <!--end::Text--> <!--begin::Content--> <div class="fs-6 fw-bold"> <!--begin::Date--> <span class="text-muted">2025-05-28 07:01:35</span> <!--end::Date--> </div> <!--end::Content--> </div> <!--end::Body--> </div> <!--end::Feature post--> </div> <!--end::Col--> <!--begin::Col--> <div class="col-md-4"> <!--begin::Feature post--> <div class="card-xl-stretch me-md-6"> <!--begin::Image--> <a class="d-block bgi-no-repeat bgi-size-cover bgi-position-center card-rounded position-relative min-h-175px mb-5" style="background-image:url('/static/assets/images/nopic.gif')" href="/news/201865.html"> </a> <!--end::Image--> <!--begin::Body--> <div class="m-0"> <!--begin::Title--> <a href="/news/201865.html" class="fs-5 text-dark fw-bold text-hover-primary text-dark lh-base">微软更新 Edge 136...</a> <!--end::Title--> <!--begin::Text--> <div class="fw-semibold fs-8 text-gray-600 text-dark my-2">IT之家 5 月 27 日消息,微软公司昨日(5 月 26 日)更...</div> <!--end::Text--> <!--begin::Content--> <div class="fs-6 fw-bold"> <!--begin::Date--> <span class="text-muted">2025-05-27 09:48:13</span> <!--end::Date--> </div> <!--end::Content--> </div> <!--end::Body--> </div> <!--end::Feature post--> </div> <!--end::Col--> <!--begin::Col--> <div class="col-md-4"> <!--begin::Feature post--> <div class="card-xl-stretch me-md-6"> <!--begin::Image--> <a class="d-block bgi-no-repeat bgi-size-cover bgi-position-center card-rounded position-relative min-h-175px mb-5" style="background-image:url('/static/assets/images/nopic.gif')" href="/news/201861.html"> </a> <!--end::Image--> <!--begin::Body--> <div class="m-0"> <!--begin::Title--> <a href="/news/201861.html" class="fs-5 text-dark fw-bold text-hover-primary text-dark lh-base">微软开源浏览器Agent,...</a> <!--end::Title--> <!--begin::Text--> <div class="fw-semibold fs-8 text-gray-600 text-dark my-2">微软在官网开源了一个专用于浏览器网络任务的Agent——Magen...</div> <!--end::Text--> <!--begin::Content--> <div class="fs-6 fw-bold"> <!--begin::Date--> <span class="text-muted">2025-05-27 09:20:10</span> <!--end::Date--> </div> <!--end::Content--> </div> <!--end::Body--> </div> <!--end::Feature post--> </div> <!--end::Col--> <!--begin::Col--> <div class="col-md-4"> <!--begin::Feature post--> <div class="card-xl-stretch me-md-6"> <!--begin::Image--> <a class="d-block bgi-no-repeat bgi-size-cover bgi-position-center card-rounded position-relative min-h-175px mb-5" style="background-image:url('/static/assets/images/nopic.gif')" href="/news/201788.html"> </a> <!--end::Image--> <!--begin::Body--> <div class="m-0"> <!--begin::Title--> <a href="/news/201788.html" class="fs-5 text-dark fw-bold text-hover-primary text-dark lh-base">Norton Neo浏览器...</a> <!--end::Title--> <!--begin::Text--> <div class="fw-semibold fs-8 text-gray-600 text-dark my-2">IT之家 5 月 24 日消息,安全公司诺顿(Norton)于 5...</div> <!--end::Text--> <!--begin::Content--> <div class="fs-6 fw-bold"> <!--begin::Date--> <span class="text-muted">2025-05-24 18:48:35</span> <!--end::Date--> </div> <!--end::Content--> </div> <!--end::Body--> </div> <!--end::Feature post--> </div> <!--end::Col--> </div> </div> <!--end::Table widget 14--> </div> <!--end::Col--> <!--begin::Col--> <div class="col-xl-4 mt-0"> <!--begin::Chart Widget 35--> <div class="card card-flush h-md-100"> <!--begin::Header--> <div class="card-header pt-5 "> <!--begin::Title--> <h3 class="card-title align-items-start flex-column"> <!--begin::Statistics--> <div class="d-flex align-items-center mb-2"> <!--begin::Currency--> <span class="fs-5 fw-bold text-gray-800 ">热门资讯</span> <!--end::Currency--> </div> <!--end::Statistics--> </h3> <!--end::Title--> </div> <!--end::Header--> <!--begin::Body--> <div class="card-body pt-3"> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/uploadfile/202403/6f2453cdd7aedac.jpg')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/linuxzg/7373.html" class="text-dark fw-bold text-hover-primary fs-6">Helix:高级 Linux ...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">说到 基于终端的文本编辑器,通常 Vim、Emacs 和 Nano 受到了关注。这并不意味着没有其他...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/uploadfile/202403/6653176a967ec37.jpg')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/linuxzg/6066.html" class="text-dark fw-bold text-hover-primary fs-6">使用 KRAWL 扫描 Kub...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">用 KRAWL 脚本来识别 Kubernetes Pod 和容器中的错误。当你使用 Kubernet...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/uploadfile/202403/6b84b0eb17d5.jpg')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/linuxzg/2407.html" class="text-dark fw-bold text-hover-primary fs-6">JStock:Linux 上不...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">如果你在股票市场做投资,那么你可能非常清楚投资组合管理计划有多重要。管理投资组合的目标是依据你能承受...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/uploadfile/202403/a087872bfb56076.jpg')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/linuxzg/1970.html" class="text-dark fw-bold text-hover-primary fs-6">通过 SaltStack 管理...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">我在搜索Puppet的替代品时,偶然间碰到了Salt。我喜欢puppet,但是我又爱上Salt了:)...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/uploadfile/202403/1dcb7ec3ebb375.jpg')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/linuxzg/8236.html" class="text-dark fw-bold text-hover-primary fs-6">Epic 游戏商店现在可在 S...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">现在可以在 Steam Deck 上运行 Epic 游戏商店了,几乎无懈可击! 但是,它是非官方的。...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/uploadfile/202403/87b91661b9957e2.jpg')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/linuxzg/8209.html" class="text-dark fw-bold text-hover-primary fs-6">《Apex 英雄》正式可在 S...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">《Apex 英雄》现已通过 Steam Deck 验证,这使其成为支持 Linux 的顶级多人游戏之...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/uploadfile/202403/8b4bf800f4b46.jpg')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/linuxzg/5564.html" class="text-dark fw-bold text-hover-primary fs-6">如何在 Github 上创建一...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">学习如何复刻一个仓库,进行更改,并要求维护人员审查并合并它。你知道如何使用 git 了,你有一个 G...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/uploadfile/202403/d336c115795669a.jpg')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/linuxzg/10392.html" class="text-dark fw-bold text-hover-primary fs-6">2024 开年,LLUG 和你...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">Hi,Linuxer,2024 新年伊始,不知道你是否已经准备好迎接新的一年~ 2024 年,Lin...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/uploadfile/202403/1401cc042d7e7.jpg')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/linuxzg/9858.html" class="text-dark fw-bold text-hover-primary fs-6">什么是 KDE Connect...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">什么是 KDE Connect?它的主要特性是什么?它应该如何安装?本文提供了基本的使用指南。科技日...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/uploadfile/202403/2c5ae0168df47b1.jpg')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/linuxzg/2168.html" class="text-dark fw-bold text-hover-primary fs-6">Opera 浏览器内置的 VP...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">昨天我们报道过 Opera 浏览器内置了 VPN 服务,用户打开它可以防止他们的在线活动被窥视。不过...</span> </div> <!--end::Title--> </div> </div> <!--end::Body--> </div> <!--end::Chart Widget 35--> </div> <!--end::Col--> </div> </div> <!--end::Content container--> </div> <!--end::Content--> </div> <!--end::Content wrapper--> <!--begin::Footer--> <div id="kt_app_footer" class="app-footer"> <!--begin::Footer container--> <div class="app-container container-xxl d-flex flex-column flex-md-row flex-center flex-md-stack py-3"> <!--begin::Copyright--> <div class="text-dark order-2 order-md-1"> <span class="text-muted fw-semibold me-1">2025 ©</span> <a href="/" target="_blank" class="text-gray-800 text-hover-primary">linux办公网</a> </div> <!--end::Copyright--> <!--begin::Menu--> <ul class="menu menu-gray-600 menu-hover-primary fw-semibold order-1"> <li class="menu-item"> <a href="/news/" target="_blank" class="menu-link px-2">linux资讯</a> </li> <li class="menu-item"> <a href="/yingyong/" target="_blank" class="menu-link px-2">linux应用</a> </li> <li class="menu-item"> <a href="/code/" target="_blank" class="menu-link px-2">编程开发</a> </li> <li class="menu-item"> <a href="/linuxzg/" target="_blank" class="menu-link px-2">Linux中国 </a> </li> </ul> <!--end::Menu--> </div> <!--end::Footer container--> </div> <!--end::Footer--> </div> <!--end:::Main--> </div> <!--end::Wrapper--> </div> <!--end::Page--> </div> <!--end::App--> <div id="kt_scrolltop" class="scrolltop" data-kt-scrolltop="true"> <!--begin::Svg Icon | path: icons/duotune/arrows/arr066.svg--> <span class="svg-icon"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <rect opacity="0.5" x="13" y="6" width="13" height="2" rx="1" transform="rotate(90 13 6)" fill="currentColor"></rect> <path d="M12.5657 8.56569L16.75 12.75C17.1642 13.1642 17.8358 13.1642 18.25 12.75C18.6642 12.3358 18.6642 11.6642 18.25 11.25L12.7071 5.70711C12.3166 5.31658 11.6834 5.31658 11.2929 5.70711L5.75 11.25C5.33579 11.6642 5.33579 12.3358 5.75 12.75C6.16421 13.1642 6.83579 13.1642 7.25 12.75L11.4343 8.56569C11.7467 8.25327 12.2533 8.25327 12.5657 8.56569Z" fill="currentColor"></path> </svg> </span> <!--end::Svg Icon--> </div> <!--begin::Javascript--> <script>var hostUrl = "/static/default/pc/";</script> <!--begin::Global Javascript Bundle(mandatory for all pages)--> <script src="/static/default/pc/plugins/global/plugins.bundle.js"></script> <script src="/static/default/pc/js/scripts.bundle.js"></script> <!--end::Global Javascript Bundle--> <!--end::Javascript--> </body> <!--end::Body--> </html>