0c0ca4a0ac1f249860b29e295dd55260

如何巧用飞书消息卡片输入框实现一套业务交互逻辑

飞书开放平台最近开始内测了输入框的能力,基于输入框,为消息卡片提供了进一步业务系统打通的可能性,你可以不需要开发一整个网页应用,只需要借助飞书机器人和飞书消息卡片,就可以实现一套业务交互逻辑。

流程图示意

w0052z

目标说明

这里首先确定要实现的逻辑:这里我要做的是一个短链接应用,功能很简单,点击下方的机器人菜单,并在弹出的窗口中输入对应的短链接后缀和要跳转的链接,点击确定就会帮我创建一个短链接。

4rbg8i

具体效果如下:

dqk8d2

如果后缀已经被占用,则展示如下内容:

50tl60

在实现这个功能时,我首先使用了飞书提供的输入框组件的能力和表单组件能力,来实现整个业务交互,当然,你也可以根据业务形态,来选择合适的组件,构成一整个输入表单。

实现逻辑

整体的功能可以分为三步:

  1. 点击按钮:机器人需要响应点击事件,并发送一个带有输入框的消息卡片。
  2. 验证卡片输入内容:消息卡片中提供了输入框,但是用户的输入是否我们能用,需要设计一些验证的能力。
  3. 反馈用户是否创建成功:当我们创建成功后,需要给开发者提示,告诉他是否已经创建成功,帮助他结束整个流程。

接下来就是具体的实现步骤了。

点击按钮并回复卡片

首先,我先是使用了机器人的菜单功能,来实现在机器人底部配置菜单。你需要访问飞书开发者后台,找到机器人能力中的「机器人自定义菜单」,就可以配置一个机器人的自定义菜单了。机器人菜单支持跳转到指定链接,或者是推送事件,我选择推送事件,这样我就可以在服务端响应用户的创建的行为。这里我设定了事件内容为 create ,便于后续处理。

ogypfv

机器人菜单的处理则可以参考机器人菜单使用说明,通过订阅「机器人自定义事件」来完成对于相应行为的接受和对应的处理。

这部分的处理逻辑可以参考如下代码

// 判断请求体当中是否有 header 字段 && 来源的事件是否是机器人菜单
if (Object.hasOwn(ctx.body, "header") && ctx.body.header.event_type == 'application.bot.menu_v6') {

    // 请求的事件是否是创建短链接对应的事件。
    if (ctx.body.event.event_key == "create") {
      try {
        await client.request({
          method: "POST",
          url: "https://open.feishu.cn/open-apis/im/v1/messages",
          data: {
            receive_id: ctx.body.event.operator.operator_id.open_id, // 从事件体中提取事件的触发人
            msg_type: 'interactive',
            content: "", // 推送卡片 JSON
          },
          params: {
            receive_id_type: 'open_id',
          },
        })
        return {};
      } catch (e) {
        console.log(`key: ${ctx.body.event.event_key}, user:${ctx.body.event.operator.operator_id.open_id},error`, e);
        return {};
      }
    }
  }
Code language: JavaScript (javascript)

对卡片输入内容进行校验

在完成卡片响应的设定后,接下来我实现的是校验的逻辑,这里分为两层:第一层是客户端可以完成的校验:比如短链接应该少于 10 个字符。第二层是只有客户端才能完成的校验。

1. 在本地校验文件长短

如果每次发起请求都需要发送到服务端进行校验,则有比较高的校验成本。好在消息卡片提供了本地校验的能力,你可以通过 max_length 字段来验证输入框长短.

这里我是使用输入框组件的字段,来验证输入的内容长度不得大于 10 。

du1glf

2. 输入两个参数才发起请求

在消息卡片的输入框组件中,只要输入内容就会发现校验,因此我不能直接使用输入框组件,而是需要借助 form 组件,来实现用户输入两个内容再手动发起提交。则具体我构建的卡片 JSON 是这样的。

{
  "header": {
    "template": "turquoise",
    "title": {
      "content": "创建短链接",
      "tag": "plain_text"
    }
  },
  "elements": [
    {
      "tag": "form",
      "name": "form_1",
      "elements": [
        {
          "tag": "input",
          "name": "postfix",
          "placeholder": {
            "tag": "plain_text",
            "content": "请输入后缀"
          },
          "max_length": 10,
          "label": {
            "tag": "plain_text",
            "content": "请输入后缀:"
          },
          "label_position": "left",
          "value": {
            "k": "v"
          }
        },
        {
          "tag": "input",
          "name": "link",
          "placeholder": {
            "tag": "plain_text",
            "content": "请输入要跳转链接"
          },
          "label": {
            "tag": "plain_text",
            "content": "请输入要跳转链接:"
          },
          "label_position": "left",
          "value": {
            "k": "v"
          }
        },
        {
          "action_type": "form_submit",
          "name": "submit",
          "tag": "button",
          "text": {
            "content": "提交",
            "tag": "lark_md"
          },
          "type": "primary",
          "confirm": {
            "title": {
              "tag": "plain_text",
              "content": "创建短链接"
            },
            "text": {
              "tag": "plain_text",
              "content": "确认提交吗"
            }
          }
        }
      ]
    }
  ]
}
Code language: JSON / JSON with Comments (json)

这部分的关键是用 form 组件包裹 Input 组件,从而规避了 Input 组件输入内容就会发送到服务端校验的问题。

7yro9r

3. 在服务端验证有无

这部分逻辑我在实现的时候相对简单,没有专门去进行校验(主要是因为我的短链接服务和机器人是两个不同的服务),而是通过短链服务返回 200 还是 401 来判断是否出现了重复的问题,所以这里只是简单的使用了一个 try catch 来完成校验。

需要注意的是,这里你会注意到,返回是直接返回了一段 JSON String,这是因为触发这个事件是通过消息卡片的回调能力,如果你在消息卡片的回调能力返回一个 JSON,就会直接把 UI 层面的卡片渲染为你返回的卡片结果。靠着这个功能,我来实现的成功与失败返回不同的内容。

if (Object.hasOwn(ctx.body, "action") && ctx.body.action) {    
    try {
      // create link

      if (status == 200) {
        return JSON.stringify({
          "type": "template",
          "data": {
            "template_id": "ctp_AAmFBm5vnlt0",
            "template_variable": {
              "source": ctx.body.action.form_value.postfix,
              "target": ctx.body.action.form_value.link
            }
          }
        })
      }
      return {};
    } catch (e) {
      return JSON.stringify({
        "type": "template",
        "data": {
          "template_id": "ctp_AAmFBm5vZYuo",
          "template_variable": {
            "POSTFIX": ctx.body.action.form_value.postfix
          }
        }
      });
    }
  }
Code language: JavaScript (javascript)

完整代码参考

整个机器人的部分的代码只有 170 余行,不多,供你参考

import cloud from '@lafjs/cloud'
import axios from 'axios'

let appid = "";
let secret = ""

const lark = require('@larksuiteoapi/node-sdk');

const client = new lark.Client({
  appId: appid,
  appSecret: secret
});


export default async function (ctx: FunctionContext) {

  console.log("event",ctx.body);

  if (ctx.body.challenge) {
    return ctx.body
  }

  if (Object.hasOwn(ctx.body, "action") && ctx.body.action) {
    if (ctx.body.action.name != "submit") return { code: 1 };
    try {
      // function to create link

      if (status == 200) {
        return JSON.stringify({
          "type": "template",
          "data": {
            "template_id": "ctp_AAmFBm5vnlt0",
            "template_variable": {
              "source": ctx.body.action.form_value.postfix,
              "target": ctx.body.action.form_value.link
            }
          }
        })
      }
      return {};
    } catch (e) {
      return JSON.stringify({
        "type": "template",
        "data": {
          "template_id": "ctp_AAmFBm5vZYuo",
          "template_variable": {
            "POSTFIX": ctx.body.action.form_value.postfix
          }
        }
      });
    }
  }

  if (Object.hasOwn(ctx.body, "header") && ctx.body.header.event_type == 'application.bot.menu_v6') {
    // 处理按钮
    if (ctx.body.event.event_key == "help") {
      try {
        let content = JSON.stringify({
          template_id: "ctp_AAmFBFOpYX0S"
        });
        await client.request({
          method: "POST",
          url: "https://open.feishu.cn/open-apis/im/v1/messages",
          data: {
            receive_id: ctx.body.event.operator.operator_id.open_id,
            msg_type: 'interactive',
            content: JSON.stringify({
              "type": "template",
              "data": {
                "template_id": "ctp_AAmFBFOpYX0S",
              }
            }),
          },
          params: {
            receive_id_type: 'open_id',
          },
        })
        return {};
      } catch (e) {
        console.log(`key: ${ctx.body.event.event_key}, user:${ctx.body.event.operator.operator_id.open_id},error`, e);
        return {};
      }
    }
    if (ctx.body.event.event_key == "mylink") {
      try {
        // function to get all my link 
        let links = data.data.map(item => {
          return {
            source: `[${item.Postfix}](https://link.feishu.io/${item.Postfix})`,
            target: item.Link
          }
        })
        await client.request({
          method: "POST",
          url: "https://open.feishu.cn/open-apis/im/v1/messages",
          data: {
            receive_id: ctx.body.event.operator.operator_id.open_id,
            msg_type: 'interactive',
            content: JSON.stringify({
              "type": "template",
              "data": {
                "template_id": "ctp_AAmFBm5vnHfs",
                "template_variable": {
                  "CONTENT": links
                }
              }
            }),
          },
          params: {
            receive_id_type: 'open_id',
          },
        })
        return {};
      } catch (e) {
        console.log(`key: ${ctx.body.event.event_key}, user:${ctx.body.event.operator.operator_id.open_id},error`, e);
        return {};
      }
    }
    if (ctx.body.event.event_key == "create") {
      try {
        await client.request({
          method: "POST",
          url: "https://open.feishu.cn/open-apis/im/v1/messages",
          data: {
            receive_id: ctx.body.event.operator.operator_id.open_id,
            msg_type: 'interactive',
            content: "{\"header\":{\"template\":\"turquoise\",\"title\":{\"content\":\"创建短链接\",\"tag\":\"plain_text\"}},\"elements\":[{\"tag\":\"form\",\"name\":\"form_1\",\"elements\":[{\"tag\":\"input\",\"name\":\"postfix\",\"placeholder\":{\"tag\":\"plain_text\",\"content\":\"请输入后缀\"},\"max_length\":10,\"label\":{\"tag\":\"plain_text\",\"content\":\"请输入后缀:\"},\"label_position\":\"left\",\"value\":{\"k\":\"v\"}},{\"tag\":\"input\",\"name\":\"link\",\"placeholder\":{\"tag\":\"plain_text\",\"content\":\"请输入要跳转链接\"},\"label\":{\"tag\":\"plain_text\",\"content\":\"请输入要跳转链接:\"},\"label_position\":\"left\",\"value\":{\"k\":\"v\"}},{\"action_type\":\"form_submit\",\"name\":\"submit\",\"tag\":\"button\",\"text\":{\"content\":\"提交\",\"tag\":\"lark_md\"},\"type\":\"primary\",\"confirm\":{\"title\":{\"tag\":\"plain_text\",\"content\":\"创建短链接\"},\"text\":{\"tag\":\"plain_text\",\"content\":\"确认提交吗\"}}}]}]}",
          },
          params: {
            receive_id_type: 'open_id',
          },
        })
        return {};
      } catch (e) {
        console.log(`key: ${ctx.body.event.event_key}, user:${ctx.body.event.operator.operator_id.open_id},error`, e);
        return {};
      }
    }
  }
  return { data: 'hi, laf' }
}
Code language: JavaScript (javascript)
5e54199359bbafe0ef692365a9bcffb6

使用 fresh 来提升你的 Golang 开发效率

Golang 作为一个编译型语言,在编写程序时,一个不太方便的点便是每次修改完代码,都需要重新编译才能测试效果。虽然你可以使用 go run main.go 命令来运行一个 go 文件,但由于项目往往文件比较多、修改时还是需要手动输入命令比较麻烦,所以给 Golang 的开发过程带来了不少的问题。

fresh 就是一个帮助你执行一些重复命令的命令行工具,有了 fresh ,你就可以不用自己手动执行 go run main.go,它在检测到文件发上了变化后,会自动帮你中断掉当前进程,并重新执行命令,帮你实现 live-reload 的效果。

fresh 的执行效果

v1btrb

https://github.com/gravityblast/fresh

安装

安装比较简单,执行 如下命令后,你就可以在任何地方执行 fresh 命令了。

go get github.com/pilu/fresh
Code language: JavaScript (javascript)

执行

当你当前目录有 main.go 文件时,直接执行 fresh 就会自动执行 main.go 文件。不过,如果你想要自定义的话,也可以通过配置文件来完成。创建一个 sample.conf 文件,贴入如下配置,并执行 fresh -c sample.conf 就可以让 fresh 按照你的配置来执行命令。

root:              .
tmp_path:          ./tmp
build_name:        runner-build
build_log:         runner-build-errors.log
valid_ext:         .go, .tpl, .tmpl, .html
no_rebuild_ext:    .tpl, .tmpl, .html
ignored:           assets, tmp
build_delay:       600
colors:            1
log_color_main:    cyan
log_color_build:   yellow
log_color_runner:  green
log_color_watcher: magenta
log_color_app:<a href="https://github.com/gravityblast/fresh#usage"></a>
Code language: HTML, XML (xml)
d2b5ca33bd970f64a6301fa75ae2eb22 25

《高效邮件工作法》书摘

  • 高效能人士最常考虑的就是工作的“主导权”。
  • 高效能人士不喜欢无用功。这里所说的无用功,指的是原本不用做,却因为没有安排好而不得不做的所有工作。
  • 与其排出优先级,不如省下时间着手处理眼前的工作,反而更能迅速完成工作。
  • 例如,你打开的第一封邮件的内容是“请修改网站资料”,大约需要10分钟的时间。这时,如果你手头刚好有别的工作,可能会回复“收到,我会在××点之前处理,请您稍等”。但是高效能人士会先处理这件事。不是说回复“××点之前处理”不对,只是“之后有时间了再处理”这种想法,是拖延的思维,有些危险。从尽快完成工作的角度考虑,了解邮件内容后立刻着手处理更有效率。
  • 其实如果在“3W”的基础上再增加一些信息,邮件的效果会更好。这就是“6W+3H”。先在“3W”上加上“3W”: When……什么时间 Where……什么地点 Whom……对象是谁 再加上“3H”: How to……怎么做 How many……多少 How much……花费多少 利用这些来整理想要传达的信息吧。
  • 总之,回复邮件并不是越快越好,最佳的回复时机要结合“目的”来考虑。
  • 发送的邮件完美无瑕,这是我们的理想。但是如果因为追求完美而错过对方期望收到邮件的时间,这封邮件就失去了它的价值。我认为我们更应该重视速度,为了“目的”,牺牲一点“正确”也无可厚非。这么一想,写邮件时是否会更放松一些?
  • 因此,避免连词的过度使用,是缩短邮件的一个方法。有人觉得连词是邮件不可或缺的,但是即使没有连词,邮件内容也是流畅的。所以果断删除那些不必要的连词吧,上下文的连贯性并不会受到什么影响。
  • 其实想要尽快收到回复并不难。只要根据前文所列的看上去有些棘手的邮件的共同点,反其道而行之即可。具体来说,就是要使邮件内容易读懂、易判断、需求明确。此外,要明确地列举出回复的好处(更进一步说,最好再加上不回复的坏处)。
  • 高效能人士的语感十分敏锐,他们不仅可以准确地传达信息,还会有意识地考虑如何给对方留下好印象。因为就算你传达的信息无误,如果对方对你没有好印象,也不会心情愉悦地与你合作,反而可能拖延工作。要想提高工作效率,仅靠自己的努力是不够的,只有使对方心情愉快地与你合作,才能加快工作进程。
  • 高效能人士很少使用消极的语言,即便在传达消极的内容时,也会尽量使用积极的表达方式。例如,他们会将“按时集合不要迟到”换成“请您预留足够的时间,及时到达集合地点”。再比如,他们会将“请不要随意修改数据”改为“如果需要修改数据,请与负责人联系”。这样一来,不仅不会惹怒对方,还可以使其欣然采取我们所期望的行动。
  • 转换说法时,需要注意的要点很多,其中最关键的就是不要为自己的行为道歉,而要感谢对方的行为。比起“没能接到您的电话,非常抱歉”,“感谢您的来电”更能给人留下好印象。
  • 邮件只能用文字传达信息,因此,要避免对方将信息理解错误。如果遇到信息还没有完全确认就需要发邮件的情况,在前文的案例中,不要写“我认为付款时间是下月末”,而该写成“付款时间是下月末,我向会计确认之后再与您联络”。 当然,对于很多推测、预测、无法断言的内容,如不便断言的战略等,传达前需要事先表明“我预测”、“我个人认为”,或者“我确认一下细节再……”,这样文中就不用反复使用“我认为/我想”的表述了。
  • 话虽如此,胡乱打听却是不智的。这种时候,请使用“在可能的范围内”、“如果方便的话”等表述。
  • 大项目的运行必须事先设定“提前确定信息共享对象”、“工作汇报另行发送邮件”等基本规则。
  • 适合通过电话沟通的情况有: •可以当场回复的事情。 •紧急的事情。 •需要边解说边确认对方的理解程度的事情。 •因为存在感性因素,仅用文字表达容易引起纠纷的事情。 即使对方已经发来邮件,如果你认为电话沟通更快捷或更不容易引起误解,都可以主动进行电话沟通。
man covering face with both hands while sitting on bench

Eye Monitor 沉浸式工作打断神器

写代码最常见的问题是容易太沉浸,一写就是好几个小时不挪窝。 最近发现了一个应用: Eye Monitor ,可以很好的解决沉浸式写代码导致的久坐问题。

它和番茄钟有什么不同?

番茄钟在很多场景下, 也都是实现打断的功效,强制你在一个特定的时间范围内做事 / 休息。但和大多数番茄钟不同的是,这个应用实现了一些有意思的活动算法,来帮你计算时间。而番茄钟则是明确的按时间卡住,不论这段时间你是否有操作,时间到了就是到了。

实现的效果

Eye Monitor 实现的效果就是当你的“疲劳度”达到了 100%,就会给你全屏幕弹窗,强制让你休息。虽然你也可以继续跳过,但跳过本身并不会降低你的疲劳度,只是让你可以短时间的休息一下,然后再次提醒你休息。这个设计是有点意思的。

8n7rqv

比如,这是我的休息统计,可以看到疲劳值会增加,中间如果你有休息,疲劳值则会降低,再次开始 Coding 则会再次提交。除了可以用来提醒自己休息,还可以不定时的看看自己什么时候在 Happy Hacking,什么时候在摸鱼~

40muwy

two women facing security camera above mounted on structure

使用 Find Duplicates 插件清理 Calibre 书库

我在导入 Kindle 的图书时,错误的导入了两遍,导致我的 Calibre 仓库快速膨胀,因此,我希望清理掉其中重复的书籍,减少二次存储。

清理使用的是 Find Duplicates 这个插件

安装

在 Calibre 的「首选项」-「插件安装」页面,搜索 Find Duplicates,就可以找到这个插件,双击安装,并重新启动,即可使用该插件。

205m0u

如果你默认选择的是在主菜单展示工具,则会像我一样,在页面顶部有一个新的入口

lb787o

使用

使用非常简单,点击按钮,进入搜索页面,可以配置对比的元素,可以是二进制对比(更精准)或者是 基于某个特定的标签对比(比如 ISBN),也可以使用默认的标题作者对比。根据你的喜好,你可以选择合适的方式进行对比。

在下方的结果输出中,可以选择“Show All Groups at once with highlighting”,这样可以在一个列表中快速看到所有需要清理的图书,快速删除,达成目标。

点击确定,执行后的结果就是这样子的了,你只需要在重复的两本书中,选择你要删除的那一本即可。

a tractor in a field

如何 Debug 爬虫无法成功爬取的问题

在写爬虫的时候,我们会遇到最常见的问题是浏览器访问是一切正常的,但到代码编写的时候,就发现无法正常爬取。

y39ss5

这个时候往往是我们的爬虫所模拟的行为和代码里是不同的(比如浏览器拥有 30 个参数,但我们的代码中只有一个参数),从而导致最终执行的效果不同。而想要在代码中实现和浏览器相同的效果,最重要的是完全复制浏览器的行为,以便于让代码去模拟

所以关键在于找到从30个参数正常运转,到1个参数不运转的关键参数,毕竟我们不想在代码当中添加太多的 Magic Value 来解决一些问题。所以要找到关键的参数。

获取现场

首先,我们需要获取到和浏览器一样的数据,因为这个是我们进行后续的基础,有了它,我们才能进行从 30 个参数减少到 1 个参数。在执行这个步骤时,你需要借助 Chrome Devtools,来获取到现场。

使用 F12 打开 Chrome DevTools,切换到 「网络」Tab ,并刷新页面,以重新加载请求。页面正常加载完成后,你就可以从中找到你要 Debug 的请求。在这个请求上点击右键,选择「复制」,并选择「以 cURL 格式复制」,复制以后,你会得到如下的内容。这就是你在使用浏览器时,实际发送给服务器的请求。

你可以将这段命令放在 Terminal 中运行,你会看到和浏览器中的一样的内容输出。

此时,我们看复制出来的命令,其中包含了链接(我们的一个的参数),以及大量的 Header,这些 Header 中的某一个可能就是服务器将我们视为爬虫的 Header,然后拒绝我们的。

curl 'https://www.baidu.com/' \
  -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' \
  -H 'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7' \
  -H 'Cache-Control: no-cache' \
  -H 'Connection: keep-alive' \
  -H 'Cookie: BIDUPSID=1B455AFF07892965CF63335283C0BD80; PSTM=1690036933; BD_UPN=123253; BDUSS=BDcmp1YzFSeTRDLXVGZlNBbDJKZ08ya1lMQUpBVTlEaWM5WE9mV25YWn5EfmxrRVFBQUFBJCQAAAAAAAAAAAEAAADwPbowsNe084aq4MIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH-C0WR~gtFkan; BDUSS_BFESS=BDcmp1YzFSeTRDLXVGZlNBbDJKZ08ya1lMQUpBVTlEaWM5WE9mV25YWn5EfmxrRVFBQUFBJCQAAAAAAAAAAAEAAADwPbowsNe084aq4MIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH-C0WR~gtFkan; delPer=0; BD_CK_SAM=1; ZFY=sMxi79JqlMJjPMSJ3gQr5ht5g0MCtkIqefc2OTMspV4:C; BD_HOME=1; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; rsv_jmp_slow=1691762441727; BAIDUID=1B455AFF07892965CF63335283C0BD80:SL=0:NR=10:FG=1; sug=0; sugstore=1; ORIGIN=2; bdime=0; BAIDUID_BFESS=1B455AFF07892965CF63335283C0BD80:SL=0:NR=10:FG=1; PSINO=2; COOKIE_SESSION=161794_0_4_3_2_11_1_0_4_4_1_0_161839_0_9_0_1691922269_0_1691922260%7C4%230_0_1691922260%7C1; MCITY=-131%3A; H_PS_PSSID=36558_39217_38876_39118_39198_26350_39138_39100; BA_HECTOR=8gah01agag8g2kala0a12l2o1idr2ba1o; RT="z=1&dm=baidu.com&si=8e7a4596-4b9f-45c3-bf30-f7dffaddd79d&ss=llewny2r&sl=3&tt=1ag&bcn=https%3A%2F%2Ffclog.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ld=89j&ul=104t&hd=105p"' \
  -H 'DNT: 1' \
  -H 'Pragma: no-cache' \
  -H 'Sec-Fetch-Dest: document' \
  -H 'Sec-Fetch-Mode: navigate' \
  -H 'Sec-Fetch-Site: none' \
  -H 'Sec-Fetch-User: ?1' \
  -H 'Upgrade-Insecure-Requests: 1' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"' \
  --compressed
Code language: JavaScript (javascript)

使用二分法测试 Header

如果要查出哪些 Header 是关键参数,一个比较便捷的方式是采用二分法的方式来调试这些 Header。

具体操作时,你只需要删除一半的 Header,并再次发送 cURL,看是否可以正确获得我们想要的内容。如果你发现删除的这一半并不会让你拿到的返回结果报错,就可以继续使用二分法删除 Header,直到定位到真正会影响到我们正确获取结果的 Header 为止。

当你测试到某个 header 被移除后回导致无法正确返回内容,接下来你可以把剩下的 header 继续使用二分法来删除,测试具体会影响结果的 Header,直到删无可删之时,就说明我们已经拿到了能正常运转的最简参数。

此时,你就可以放心的将上述逻辑放在你的代码中来进行维护。

除此之外,你还可以使用上述的逻辑,把你的爬虫逻辑放进单元测试,这样当目标网站调整了爬虫逻辑之后,你就会快速发现。

Investment

我的美股持仓

以下内容仅为个人的记录,不做任何投资建议。

2022 年的时候,我曾经写过我的美股投资策略,如今已经 2023 ,我也经历了一轮买入和买出,并追加了投资,所以重新复盘一下过去一年的持仓变化。

2022 年的持仓

2022 年时,我的持仓主要是 $AAPL、$MSFT、$NVDA 和 $FUTU,四只股票。总体投入的成本是 26,071.74港币,约等于 3,330.38 美元。

2023年的持仓

2023 年,我的持仓相比于去年有了一些变化。

1. 同时使用了两家券商

目前的我同时在使用富途牛牛和长桥作为我的美股交易券商。之所以切换到长桥,主要的原因是其终身免佣金(股票交易里佣金的损耗还是挺夸张的)。

2. 持仓发生了不少变化,和去年的重合度为 0%

2023 年,我把去年的一些持仓全部都换成了新的持仓,可以趁机聊聊。

先说从我的持仓中移出的部分

$AAPL 我是在 156.03 刀时买入,在 175 刀时卖出。持仓约 1 年,年化约 10%。写文章的此刻,$AAPL的价格是 174.310 刀。苹果的卖出是因为我希望将资金从富途迁移到长桥,所以做了卖出,而不是转券商(发现转券商是按持仓的股票来算的,卖出后的资金损耗反而更低一些)。当时主要是想着能够减少一些佣金,但实际上我的美股交易并不频繁,那么这个转仓是否真的有意义?


$FUTU 我是在 42.30 刀时买入,在 49.03 刀时卖出,持仓 1 年 2 个月,年化约 13.77%。写文章的此刻,$FUTU 的价格是 49.21 刀。富途的买入策略在上一篇里说过了,而卖出策略和 $AAPL 是一致的。不再赘述。


$NVDA 我是在 214 刀时买入,在 271.37 刀时卖出,持仓约 1年 2 个月,年化约 21.79%。写文章的此刻,$NVDA 的价格是435刀。NVDA 的买入策略在上一篇说过,是因为买不到 3090 ,就买了点 $NVDA。但卖出从现在来看,我认为自己还是太年轻,一个是其实当时完全没必要转仓,不交易其实完全可以接受。应该要忍住自己的精神洁癖。另外一个是对于 $NVDA 的成长性没感知,我卖掉的时候还是今年的 3 月, 彼时 ChatGPT 已经火了,对于我这个早期的 ChatGPT 用户来说,其实是能预测到利好 $NVDA 的。但是当时为了一个减少佣金的理由,就卖掉了。太年轻了!


$MSFT 我是在 295 刀时买入,在 318.83 刀时卖出,持仓约 1年 2 个月,年化收益约 6.69%。写文章的此刻,$MSFT 的价格是 319.780 刀。$MSFT 的卖出逻辑也是比较简单,主要是转仓,不多说。$MSFT在我卖之后,倒是没有涨特别多,所以我的心里负担没有 $NVDA 那么重。但回过头来看,依然不是一个很好的投资决策。


再说从我的持仓中保持的部分

$API,已经记不得当时买入的价格了,不过目前的价格是 $2.96, 而我的成本是 $11.68,不过因为买入的不多,所以还好,一共也就 300 美元左右。目前的总价值大概是 $74 ,持有约 1 年时间,年化收益约 -74.66%。就目前而言,我可能会继续买入 $API,来拉低我的平均持仓成本。此外,这部分买入可能不会买入特别的多,按照目前的情况,我可能会再买入 100 股左右,把平均持仓成本拉到 $5 左右。

$API 这家公司我有接触过,总体来说,我认为在实时互动领域是掌握了核心科技和体验上的优越性的。所以我还是看好。当然,当初 100 多刀的价格也的确是疯狂。只是我没想到现在的日常价格是 $3 。

但另外一个层面,$3 也处在一个足够便宜的价格,对我来说,只要买入的总量不到某个占比特别大的值,我依然愿意购买。安全边际足够。


最后说我新增买入的股票

2023 年,我新增的股票是 $PDD

$PDD 买入价格 $72.804,2023.05.18 买入,持有 24 股,写文章的此刻价格为 $81.20,总价值 $1948.8。$PDD 的买入原因是我自己在日常使用 PDD 较多,且 PDD 做的是“便宜”,这个是永远的竞争力,我看好它(但可能是错的)。

$DIS 买入价格 $86.498,2023.08.07 买入,持有 33 股,写文章的此刻价格为 $86.340,总价值 $2849.38。$DIS 的买入逻辑则是源于迪士尼的造星运动,从过去的米奇,到后面的迪士尼影城,再到现在的玲娜贝儿,$DIS 的生命力似乎永远都不会有问题。考虑到西半球最强法务部,买了。

$BRK.B 买入价格 $329.760,2023.05.18,持有 1 股,写文章的此刻价格为 $355.70,总价值为 $355.79。$BRK.B 买的就是情怀了,毕竟入了价值投资的门,还是要买一股纪念一下的。万一明年能被抽中去听老爷子讲话呢。

总结

2022 年到 2023 年,我整体来说是各种昏招频出。希望新的一年里,能够更加理智的进行投资,以及,多读点书,别tm瞎出招了。。。

d2b5ca33bd970f64a6301fa75ae2eb22 24

《失业白领的职场漂流》书摘

总结

这本书看的意图是看到一些对于失业的人来说,如何找到自己的工作。不过看到的更多的是针对失业人士的陷阱。有点意思。

书摘

  • 德国著名的社会学家和哲学家齐美尔有句名言,“金钱只是通向最终价值的桥梁,而人是无法栖居在桥梁之上的”。
  • 一旦掉进低薪、谋生工作的陷阱里,那么长期滞留在“过渡地带”的概率就会很大,求生的挣扎已经让这些失业人员顾不上自我技能的提升。
  • 我从哈维·麦凯(Harvey Mackay)的商业畅销书《我们被炒鱿鱼了!》(We Got Fired!)中学到,找工作比实际工作更耗时:“假如你有一份工作,那么你就可能拥有朝九晚五的奢侈;假如你是要找工作,那就预计每天做12到16个小时吧!”[
  • 杰弗里·福克斯(Jeffrey Fox)所著的《别为找工作抓狂》(Don't Send a Resume),
  • 但是从那些拥有权力与高薪工作的“赢家”的观点来看,个人命运完全掌握在自己手上这个观点一定更方便。这个观点以最吹捧的字眼来诠释赢家的成功,同时也推翻输家的抱怨。例如,帕特里克的学生来到训练营,早就预备好要把他们的困境归咎于经济、房地产市场,或公司非人的加班要求。但是这些被告们立刻被驳回,改以个人的缺失为托词:忧郁、迟疑、不专注。这里所传达的信息是,需要改变的不是这个世界,是你。那么就没有必要联合起来为更健全的经济或更人性化的企业环境而努力,或根本就不需要团结。正如一位成员所说的,我们是我们自己的敌人。
  • 我知道在“过度性感”“过于丰满”或“美若天仙”这些方面,我没有什么问题,但显然对任何年龄或任何情况的女性来说,身为女人都是需要抱歉的。
  • 一次次的失业,就算没得到什么,也多了一些时间来思考到底怎么了。习惯于每周工作60到80个小时的人,无论是在办公室、在家或通勤路上,都突然发现自己多了好多时间。这些时间不只让你可以好好省思,问自己:“我真正想做的是什么?”——这是职业教练总敦促你去思考的问题——同时还让你更广泛地思考:“这幅职业生涯规划图到底哪里不对劲?”
d2b5ca33bd970f64a6301fa75ae2eb22 23

《更富有、更睿智、更快乐》书摘

图书基本信息

  • 书名:更富有、更睿智、更快乐:世界顶尖投资者是如何在市场和生活中实现双赢的
  • 作者:威廉·格林
  • 译者:马林梅
  • 简介:《更富有、更睿智、更快乐》介绍了沃伦·巴菲特、查理·芒格、约翰·邓普顿、霍华德·马克斯等40多位投资大师的投资智慧。在分享与众多投资大师深入接触的日常故事中,作者威廉·格林总结出了投资大师的为人处世之道,也发现了这些一流的投资名家的共同点。他们都是:
    长期主义的践行者;
    擅长忍耐的纪律奉行者;
    冷静又坚韧的投资者。
  • 出版时间:2022-03-01 00:00:00
  • ISBN:9787515365718
  • 出版社:中国青年出版社

书摘

前言 卓越的投资者是如何思考的

  • 正如他向我解释的那样,投资是一个不断计算概率的过程:“一切看概率,不存在确定性。”
  • 林奇(Lynch)在高中、大学和参军时都玩扑克牌,他告诉我:“学习玩扑克牌或桥牌,参与任何可以让你学习概率知识的事务……都比读有关股市的书籍效果好。”
  • 把投资和生活视为一种游戏是很有益的思维方法,我们必须刻意地、始终如一地寻求最大限度地提高成功概率的方法。规则难以捉摸,结果也不确定,但游戏有聪明的玩法和愚蠢的玩法。
  • 你不一定每次都预测对,但预测会比纯粹的听天由命好一些……所以我们把一个纯粹的机会游戏变成了一个我们具有优势的游戏,这一优势是我们靠补充的信息获得的。
  • 例如,他知道,当他处在“情绪模式”时,他更可能做出错误的决定,所以当他对某人感到“愤怒或生气”时,他会退一步问自己:“你真正知道些什么?你的感觉是否合理?”他谨慎的分析常常表明,他的不良反应是毫无根据的。

第一章 效仿沃伦·巴菲特的人

  • 首先,无论何时购买股票,你购买的是持续经营、具有潜在价值的企业,而不仅仅是供投机者交易的纸片。
  • 其次,格雷厄姆将市场视为“投票机”,而不是“称重机”,这意味着股价往往无法反映这些企业的真实价值。
  • 最后,只有在股票的售价远低于对其价值的保守估计时才应该买入。
  • 一次,我们在他尔湾市的办公室里畅谈,他说:“投资的首要技能是保持耐心,极度的耐心。”2008年股市崩盘时,他在两个月之内完成了10笔投资交易。在平常时期,他完成的投资量较少,比如他在2011年只买入了两只股票,在2012年买入了3只,2013年一只也没买入。
  • 正如芒格所说,捕鱼要遵守两条规则:第一条是,鱼在哪里,人就在哪里;第二条规则是,别忘了第一条规则。
  • 他告诉我:“几乎没什么股票可以买入时,你必须非常小心,你不能强迫自己买入,必须保持耐心,便宜货自会来找你。”他警告说:“一直参与市场交易是傻瓜才干的事,那样做会赔钱的。”
  • 他最喜欢的一句名言是哲学家布莱斯·帕斯卡(Blaise Pascal)的“人类所有的问题,都源于人类无法独自安静地坐在一个房间里”。
  • 正如巴菲特在伯克希尔公司1998年的股东大会上所说的,“我们不会因采取行动而获益,只会因决策正确而获益”
  • 巴菲特对效仿之法并不陌生,他说:“如果能从其他人身上学习,就不必过多地提出自己的想法了,你可以运用你接触过的最佳想法,关键是要取其精华,弃其糟粕,而不是盲目地照搬一切。”
  • 巴菲特说过,“成功人士与真正成功人士的区别在于,后者几乎对所有事情都说不”。
  • 我的标准非常简单:如果其股价在短时间内(两三年内)不能翻倍,我不会对它有任何兴趣。”
  • 一天晚上,我们俩在尔湾市的一家韩国餐馆吃饭时,我问帕伯莱,为什么很多人不像他一样采用效仿之法呢。他一边吃着麻辣牛肉,一边回答说:“他们不像我这么脸皮厚,他们自尊心比较强。要成为一名卓越的模仿者,你就必须放下自尊。”
  • 正如我们看到的,关键的原则不难被识别和遵循。要有耐心,要有选择性,要对几乎所有股票说不。利用好市场的两极化情绪波动,以低于其基本价值的价格买入股票。在自己的能力范围内投资,避免投资难以理解的企业。把少量赌注押在下跌风险最小、上涨潜力显著的定价有误的股票上
  • 聪明的人很容易被复杂的事物吸引,同时会低估简单想法的巨大影响力和重要性,但帕伯莱是十足的实用主义者,他不会落入这个陷阱。“利用复利的威力是非常简单的想法,效仿是非常简单的想法,讲诚信也是非常简单的想法。”
  • 但耿直的帕伯莱嘲笑任何把他视为正义的救世主的想法,他在孟买的出租车上对我说:“当你觉得生活毫无意义时,你该怎么办?不要毁了别人的生活。留下一个更美好的星球,照顾好孩子,剩下的就是无关紧要的游戏了。”
  • 我思考了帕伯莱的人生经历及其对我的启示,发现有几条原则特别能引起我的共鸣。我在备忘录中写道:
    原则1:疯狂地效仿。
    原则2:与比自己优秀的人为伍。
    原则3:把生活视为一场游戏而不是生存竞赛或者你死我活的战斗。
    原则4:做真实的自己,不做自己不想做或者自己认为不适合的事情。
    原则5:按自己内心的评判标准生活,不要在意其他人的看法,不要被外部条件所束缚。
  • 最后,我写了芒格说过的一句话,帕伯莱也经常引用它,即:“接受简单的想法并认真对待它。”

第二章 愿意孤独

  • 他同样坚决反对退休,他认为退休对身体和心灵的伤害都是“致命的”。在邓普顿看来,到了65岁就退休的错误观念“大大增加了无所事事的闲散之人、无用之人”,这些人“会拖累文明”。
  • 世界生命法则:200条永恒的精神原则》(Worldwide Laws of Life: 200 Eternal Spiritual Principles)
  • 邓普顿目睹过身处经济危机的田纳西州农民如何被迫以近乎零美元的价格出售土地,因此始终铭记这一教训:“你必须在别人拼命想卖出时买入。”他后来用“极度悲观”这个奇妙的词汇来描述恐惧和绝望肆虐的时刻。
  • 巴菲特和芒格一样,他对定价错误、风险和回报不对称的押注有一种理智的欣赏。邓普顿解释说:“其上行的潜力远远大于其下行的潜力,当然,我可能会赔掉100美元,但如果我不赔钱的话,我可能会赚很多。”
  • 第五,寻找便宜货的最佳方法是研究过去5年中表现最糟糕的资产,然后评估造成这些困境的原因是暂时性的还是永久性的。

第三章 一切都变了

  • 马克斯指出,投资完全就是在“预测未来”,我们在分析任何资产时,要考虑对其未来利润和估值的预期,必须弄清楚今天要付出什么代价。
  • 在一切都不稳定、不可靠以及几乎任何事情都有可能发生的世界里,我们应遵循的第一条原则是,实事求是地看待自己的局限性和脆弱性。
  • 马克斯认为有效市场假说是“非常强大的观念”,但学术理论和他为自己和客户赚取了数十亿美元的实践之间仍然存在着巨大的差异。他讲了这样一个笑话:一位金融学教授和一名学生正在芝加哥校园里散步,学生突然停下来大声喊道:“看,教授,地上有一张5美元的钞票!”教授回答说:“不可能是5美元的钞票,否则别人早把它捡走了。”教授走开了,学生弯腰捡起了那张钞票并买了杯啤酒喝。巧的是,马克斯的钱包里也有一张折过的5美元钞票,这是他在哈佛商学院的图书馆里捡到的——这提醒人们,理论是有局限性的。
  • 马克斯从学术争论中得出了一个简单但足以改变人生的启示:作为一名投资者,如果他想增加价值,他就应该避开效率最高的市场,只关注效率较低的市场。他说:“一个市场被研究得越多,被关注得越多,被接受得越多,被宣传得越多,在该市场上讨价还价的余地就越小。”
  • 任何资产,无论其多么丑陋,只要价格足够低廉,它就值得购买。事实上,马克斯认为,“低价买入”是获得投资财富的唯一可靠途径,而“高点进场”是最大的风险,因此,对任何潜在的投资而言,最应该提出的基本问题是:“它便宜吗?”
  • 没有幸运女神的眷顾,马克斯永远不会涉足这些效率低下、物美价廉的市场;没有聪明的头脑和独立的思想,他永远不可能利用好发现的时机。“听着,光靠运气是不够的。”他说,“但只有聪明的才智和努力也是不够的,甚至有毅力也不一定能成功,你需要四者兼备。我们都知道,有的人很聪明,工作也很努力,但他们没有得到幸运女神的眷顾,这让人心碎。总是有人来我这里找工作,他们有的已经50岁了,这么大的年龄却失去了工作,他们应当有工作机会。”
  • 但承认好运还有另一个好处:这让他很快乐。马克斯自信地说:“我觉得自己是个幸运的人,我带着这种不可思议的感觉四处走动。如果你是个消极的人,你可能会说:‘我一生很幸运,这真的很糟糕,因为这意味着我的成功是名不副实的,可能不具有持续性。’但我会说:‘天啊,幸运是多么美好的事情啊,我真的应该心存感激之情,不管是对上帝还是机会,还是其他的什么。’”
  • 加尔布雷斯说:“我们有两类预测者,一类是无知的,另一类是不知道自己无知的。”
  • 这种对自身局限性的认识是怎样把马克斯从无益或有害的活动中解放出来的呢?首先,他不会浪费任何时间去预测利率、通货膨胀或经济增速,在这一点上,我们应该以他为榜样。如果马克斯无法预测这些事情,我相当确信我自己也做不到。与许多竞争对手不同,橡树资本公司甚至没有自己的经济学家,也不邀请外部“专家”来解读宏观经济形势。
  • 当习惯性的怀疑让马克斯错失了一次良机时,他也不会在意。他更重视的是“合理的命题”,即特定证券的价格低于其内在价值。他说:“投资于梦想很容易,真正的挑战是如何确定资产的价值。”
  • 希望获得持久成功的投资者都应该把这一基本理念铭记于心:购买低于其价值的资产,正如我们所看到的,从巴菲特到帕伯莱,从邓普顿到马克斯,他们都是这么做的。
  • 在分析任何资产时,马克斯最想知道的是,“其价格中包含多少乐观的成分”。
  • 他是一位善于吸取经验教训的投资者,他时刻牢记着这句话:谨慎之人很少犯错或者抒写伟大的诗篇。他对自己淡然处之的态度感到很满意,因为这种方法能够降低犯灾难性错误的概率。“你必须做适合自己天性的事,这一点非常重要。”当我问他曾犯过的最具破坏性的投资错误时,他回答说:“我不记得我犯过大错,我只因疏忽大意犯过小错。”
  • “但是,当市场不稳定时,你不必知道催化剂是什么。”马克斯说,“你只需要知道市场存在脆弱性即可。”
  • 他的超然和不受情绪影响的行为完美地反映了他从佛教中汲取的教训。记住:“我们必须适应环境已发生改变的现实。
  • 这是非常有益的。”马克斯告诉我,“要把世界看作是周期性的、震荡的,而不是直线发展的。”他认为几乎所有的事物都是周期性的,例如,经济会扩张和收缩;消费者支出有增有减;企业盈利能力有升有降;信贷的可获得性有高有低;资产估值会升会降等。所有这些都不是朝一个方向持续发展下去,而是会发生逆转。他把这些模式比作摆锤从一端向另一端的摆动。
  • 未来或许是不可预测的,但反复出现的繁荣和萧条是可预测的,一旦我们认识到这一潜在的规律,我们就不会再盲目行动了。
  • 遗忘的代价是高昂的,抑制这种倾向的一种方法是深入研究市场的历史。“你不能预知未来。”马克斯说,“但你能了解过去,这是很有益的。”
  • 2007年是金融危机爆发的前一年,他撰写了一份后来让他倍感自豪的备忘录,里面记录了许多危险的迹象,包括美国和英国愚蠢地放宽了抵押贷款的标准、无条件地为无价值的公司提供融资,以及愿意在没有契约保护的情况下投资高风险债券。为了醒目,他用粗体字写道:“宽松的时代紧跟着惩罚性的修正。”
  • 9月19日,他给橡树资本的客户写了一份备忘录,提出了一个无法回答但又不得不回答的问题:“金融体系会崩溃吗?还是这仅仅是我们经历的最严重的周期性衰退?我的回答很简单:我们别无选择,只能假设这不是末日,而是我们可以利用的另一个周期的开始。”他以典型的冷幽默口吻补充说,“大多数时候,世界末日不会出现。”
  • 他说:“我认为可以把问题简化为,要么世界末日出现,要么世界末日不出现……如果不出现而且我们没有购买资产,那么说明我们没有做好工作。这一方法让事情变得异常简单了。”
  • 马克斯跑回到办公室后,匆匆地写下了一份题为“消极主义的限度”的备忘录。想到那次会面,他认清了一个事实。几十年来,他一直警告投资者:当乐观情绪达到顶峰,以至于人人都不相信坏事可能发生,当悲观情绪达到极致,以至于投资者做出的行为就好像“不会有任何好事”发生时,要持怀疑的态度。在理性的怀疑论者看来,关键不是要永远持悲观的态度,而是要质疑“人人”相信的是什么,他们是过于乐观了还是过于悲观了。在解释他的顿悟时,他写道:“当过于乐观时,怀疑主义呼唤悲观主义;当过于悲观时,它又呼唤乐观主义。”
  • 在我们的交谈和他的著述中,马克斯反复提及了他几十年来一直深思的主题。在我看来,有以下5个关键的理念值得我们铭记:
    •承认我们无法预测或掌控未来很重要。
    •研究历史规律,考虑接下来可能发生的事情时要以史为鉴。
    •周期必将逆转,不计后果的过分行为必受惩罚。
    •可以通过逆周期行为利用好周期性。
    •为了在不确定的世界里取得长期的成功,要保持谦逊、怀疑和谨慎的心态。
  • 正如佛教教义指出的,我们要承认,世间的所有现象都是短暂的,这样我们就不会在事物发生变化时感到惊讶或沮丧。铃木俊隆说:“如果我们不接受一切都在变化的教义,我们就无法保持镇静。”
  • 无论是在市场上还是在生活中,我们的目标既不是轻率地冒险,也不是一味地规避风险,而是明智地承担风险,同时永远不忘坏结果出现的可能性。
  • 他说,为未来的生活做准备时,“不要试图做到极致,在投资和生活中都是如此。所以问问自己,你超越极限了吗?”
  • 这个问题不仅适用于投资,也适用于消费。马克斯说:“经济上独立并非指赚大钱或拥有很多钱,你知道钱从哪里来吗?只要你花的比赚的少,你就能攒下钱,要量入为出。切记,你反脆弱的能力来自你没有达到极限的程度。”

第四章 坚韧的投资者

  • “因为未来是不确定的,你肯定想把风险降至最低。”
  • 巴菲特在《聪明的投资者》一书的序言中写道,“成功的投资生涯不需要超群的智商、非凡的经济眼光或者内幕消息,所需要的只是一个能助力自己做决策的完善的知识架构,以及避免情绪破坏该架构的能力。”
  • “现在腐朽者,将来必重焕光彩;现在如日中天者,将来必坠入深渊。”
  • 埃维拉德所处的地位比较尴尬,这导致他的很多操作并非出自本心。首先,他受投资者的控制。投资者每天都可以赎回资金,这迫使他在价格最便宜时卖出了股票而不是买入。投资者们任性的情绪和反复无常的判断成了他无法控制的外部威胁。其次,他极易受到自己公司内部的压力,包括同事们的,他们担心他拒绝投资科技股会导致他们的经济利益受损。更糟糕的是,他要看老板的眼色行事,他自己说了不算。
  • 如果我们的目标是确保财务韧性,那么我们最好的效仿对象是巴菲特而不是布兰奇,因此,我们要确保这一点:即使陌生人不仁,我们也能做得很好。
  • 个人如何才能减少脆弱性、增强韧性呢?我们应该以巴菲特为榜样,始终保持足够的现金储备,这样我们就不会在经济低迷时被迫抛售股票(或任何其他陷入困境的资产)。我们永远不应过度举债,因为正如埃维拉德所警告的那样,债务会侵蚀我们的“耐心”。像他一样,我们应该经受住那些看似前景辉煌但无安全边际的热门股的诱惑,我们应该绕过那些资产负债表疲弱或迫切需要外部融资的企业,这些企业在困难时期很可能会消失。
    做到这些不像给大脑开刀那么难,但我们要认真对待这条常被遗忘的戒律:你不应依赖陌生人的仁慈。
  • 20世纪20年代,卡恩在格雷厄姆任职的哥伦比亚大学做助教,几十年间他们一直是朋友。我想知道他从格雷厄姆身上学到了什么,促使他在86年的金融生涯中大获成功。卡恩的回答是:“投资最重要的是保存实力,而不是获得丰厚的收益,必须将这一点铭记于心。如果你仅得到了合理的回报,且承受了最小的损失,那么你终将成为富人,而且你会超越所有赌友,这也是解决失眠问题的好方法。”
  • 正如卡恩所言,投资秘诀可用这一个词来表达,那就是“安全”,做出明智投资决策的关键总是从问“我可能亏多少钱”开始。他解释道:“考虑下行风险是投资者必做的最重要的事项,必须先解决这一问题,之后才能考虑收益。现在的问题是,人们以为自己很聪明,可以快速做出决策。你能纵马驰骋这不假,但你走对路了吗?你能看出自己要去哪里吗?”
  • 麦克伦南如饥似渴的阅读让他得出了与格雷厄姆和埃维拉德一样谨慎的结论:未来是如此的“不确定”,投资者应该集中精力避免遭受永久性的损失,并建立“能够承受世界各国各种风险的投资组合”。
  • 想要参与人类前行的征程,首先要在逆境中生存下来。”这是在投资和生活中都需要牢记的一条箴言。
  • 当其他人惊慌失措时,他也能够以“当前更合理的价格买入遭受重创的股票”。他说:“只靠保守是不够的,你还要愿意在别人觉得最不适合时出手。”
  • 在市场上与在生活中一样,成败很大程度上取决于我们在低谷期的生存能力。
    麦克伦南在高盛工作了14年,曾与华尔街一些业绩最出色的人共过事。他起初很想知道这些人是否具有某种与众不同的独特才能。“随着时间的推移,我逐渐发现,他们不放弃原则、不断地学习、不断地进步,持之以恒,在逆境中具有强烈的求生欲。”他看到了最出色的投资者具有的共性,“不放弃,不断获取新知识”,而且能“熬过低谷期”。
  • 我们现在尝试着从格雷厄姆、卡恩、巴菲特、埃维拉德和麦克伦南身上汲取一些关于如何增强投资者韧性的实用经验。在我看来,我们应当铭记以下5条基本规则。
    第一,我们要尊重不确定性。想想格雷厄姆和卡恩在过去约一个世纪里经历过的风风雨雨,你就会意识到,无序、混乱、动荡和意外不是系统的缺陷,而是系统的特性。我们无法预测这些干扰出现的时间、触发因素或确切性质,但我们要认识到,它们可能会出现,并为应对它们做好准备,以减轻它们出现时带来的危害。怎样做呢?确认我们的脆弱性并自觉地消除(或减少)它们。正如纳西姆·尼古拉斯·塔勒布在《反脆弱:从不确定性中获益》一书中所写的那样,“弄清楚什么是脆弱的,比预测对其造成伤害的某个事件是否会发生要容易得多。”
    第二,要保持韧性,必须减少或消除债务,避免使用杠杆,谨防过度支出,这些都会使我们依赖陌生人的仁慈。要问自己这两个关键的问题:“我在哪些方面比较脆弱?我如何降低脆弱性?”比如说,如果你把所有的钱都放在一家银行、一家券商、一个国家、一种货币、一个资产类别或一只基金中,你无异于在玩一把上了膛的枪。幸运时,你可能在短期内赚得盆满钵满,但是,随着时间的推移,当意外事件发生时,你的脆弱性就会暴露无遗。
    第三,我们不应该只重视短期收益或超越基准,相反,我们更应该重视对抗冲击、避免破产和确保生存。从某种程度上看,随着经济增长、生产力提高、人口扩张和复利效力的发挥,我们自然而然会得到收益,但正如卡恩所警告的,我们不能忽视不利因素。
    第四,谨防过度自信和自满。亚里士多德曾指出,“钱多人傻”。就我个人而言,我确信自己是个不够理性、无知、自欺欺人的人,而且尽管我常常嘲笑行为不当之人,但我也容易犯同样的错误,包括相信未来与最近的过去相似这一危险的习惯。
    第五,作为有见识的现实主义者,我们应该敏锐地意识到我们面临的风险,并且应该始终获取安全边际。但要特别注意这一点:我们不能在风险意识的影响下变得惶恐、悲观或偏执。尼采警告说,“凝视深渊太久,你就会变成深渊”。正如麦克伦南在此次新冠疫情期间所展示的那样,坚韧的投资者有实力、有信心抓住机遇,而无信心的投资者将错失机遇。防守突然变为进攻,混乱带来了利润。

第五章 复杂的最高境界是简单

  • 巴菲特本人就是一位简化大师,他在1977年致股东的信中提出了选股的4个标准。他写道:“我们想要的企业必须是:(1)我们可以了解的行业,(2)具有长期竞争力,(3)由才德兼具的人士所经营,(4)吸引人的价格。”你可能不觉得这些标准有什么,但是,要提出比这几条更为合理的选股标准恐怕很难。
  • 众所周知,执掌的基金规模庞大时,要跑赢大盘非常困难,但是,当我们在2017年会面时,丹诺夫做到了这一点。从1年期、3年期、5年期、10年期和27年期的数据来看,他的基金均跑赢了标普500指数。我急于揭开他成功的秘诀,但他只用几个字就概括了他的投资理念,即“股票跟着收益走”。
    在这一原则的指引下,他不遗余力地寻找“将在5年内发展壮大的最佳企业”,为什么呢?因为他认为,如果一家公司的每股收益在未来5年内能翻倍,那么其股价也有可能翻倍(一倍或多倍)。这样的观念很容易被他人忽略,因为它听起来过于简单,但请记住:投资可不像奥运会的跳水项目那样,评委会给难度大的动作加分。
  • 我们每个人都需要一个简单、持续、长期有效的投资策略,一个我们充分理解并坚信无论身处顺境还是逆境都会坚持采用的投资策略。
  • 普通投资者投资指数基金是以这一令人沮丧但符合现实的理念为基础的:如果你不能战胜市场,那么你就应该专注于以尽可能低的成本获得相应的回报。对于绝大多数的投资者来说,投资指数化产品无疑是最合理、最简单的策略。
  • 正如格林布拉特所说,“股票代表的是你正在评估并试图以折扣价购买的企业的所有权”,那么,关键是要确认价格和企业价值之间存在极大差距的情形。这一价差给了你一个安全边际,格林布拉特(像格雷厄姆和巴菲特一样)认为这是投资中最重要的概念。
  • 一旦你意识到,你的使命是给企业估价并以远低于其价值的价格购买其股票,你就会释然了。格林布拉特说:“如果你能这么简单地看待投资,并且始终保持这种简单性,那么你就会发现这一理念非常吸引人,你也会觉得其他理念都很愚蠢。在它的影响下,我把别人告诉我的关于如何看待世界和市场的99%的理念都抛诸脑后了。”
  • 格林布拉特根据不同企业的具体情况采用了4种估值法:1. 进行折现现金流分析,计算公司未来收益估值的净现值;2. 将公司的价值与同类企业的进行比较,评估其相对价值;3. 估计公司的收购价值,计算知情的买家可能会支付的价格;4. 计算公司的清算价值,即分析公司破产清算时的价值。
  • 这就引出了被金融界视为最可靠法则的基本真理:从短期来看,市场是非理性的,经常会导致股票被错误地定价,但从长期来看,市场却是异常理性的。格林布拉特说:“最终,市场先生会做对。”
  • 正如格雷厄姆教导的那样,投资最重要的是安全边际。如果你以远低于其内在价值的价格买入了一只股票,其他投资者迟早会发现这一点,他们最终会推高股价。与此同时,格林布拉特说,“我看不出我会赔很多钱”,这正是他大胆下注的原因。他说:“要根据承担的风险大小来决定仓位。我加仓的不是赚钱最多的股票,而是不会让我赔钱的股票。”
  • 格林布拉特的投资方法不断完善,部分是因为他看到巴菲特调整和改进了格雷厄姆的购买低价股的策略。正如格林布拉特所解释的那样,巴菲特做了“简单的小改进”,这“使他成了世界上最富有的人之一:买进便宜股很棒,但若能买下便宜的优秀企业,那就更棒了”。
  • 这些弄巧成拙的行为凸显出了每个投资者都可能面临的最棘手的挑战。仅找到了能提高长期获胜概率的明智策略是不够的,你还要严格、一贯地运用这种策略,尤其是在你心里感到极不舒服时。
  • 这些数据使他得出了一个重要的启示:“对大多数人来说,最好的策略并不是能让人获得最高回报的策略。”相反,理想的策略是“即使在困难时期也能被坚守的好策略”。
  • 对于一位在20年的时间里运用集中投资法获得40%的年回报率的著名投资者来说,这是令人惊讶的演变,但这一事实也提醒人们,大多数投资者应该致力于获得稳健和可持续的回报,而不是逞匹夫之勇。格林布拉特说:“当我持有6到8只股票时,每隔两三年就可能在短短几天之内损失20%或30%,这样的情形并不少见。”这是一种难以坚持的策略,对大多数个人投资者来说,“它不是好的选择,但对我来说却不错,当股票下跌了20%或30%时,我不会惊慌失措,因为我知道我拥有什么”。
  • 要执行一项涉及数百个多头和空头头寸的复杂策略绝非易事,格林布拉特组建了一支由金融分析师和技术专家组成的20人团队来帮助他实现这一目标。然而,作为其策略基础的原则始终是简单而强大的,我们所有人都应该铭记这些原则,它们是:
  1. 股票代表着企业的所有权,必须重视企业。
  2. 只有当股票的交易价格低于其价值时,才应该买入它们。
  3. 从长期来看,市场是理性的,它将(或多或少地)反映出企业的公允价值。
    问题是,没有人知道市场多久之后才能反映出公允价值,是数周、数月还是数年,但格林布拉特愿意等待,因为他相信这些原则是靠得住的。他说:“如果股票代表了企业的所有权,而且我擅长对它们进行估值,那么至少在一般情况下,随着时间的推移,我会做得很好。和万有引力定律一样,经济规律不会消失。”
  • 当我思考从格林布拉特身上学到了什么时,4点简单的启示赫然出现在了我脑海里。第一,你不需要最佳策略,你只需要一个能实现你财务目标的明智策略。正如普鲁士军事战略家卡尔·冯·克劳塞维茨将军(General Carl von Clausewitz)所说的,“追求完美是好计划的最大敌人”。
    第二,策略应该非常简单、合理,你能理解它,你相信它的内核,即使在困难时期、在它看起来不再有效时你也能毫不动摇地坚持采用它。它还必须契合你对痛苦、波动和损失的承受力。写出策略及其依据的原则和你认为它未来能发挥效力的原因是很好的做法,把它视为一份政策声明或财务行为准则,在你承受压力和面对困惑的时候,在你想要获得心理平衡感和方向感的时候,你可以看看它。
    第三,扪心自问,你是否真的有战胜市场的能力和特质。格林布拉特不寻常的特质使他拥有了显著的优势:他具有强大的分析能力,能将复杂的游戏解构为最基本的原则:评估企业的价值,折价买入,然后等待。他知道如何评估企业的价值。他不受传统观点或权威人士的影响,比如沃顿商学院的教授们宣扬的市场有效说,相反,他乐于一次次地证明他们是错误的。另外,他富有耐心、脾气平和、自信、能干、理性、自律。
    第四,切记这一点:要成为富有的、成功的投资者不一定非要战胜市场。几十年来,约翰·博格目睹了数千名基金经理试图证明自己的长期业绩优于指数基金,但他们都失败了。他对我说:“事实证明,这些所谓的‘恒星’都是‘彗星’,它们曾在片刻间照亮了夜空,但很快就燃烧殆尽了,它们的灰烬轻轻地飘落在了地上。相信我,这样的事情几乎总在发生。”
    博格认为,“最简单的做法”是购买并持有一只配置均衡的指数基金,这类基金持有固定比例的国内外股票和债券。就是这样,不必绞尽脑汁地寻找市场时机,也不必费神劳力地选择下一只热门股或基金。

第六章 尼克和扎克的精彩冒险

  • 你要面对的真正的机器是你自己。你的内在和外在并不是分离的,它们会亲近或者远离高质量。
  • 在扎卡里亚看来,不理性、不顾事实和不管谁受伤害,都要不惜一切代价迅速赚钱的意愿导致了这样的结果。
  • “聪明之道无他,学会忽略一些事情而已。”
  • 例如,他们想知道,公司能否通过提供优质的产品、低廉的价格和高效的服务来增进与客户的关系?CEO是否为提高公司的长期价值合理地配置了资本?公司是否向员工支付了低工资、虐待了供应商、辜负了客户的信任,或从事了任何其他可能危及其最终成就的短视行为
  • 斯利普和扎卡里亚对这种趋向短期主义的转变感到震惊。“我们一辈子都搞不懂投资者为什么每隔几个月就会换股,这对整个社会有什么好处呢?”斯利普写道:“当投资者总是在改变主意时,这个社会的基本架构就会被打破。”游牧者将通过迥然不同的方法取得成功。斯利普说:“《圣经》有云,你想把房子建在岩石上而不是沙土上,你想建造持久坚固的房子。”
  • 考虑到当时的机会,游牧者投资以低价出售的企业是合理的,但这种策略有一个缺陷:当这类股票的价格反弹、变得不再便宜时,他们不得不卖掉它们,并寻找新的便宜股。但是,当他们试图重新分配资金时,如果没有特别合适的企业在售呢?对于这种再投资风险,一个明显的解决方案是购买并长期持有优质企业的股票,这样更有可能在未来多年内持续获利。
  • 斯利普和扎卡里亚开始寻找其他由具有远见卓识的管理者经营的企业,他们相信,随着时间的推移,持有这些企业的股票能不断积累财富。斯利普说:“如果管理者能理性思考,目光长远,你可以把资本配置决策交给他们做,你自己就不必再买卖股票了。”他们也开始思考哪些特征能解释公司的成功保质期异常长的原因,最终他们得出了一个很有启发性的结论:有一种商业模式可能比其他模式更强大,他们把它称为共享的规模经济(scale economies shared)。
  • 这类公司的文化通常是由具有远见卓识的创始人而非雇员塑造的,他们往往重视微小的细节、客户体验的改善,在经济繁荣时期也重视降低成本,而且,即使当前面临着公布强劲数据的外部压力,他们也会为遥远的未来进行投资。斯利普说:“他们都是非常反传统的。”这些传奇人物包括沃尔玛的山姆·沃尔顿、开市客的吉姆·西格尔(Jim Sinegal)、西南航空的赫伯·凯莱赫(Herb Kelleher)和内布拉斯加州家具市场的罗斯·布卢姆金(Rose Blumkin)。布卢姆金是俄罗斯移民,从6岁起一直工作到了她过完100周岁的生日,她忠实地遵循三大原则:“价廉、说实话、不欺骗任何人”,一手打造了美国规模最大的家居用品企业。
  • “以低价的形式将效率提升和规模经济带来的好处返还给客户创造了良性循环,从长期来看,这将导致更多的自由现金流。”
  • 在我看来,我们可以从斯利普和扎卡里亚的经历中得到5点启示。
    第一,他们的经历让我们明白了在商业、投资和生活中以追求高质量为指导原则意味着什么。这是他们受《禅和摩托车维修艺术》一书的启发形成的道德和智慧理念。人们很容易把“质量”视为一个模糊和主观的概念,但它为许多决策提供了一个极为有用的筛选标准。例如,斯利普和扎卡里亚显然认为,只收取足够游牧者保持运营的低年度管理费是一个更高质量的选择,无论他们的业绩如何,这一选择都会使他们变得富有。
    第二,我们要铭记这一思想:关注保质期长的因素,不要太在意昙花一现的因素。他们在选择信息时运用了这一原则,在选择拟投资的公司时也运用了这一原则。
    第三,我们能认识到,规模经济共享这种特殊的商业模式创造了一种良性循环,能够在长期内创造可持续的财富。斯利普和扎卡里亚利用这一真知灼见,通过聚焦于运用类似模式的高质量企业,获得了巨额的利润。自相矛盾的是,他们还认为,持有少量股票(通常约为10只)的风险比持有数百只股票的风险要小——多样化是标准的策略,必然会导致平庸的回报。“我们知道,我们不了解很多事情。”斯利普说,“所以对我们来说,只持有某些公司的股票是合理的,因为我们真正了解它们。”
    他们最了解、最喜爱的企业是亚马逊、开市客和伯克希尔,这并不奇怪。即使在新冠疫情把全球搞得天翻地覆时,这些企业也展现出了非凡的韧性。毕竟,它们的规模经济能使它们为客户提供超值的服务。“特别是亚马逊和开市客,在危机中它们的业务量反而增加了。总体而言,环境对经济的影响越大,这些企业的成本优势就越大。”
    第四,即使是在自私行为是常态、生性贪婪的资本主义企业里,也没有必要为了取得惊人的成功而做出不道德或肆无忌惮的行为。在金融危机期间,斯利普写文章讨论了“玩家为获胜可不择手段”的文化造成的破坏性影响,他和扎卡里亚希望游牧者能体现出一种更加开明的资本主义文化。
    这就解释了他们实施利于股东而非自己的收费方案的原因。他们对彼此也很慷慨,例如,扎卡里亚坚持认为斯利普应该拥有投资公司51%的股份,而不是与自己一样;出现分歧时,扎卡里亚相信斯利普做出的最终决定。斯利普说,虐待一位“把装上子弹的左轮手枪扔到桌子对面后说:‘来吧,如果你愿意,你可以开枪打我!’”的搭档是不可想象的。他补充说,“我们的关系非常好,这对我们的成功很重要”,在关闭基金公司几年后,他们仍然共用一间办公室,从中可知二人的关系。正如斯利普所说,“良好的行为有较长的保质期。”
    极为重视慈善也是他们践行温和的资本主义文化的一个显著特征。“在确认了我们想经营游牧者基金的那一刻,我们俩都很清楚,我们的工作就是把钱返还给社会。”斯利普说,“这样的想法降低了我们因钱太多而变得焦躁不安的风险。”他补充说:“散财也让人快乐。”
    扎卡里亚和妻子莫琳资助了一系列面向科学和医学研究的慈善机构,包括伦敦数学实验室、皇家学会和皇家神经残疾医院等。而斯利普则将大部分时间用于帮助一家名为边远青年社区的慈善机构,该机构为贫困地区的孩子提供了一个安全的避风港,旨在提高他们的社交能力并学习新技能。他说,他和扎卡里亚的核心工作已经转变为“尽最大努力做从长期来看最有意义的善事”。
    斯利普并没有放弃所有世俗的乐趣。他喜欢赛车,有时会驾驶着1965年的谢尔比野马GT350和1967年的洛拉T70参加比赛。他还与女儿杰西轮流驾驶着1964年的梅赛德斯宝塔参加了一场从北京到巴黎(经由蒙古和西伯利亚)的拉力赛,历时36天。
    第五,在一个短期主义和即时满足日益盛行的世界里,那些一贯朝相反方向前进的人可获得巨大的优势。这一点不仅适用于商业和投资领域,而且适用于人际关系、健康、职业以及其他一切重要的领域。

第七章 高绩效习惯

  • 所有这些都指向了一个重要的结论,它既适用于投资,也适用于生活,即巨大的胜利往往是持续的小进步和提高长期累积的结果。“成功的秘诀就是,每一天都比前一天做得好一些,”盖纳说,“你可以采用不同的方法,但事情就是这样……不断进步才是关键。”
  • 第一,他寻求的是“资本回报率高、杠杆率低的盈利性企业”;第二,企业的管理团队必须“德才兼备”;第三,公司应该有充分的机会将利润进行再投资并获得可观的回报;第四,股票价格“合理”。
  • 在进行任何投资之前,他都会问自己这个关键的问题:“如果我判断错了,结果会怎样?”然后他会权衡自己的押注,这样无论发生什么,结果都不会是灾难性的。“不要犯致命的错误。”冈德拉奇对我说,“这是长寿的根本,说到底,企业要成功,首先得长寿。
  • 盖纳的经历表明,从长期来看,你不需要做到极致就能获得超乎寻常的结果。他说:“做到极致反而会让人陷入麻烦。”他追求的是一条温和的道路,历史上最睿智的思想家也赞同这一做法,如孔子、亚里士多德、佛陀和迈蒙尼提斯。
  • 约2400年前,古希腊哲学家亚里士多德指出,卓越和持久的幸福取决于我们践行“中庸之道”的能力——就食物、酒和性等生理享受而言,我们应该在过度放纵和禁欲之间找到一个平衡点。同样,面对风险,他建议在胆怯和鲁莽这两个相互对立的极端之间谨慎行事,他说:“逃避一切、恐惧一切、对任何事情都无坚定立场的人是懦夫,无所畏惧地去迎接一切危险的人是莽夫。”
  • 他积累财富时采用的“令人满意、缓慢、稳定的”方法在很大程度上以常识和精心培养的习惯为基础,而不靠深奥的技能或大胆的冒险。当我问他,普通投资者为了致富应该怎么做时,他给出了一个最无新意的建议:“花的要比赚的少,用余钱进行投资并获得正收益。能做到这两点,你就不可能失败。”他又补充说:“如果你赚得多花得少,你很快就会变富有。”
  • 盖纳说:“你无法控制结果,你只能控制自己的努力和奉献,而且不管发生什么,都要全力以赴地完成手头的任务。”
  • 单个来看,这些做法都不是惊天动地之举,但请记住:积微成著,它们的复合效应是巨大的。此外,明智的习惯所产生的微小好处会在多年里持续积累。从短期来看,这些微小的进步似乎微不足道,但时间是坏习惯的敌人,也是好习惯的朋友,年复一年,十年又十年的积累效果是惊人的。事实上,让盖纳脱颖而出的正是他的这一重要特质:持久不变,始终如一。
    好的一点是,我们不需要学习什么秘诀,也不需要多高的智商,我们需要的是培养一个能让我们不断积累微小优势的、方向正确的和可持续的明智习惯。盖纳引领着我们踏上了正确的轨道,现在让我们看看,卓越的投资者还利用了其他哪些高效的习惯来使自己保持长期优势。
  • 比尔·米勒刚入行时曾向林奇求教,林奇告诉他,无论是从经济层面还是从智力层面来看,投资业的回报都是很丰厚的,因此吸引了过多的聪明人进入。林奇说:“战胜他们的唯一方法就是比他们更努力,因为你不会比其他人聪明多少。”林奇告诉米勒,他多年来保持领先地位依靠的是:早上6:30乘车去办公室,晚饭后和周末工作,多年不休假,多阅读投资研究报告。当米勒问,随着年龄的增长,林奇是否会放慢节奏时,林奇回答说:“不会,在这个行业里,只有两个挡位,一个是超速挡,一个是停车挡。”米勒对此表示同意,他说:“这一说法基本正确,你必须全速前进。”
  • 本章提及的所有投资者都有一个共同的习惯:他们几乎只关注自己最擅长的领域和对自己最重要的事务。他们的成功源于对这一原则的坚守:专注于一个相对狭窄的领域,忽略无数干扰他们追求卓越的因素。
  • 早在几千年前,道家学派创始人老子就曾说过,通往智慧的道路包括“减去”一切不必要的活动,他写道:“为学日益,为道日损(译文:求知要不断地增加,求道却要不断地减少)。”
  • 做减法的艺术无比重要,特别是在信息过载的时代,我们的思考很容易变得碎片化。倘若不加甄别,乱七八糟的政治新闻、社交媒体通知、机器人通话和其他破坏性噪音就会进入你的大脑。
  • 其他人的注意力越是分散,你因排除了精神混乱、技术干扰和过度刺激而得到的优势就越大。

第八章 不做蠢事

  • 尽管如此,我还是事先为我们的短暂交流做足了准备。当我仔细研究他几十年来的演讲、著作和其他的思想感悟时,我开始意识到,芒格一直以来的做法是:降低自己“愚蠢地思考”“愚蠢地做事”“犯非原创性错误”和“做常见傻事”的概率,我们所有的人都应该效仿他的做法。
  • 芒格逆向解决问题的方法受到了卡尔·古斯塔夫·雅可比的影响,后者是19世纪的一位数学家,他有句名言是“倒过来想,一定要倒过来想”,但芒格告诉我,在朋友加勒特·哈丁(Garrett Hardin)的帮助下,他养成了倒过来想的心理习惯。哈丁是一位生态学家,对劣质思维的可怕后果颇有研究。芒格说:“哈丁的基本想法是,当有人问你应该如何帮助印度时,你只要说,‘要毁灭印度应该做什么呢?’然后你想清楚你能做什么,之后你倒过来说,‘现在,我不会这么做。’这种做法违反直觉,但它确实有助于你解决问题,是一种考虑更周全的方式。”
  • 蒂林哈斯特是一位腼腆胆小的数学天才,目前管理着400多亿美元的资产。他制定了大量的防御性原则并加以践行,业绩超越了几乎所有的竞争对手。他说,首先,“不要支付太高的价格,不要选择那些容易遭淘汰和打击的企业,不要跟骗子和白痴一起投资,不要投资你不懂的领域。”
  • 我们大多数人都不愿意向公众提及自己犯过的错误,我们也不想承认它们,但在芒格看来,他越是公开透明地审视自己的错误,他就越不可能重蹈覆辙。他曾对伯克希尔的股东们说:“我喜欢人们承认自己是十足的蠢货。我知道,如果我能直面自己的错误,我会表现得更好。这是一个很棒的学习技巧。”事实上,这是我们为防止在职场中做出蠢行必须向他学习的第三个技巧。
  • 这些典型的市场蠢行进一步强化了马丁在海军服役时得到的启示:没有什么比避免犯灾难性的错误更重要了。在之后的几十年里,他一次又一次地观察到了这一规律:掉以轻心会招致不必要的灾祸。
  • 他的“风险管理黄金法则”很简单,即“知道自己拥有什么”。
  • 马丁与他人合著了《本杰明·格雷厄姆成长股投资策略》(Benjamin Graham and the Power of Growth Stocks)一书,他在这本书里告诫投资者:“你可能搞砸了投资,问题是,你能很快复原吗?”“格雷厄姆的安全边际理念能助你‘控制’错误,这样你就不会犯太大的错误,你也就能很快恢复元气了。”
  • 只有在价格足够便宜且预计在未来7年内能够获得高回报的情况下,马丁才会买入一只股票。对于中盘股,他设定的最低回报率为12%,对于风险较大的小盘股,他设定的最低回报率为15%。为什么要这么做?只有设定了这些标准化的要求,他才会在股票价格足够便宜时系统性地买入。正如马丁在海军服役时所学到的,“按程序走”是必不可少的保障:“永远尊重它,因为它能让你远离麻烦。”采用标准做法和严格遵守规则是我们减少蠢行的第四个技巧。巴菲特和芒格可能不需要正式的标准或规则来约束自己,但你我不是他们。
  • 芒格整理出了“标准的思维错误”,为他也为我们提供了一份实用的思维陷阱清单。“要注意的是,首先要理解它们,然后训练自己摆脱它们。”斯利普说,“说起来容易做起来难,这是一项艰苦的工作。”但这么做很有必要,因为人“最持久的优势是心理优势”。
  • 芒格打了个生动的比方,他说:“当一个精子进入卵子体内时,卵子会自动启动关闭装置以阻止其他精子进入。人类的思维也有这样的倾向。”不愿重新审视我们的观点和改变我们的想法是理性思考的最大障碍。我们的心态不够开放,我们会有意或无意地优先考虑那些能强化我们信念的信息。
  • 盲目地坚守固有信念的错误可能会因其他几种心理倾向而加剧:自视过高倾向会导致我们高估自己的才能、观点和决定;过度乐观倾向诱使我们对财务问题粗心大意,尤其是当一切顺利、我们感觉自己很聪明时;简单的、避免痛苦的心理否认会导致我们在“现实太痛苦而无法承受”时歪曲事实,这都有助于解释为什么有那么多的投资者自欺欺人地认为,尽管他们缺乏必要的技能、素养或成本控制,但从长远来看,他们能跑赢指数基金。芒格很喜欢引用古希腊演说家德摩斯提尼的这句话:“没有比自我欺骗更容易的事了,人总是相信他愿意相信的东西。”当人类的大脑耍花招时,我们怎样才能作出理性的投资决策呢?首先,我们要承认,这种隐伏的威胁是存在的。正如格雷厄姆所言,“投资者主要的问题,甚至他最大的敌人,很可能就是他自己。”
    我们还要警惕自己独特的心理倾向,它会使我们的判断偏离可预测的方向。担忧这一点的霍华德·马克斯对我说:“当你的思维被一厢情愿的想法牵制时,你的判断就会偏向于这些想法……当你感到恐惧时,你会倾向于做出消极的判断……没有人说,‘这是我的预测,它可能是错的’,但你必须对自己说,‘这是我内心期待的结果,我必须意识到它可能被我的情感偏见所影响’,你必须抵制它。对我来说,这意味着当事情变得棘手时我不能退缩。”
  • 和芒格一样,舒宾·斯坦因倡导以“科学的方法”进行投资分析。这意味着要持“反证心态”,尽力“反驳”你的假设,看看“它是否经得起攻击”,舒宾·斯坦因最喜欢的一个问题是:“为什么我可能是错的?”
  • 科学文献表明,饥饿、愤怒、孤独、疲倦、痛苦和压力是常见的“导致糟糕决策的因素”,因此舒宾·斯坦因用这些因素的首字母缩略词“HALT-PS”提醒自己:当它们可能影响他的判断时,他要停下来,将重要的决策延后,直到他的大脑恢复正常状态。这是我们避免做蠢事的第七个技巧。
  • “我们知道,有4种行为可以促进大脑健康和增强大脑功能,”舒宾·斯坦因说,“它们是冥想、锻炼、睡眠和补充营养。”他决心利用一切可利用的工具锻炼身体,这使他睡得更香了。他吃了更多的鱼、蔬菜和水果,放弃了“最坏的倾向”,包括无节制地吃香草冰激凌和捣碎的巧克力曲奇的习惯。他还养成了定期冥想的习惯,对许多成功的投资者来说,这一习惯至关重要。

尾声 财富之外

  • 索普原来是一位数学教授,收入微薄,后进入了投资行业。他很享受投资成功带给他的奢侈享受。当我问他是否有特别喜欢的物品时,他笑着回答说:“我真的很喜欢我的特斯拉,它太好玩了,是最棒的车。”尽管如此,他却从来不认为,当他拥有了更多的钱、更多的房子、更多的汽车、更多的一切时,他会变得更幸福。“与什么人共度时光可能是人生中最重要的事情。”索普说,他的结发妻子在他们结婚55年后去世,后来他再婚了。“一直积累财富的人不明白这一点,他们最终得到了很多东西,但他们一生都忙于追逐它们。”
  • 米勒的故事给了我两点珍贵的启示。
    第一,每个人都会承受痛苦。当我在痛苦中挣扎时,一想到米勒、卡普、帕伯莱和我采访过的其他富人或名人都曾经历过痛苦,我就会感到心安一些。记得亚历山大的斐洛(Philo)说过这么一句话:“要善良,因为你遇到的每个人都在经历某种痛苦。”没有人能一帆风顺,有时我们需要从哲学、精神、家庭、朋友或其他任何地方寻求支持。如果我们想以财富摆脱精神痛苦,那我们注定会失望。
    第二,不屈不挠是一种崇高的美德。几年前,正遭受痛苦折磨的我给帕伯莱写了一封信,当时他在多个方面都面临着巨大的挑战,包括他持股最多的马头控股公司(Horsehead Holdings)破产了。他回复说:“马可·奥勒留是我心目中的英雄。我们不知道灾祸何时来临,但面对逆境是好事,它会使我们变得更加强大。”帕伯莱无敌的乐观主义精神让我想起了《沉思录》中的一句话:“当有什么事情令你感到痛苦时,记住这一原则:事情本身不是厄运;忍受并战胜它却是一大幸事。
  • 多年以来,他一直在思考这些问题:阿姆斯特丹的那位少女为什么要救他,她怎么会为了救“陌生人”而“愿意牺牲自己的生命”?她的父母怎么会允许她做这么危险的事情?范登伯格的精神科医生告诉他:“很简单。当你的生命比你的原则更重要时,你就会牺牲你的原则;而当你的原则比你的生命更重要时,你就会牺牲你的生命。”范登伯格说,这一见解“对我产生了深远的影响”。
a computer screen with a remote control on it

ACME.sh 续签不成功下的 Debug 记录

我的域名证书目前基本上 100% 使用 acme.sh,免费大碗,唯一的问题是需要续签。对于一些涉及到 CDN 场景的可能不太友好。不过我的 CDN 往往也不太使用主域名,所以也可以接受。

最近在给一个域名续签的时候,出现了报错的问题

续签代码:

 "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh"
Code language: JavaScript (javascript)

报错如下:

[Sun Aug 13 06:02:43 PM CST 2023] Renew: 'replace.com'
[Sun Aug 13 06:02:43 PM CST 2023] Renew to Le_API=https://acme.zerossl.com/v2/DV90
[Sun Aug 13 06:02:43 PM CST 2023] Using CA: https://acme.zerossl.com/v2/DV90
[Sun Aug 13 06:02:44 PM CST 2023] Multi domain='DNS:replace.com,DNS:feishu.io'
[Sun Aug 13 06:02:44 PM CST 2023] Getting domain auth token for each domain
[Sun Aug 13 06:02:48 PM CST 2023] Getting webroot for domain='replace.com'
[Sun Aug 13 06:02:48 PM CST 2023] Getting webroot for domain='feishu.io'
[Sun Aug 13 06:02:48 PM CST 2023] Verifying: replace.com
[Sun Aug 13 06:02:49 PM CST 2023] Processing, The CA is processing your order, please just wait. (1/30)
[Sun Aug 13 06:02:53 PM CST 2023] replace.com:Verify error:"error":{
[Sun Aug 13 06:02:53 PM CST 2023] Please add '--debug' or '--log' to check more details.
[Sun Aug 13 06:02:53 PM CST 2023] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
[Sun Aug 13 06:02:55 PM CST 2023] Error renew replace.com.
Code language: JavaScript (javascript)

在出现问题之后,可以通过在命令中添加 --debug 的方式,来实现查看响应的日志,debug 的命令如下:

 "/root/.acme.sh"/acme.sh --cron --debug --home "/root/.acme.sh"
Code language: JavaScript (javascript)

则在新的输出中,说明了我具体卡在哪里了

[Sun Aug 13 06:04:49 PM CST 2023] replace.com:Verify error:"error":{
[Sun Aug 13 06:04:49 PM CST 2023] Debug: get token url.
[Sun Aug 13 06:04:49 PM CST 2023] GET
[Sun Aug 13 06:04:49 PM CST 2023] url='http://replace.com/.well-known/acme-challenge/rm-enWjHphDeyjXtfXu2mi1V-D6cZY8EHAe_Gi7TmC4'
[Sun Aug 13 06:04:49 PM CST 2023] timeout=1
[Sun Aug 13 06:04:49 PM CST 2023] _CURL='curl --silent --dump-header /root/.acme.sh/http.header  -L  --connect-timeout 1'
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
[Sun Aug 13 06:04:49 PM CST 2023] ret='0'
Code language: HTML, XML (xml)

acme.sh 的报错非常清晰,我的报错是因为我的文件目录中 /.well-known/ 中的验证文件找不到了,所以报错。那我只需要去检查我的 Nginx 配置即可。这里因为我的 Nginx 配置根目录不在默认指明的目录(因为用了 Docker ,nginx 只是一个代理),所以我需要将其修改为真正的 webroot。

修改 ~/.acme.sh/replace.com/replace.com.conf 中的 Le_Webroot 配置为真实的 webroot,再重新签名,就域名成功签名了。