理想的李想

最开始知道李想是在大学时候。每每溜达到中关村,一个“中学生”创办的企业屹立在微软、新东方等众多大公司、巨头之中,难免对其人其事感到好奇。后面家里换车,发现满足当时自己使用场景的产品还真的只有理想。用钱包投票其产品的同时,又再次引起了对李想的好奇。

很多人对李想的印象是“理想汽车的创始人”,但我更愿意称他为“理想的李想”。因为他在很多方面都展现了独特的思考和坚持。毕竟,行为其表是容易被模仿的,事实上,L系列取得市场认可之后,模仿者众。甚至有人调侃,李想凭一己之力,重新定义了什么才是市场认可的“新能源”。

恰逢昨晚深夜回家,回看了i8的发布会。正好看了李想主讲的前半段。虽然发布会后,股价似乎很不买单。但是,在疲劳而闷热的深夜,能让自己如白驹过隙的仔细倾听半个多小时,也是一件神奇的事情。而这种魔力的原点来自他对用户需求的理解。

李想的演讲中,郑重的阐述了他对SUV的理解。这算是正对一个长得很像MPV的i8的质疑的回应。这是一个很有意思的点。因为在我看来,李想的演讲中,最打动我的并不是他对SUV的理解,而是他对用户需求的理解。而在这个网络环境越来越噪音话的时代,很多人是不想也没有耐心看到背后这点。

用户的需求其实并不是某个天马行空想法的造物主降临。而是有很多细致而系统的全面展现,甚至是润物无声。当你习惯它的时候,你并不有所直觉,但是当你回过头来,才会发现它的存在。而这个点上,其实让我在某个时刻有了当年会看乔帮主演讲的感觉。

新能源汽车是民用制造业和科技的制高点。与“为发烧而生”不通,李想更多的是在阐述硬件和软件为产品和体验买单,典型的新时代的包豪斯思想。比如,小米的电机卷参数,而理想的自研电机卷静音。很多人觉得这可能是雕虫小技,甚至“无用”。但正如很多重大的变革,往往萌芽的时候很难就被看好。或者说,一开始的看好往往意味着本质的不看好。

而任何商业最终都要回归市场。而李想不止一次的证明了其对市场和商业的理解。比如,mega 的增配和涨价,i8 的定价策略等。很多人会觉得这是一种执迷不悟,但我更愿意称之为“不凡”。市场需要教育,但更多时候市场需要挖掘和引导。而并不是每一个企业家都有如此的洞见,跟不要说行动。

几个月前,因为限价单导致没有买入理想的股票还耿耿于怀。如今看了发布会有种很不理智的投资上的爱屋及乌。但是依然再次选择了用钱包投票。这也是自己的一次思想和行动实验。这笔单子,一年以后再见。

再议移除 macOS 中被企业策略强制安装的 Chrome 插件扩展

几年前,通过移除 macOS 中被企业策略强制安装的 Chrome 插件扩展的方法把某公司提供的安全方案的 Chrome 插件扩展移除掉了。时过境迁,如今安全软件已经全面转为自研。并且 Chrome 企业策略管理方案也有所改变,趁着周末简单记录一下。

检查策略状态

在 Chrome 地址栏输入 chrome://policy/。在我的电脑中,可以看到浏览器新增了一个 ExtensionInstallForcelist 的策略。

移除强制安装的插件

之前文章中提及的删除插件方式依然有效:Chrome 的插件安装在 ~/Library/Application Support/Google/Chrome/Default/Extensions 目录下,除去 Temp, 每个文件夹对应一个插件,把不需要的插件文件夹直接删除即可。

移除企业管理策略

/Library/Managed Preferences/ → 删除 com.google.Chrome.plist

defaults delete com.google.Chrome ExtensionInstallForcelist  # 删除用户级策略
sudo defaults delete /Library/Preferences/com.google.Chrome ExtensionInstallForcelist  # 删除全局策略

然后重启 Chrome 即可。

防止策略被重新添加

防止策略被重新添加的关键在于找出是哪个软件在添加这个策略。如果使用的设备是公司资产,请确认相关操作符合公司的安全要求。这里就不展开了。

参考资料

玩转chromedp

最近有项目需要使用无头浏览器进行后台任务处理。古早以前使用 PhantomJS 进行无头浏览器操作,但现在已经不再维护了。现在推荐使用 Chrome DevTools Protocol (CDP) 来实现无头浏览器的功能。

Chrome DevTools Protocol (CDP)

CDP 是 Chrome 浏览器提供的一个协议,允许开发者通过编程方式控制浏览器的行为。它可以用于调试、性能分析、自动化测试等场景。

CDP 的文档可以在这里找到:Chrome DevTools Protocol

Golang 中的 CDP 实现

作为一个gopher, 综合开发、调试和部署成本,决定继续选用golang chromedp 进行无头浏览器操作。这个项目比六七年前使用涨了快10倍的star, 不得不说这个项目的生命力真的很强。

这个项目符合golang项目一贯的开箱即用风格。示例也非常丰富,因此一般的测试直接找到对应示例进行修改即可。但惟独自己计划项目中需要使用的几个特性要求找不到匹配的实现。

特性要求

  • 安全隔离,需要再远程服务运行浏览器
  • 响应时效,页面打开机操作与本地打开不能有显著差异
  • 成本控制,单台服务器上需要支持多个浏览器实例运行,上下文隔离
  • 业务流程匹配,主要是需要对页面操作支持中断操作和持续执行

代码是不可能自己亲自花时间写的。借用cursor, 花了两分钟生成,两分钟调整代码结构:

package main

import (
"context"
"log"
"os"
"time"

"github.com/chromedp/cdproto/network"
"github.com/chromedp/cdproto/target"
"github.com/chromedp/chromedp"
)

const cookie = "TODO"

const REMOTE_ADDR = "ws://127.0.0.1:9222"

const REMOTE_ALLOC_CTX = true

func main() {

id, err := openBaidu()
if err != nil {
log.Fatalf("打开百度失败: %v", err)
}

search(id, "当前时间")

log.Printf("openBaidu and search success, id: %s", id)

}

func openBaidu() (target.ID, error) {
allocCtx := getAllocCtx()

// 创建一个带取消功能的上下文
ctx, _ := chromedp.NewContext(
// context.Background(),
allocCtx,
// 设置日志级别
chromedp.WithTargetID("20E9DFB7B355658007B89CC47C5BAC3A"),
)

// 截图保存路径
screenshotPath := "1.open_baidu_result.png"

// 定义截图缓冲区
var buf []byte

// 设置全局请求头,包含Cookie
// 这种方式比在每个请求上单独设置更可靠
headers := map[string]interface{}{
"Cookie": cookie,
}

// 执行任务
err := chromedp.Run(ctx,
// 首先设置全局请求头
network.SetExtraHTTPHeaders(headers),

// 导航到百度首页
chromedp.Navigate("https://www.baidu.com"),

// 等待搜索框元素加载完成
chromedp.WaitVisible("#kw", chromedp.ByID),

// 等待一下确保结果完全加载
chromedp.Sleep(1*time.Second),

// 捕获整个页面的屏幕截图
chromedp.FullScreenshot(&buf, 90),
)

if err != nil {
log.Fatalf("执行任务失败: %v", err)
return "", err
}

// 保存截图
if err := os.WriteFile(screenshotPath, buf, 0644); err != nil {
log.Fatalf("保存截图失败: %v", err)
return "", err
}

cdpCtx := chromedp.FromContext(ctx)
return cdpCtx.Target.TargetID, nil
}

func search(id target.ID, query string) {

allocCtx := getAllocCtx()

ctx, _ := chromedp.NewContext(allocCtx, chromedp.WithTargetID(id))

// 定义截图缓冲区
var buf []byte

chromedp.Run(ctx,
chromedp.SendKeys("#kw", query, chromedp.ByID),
chromedp.Click("#su", chromedp.ByID),
chromedp.WaitVisible("#content_left", chromedp.ByID),
// 捕获整个页面的屏幕截图
chromedp.Sleep(1*time.Second),
chromedp.FullScreenshot(&buf, 90),
)

// 保存截图
if err := os.WriteFile("2.search_result.png", buf, 0644); err != nil {
log.Fatalf("保存截图失败: %v", err)
}
log.Printf("保存截图到 %s\n", "search_result.png")
}

func getAllocCtx() context.Context {
if REMOTE_ALLOC_CTX {
allocCtx, _ := chromedp.NewRemoteAllocator(context.Background(), REMOTE_ADDR)
return allocCtx
} else {
opts := append(chromedp.DefaultExecAllocatorOptions[:],
chromedp.Flag("headless", false),
)
allocCtx, _ := chromedp.NewExecAllocator(context.Background(), opts...)
return allocCtx
}
}

简单说明一下:

  • 前3个特性要求
  • 通过 chromedp.NewRemoteAllocator 创建远程浏览器实例,支持多实例隔离
  • 通过 chromedp.WithTargetID 设置浏览器实例 ID,支持tab页面关联,实现中断交互

本来计划要花点时间的任务,在AI加持下分分钟搞定。可以迎接端午安康了!