MoreRSS

site iconlklog | 龙鲲修改

马拉松爱好者,喜欢捣腾新鲜的事物。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

lklog | 龙鲲的 RSS 预览

湖南联通智家AI云套餐畅越版详细评测(49元千兆宽带2张免费副卡1000分钟通话)

2026-10-20 19:11:09

本文于 2026年10月20日 8:53 更新,注意查看最新内容

前言

今天看到消息,说湖南移动的全民百G业务下架了,然后去核实了一下,当时好像还有部分渠道可以线上办理,资费专区的公示也还在,就没太在意,后来看到移动的公告信息,才确认这个业务彻底下架了。

(公告链接:https://www.10086.cn/aboutus/news/pannounce/hn/index_731_746_detail_56014.html)

其实早在上个月,在互联网上就看到了类似的消息,说这个业务要下架,结果一直也没下架了,以为会按照公示信息延续到年底,结果今天就看到下架的消息,只能说参加活动要趁早,以免夜长梦多。

今天这个联通智家AI云套餐畅越版互联网上其实流传有一段时间了,只是一直没时间去写一个详细的评测,当时也就是互联网上浏览消息,说可以办理这么一个套餐,感觉性价比挺高的,于是就尝试了一下,确实是可以的,这里记录具体过程,以备日后查阅。

简析

因为这个套餐有很多档位,本文主要评测的是99元档位(资费标准:99元/月),也是互联网流传比较广的一个档位,个人觉得也是这个套餐性价比比较高的一个档位。

该套餐的名称全称叫:联通智家AI云套餐畅越版99元-湖南(方案编号:25HN300486)。

套餐内含有一条免费宽带,下行速率1000Mbps,也就是我们常说的千兆宽带。

99元档语音为1000分钟,通用流量为30GB,可免费办理2张副卡。

套餐原本资费为99元/月,办理湖南AI云套餐老用户5折优惠包后(方案编号:25HN301819),实付49.5元/月。

PS:资费专区也有新用户办理该套餐的优惠活动,具体自行联系官方客服了解,不清楚是否还能够参加。

1000M宽带

安装使用该宽带前的准备:

1.查看是否为千兆光猫(光猫背面有具体型号,通过具体型号搜索即可)。

2.查看所有网线是否支持千兆宽带。

部分用户是通过光猫连接路由器,再从路由器连接电脑,这种情况会使用两根网线,任意一根网线不支持千兆宽带都无法跑满下行1000Mbps。简单的分辨技巧就是通过线身上的标识进行查看,例如CAT5 E、CAT6、CAT7和CAT8,这些都是支持千兆宽带的。

3.查看路由器是否支持千兆带宽(路由器背面有具体型号,通过具体型号搜索即可)。

PS:该宽带上行速率仅40Mbps,默认情况下有极大几率跑不满,如果发现下行达标的情况下,上行不达标,可以联系客服,让宽带维修师傅上门处理。

宽带安装地址的要求:

简单来说就是,一个长沙的号码办理了该套餐,那么该宽带就只能安装在长沙,并且是资源覆盖区域(一般都是)。

宽带安装之后的测速:

因为现在有测速需求的人越来越多,但测速的产品却不增反减,早年间运营商官方都提供网页端的测速功能,现在基本上找不到,根据我自己的实际测试,推荐测速的平台有:

测速网(https://www.speedtest.cn/):支持多端测试,但由于使用人数较多,千兆宽带高峰期基本跑不满。

全球网测APP(应用市场下载):中国信息通信研究院研发产品,仅支持APP端,实测WIFI 5G频段可以跑满千兆。

高校测速:这里以中国科学技术大学测速网站(https://test.ustc.edu.cn/)为主,类似的还有南京大学测速站(https://test.nju.edu.cn/)、南京航空航天大学测速网站(https://speed.nuaa.edu.cn/)等,实测也很难跑满。

至于其他的,网页端还有SPEEDTEST(没有国内节点,很不稳定),speedtest.im(没有自己的测速节点,容易弹下载链接),APP端还有花瓣测速(非华为手机无法直接安装),基本都很难稳定跑满千兆。

除了专门的测速工具,其实还可以变相测出峰值网速,就是开启设备网速显示后,通过下载大文件(游戏、视频等)来测试此时的最高网速,一个大文件跑不满,同时多下载几个大文件,一个平台跑不满,多用几个平台,毕竟带宽的网速还是要应用在体验上的,这样也会更加直观。

已安装宽带注意事项:

若主卡下本身已安装宽带,记得在新套餐生效后在中国联通APP查看宽带速率是否更新,若未更新记得联系官方客服处理。

语音1000分钟

套餐内每月含有1000分钟语音通话,主副卡共享。这个语音不算多,但在折后这个价位也不算少,如果没有特殊需要,一般家庭都是够用的。即使超出,套外国内语音电话拨打也只需要0.15元/分钟 。

通用流量30GB

这算是这个套餐唯一的短板,其中套内流量15GB,赠送流量15GB,共两个包,主副卡均可共享,超出后国内流量3元/GB。目前没看出分成两个包的意义在哪,可能涉及结转或者流量使用优先级等问题,但使用这个套餐的人应该是没有太多流量需求的,不然会比较的不划算。

2张免费副卡

套餐自动减免2张副卡费用,联通正常一张副卡的费用在10元/月,而这个套餐可以自动减免两张副卡的费用,本身套餐折后就只要49.5元,减免两张副卡后,折算下来的费用就非常的低了。

PS:如果原有主卡下就有一张副卡,更换为该套餐后,原有副卡费用会自动减免。如果家人(非同一实名)有联通套餐,可以在更换套餐时一并纳入副卡,既减免了基本套餐费用,也可以共享主卡通话和流量。

2T云盘

套餐自带2T联通云盘,上传下载均不限速,实际测试下来送的是联通云盘尊享会员,官方资费是10元/月,而且不同于活动赠送的联通云盘会员,这个属于营业厅订购的云盘会员,可以额外领一个热门权益N选1,热门权益大部分都是定制过的内容,和原版会有些出入,例如云影院功能,它的影片资源是由5G宽视界提供,虽然不能搜索,但它提供最近几个月热门影片的正版资源和很多高分的影片,个人感觉比那种放N年前影视资源的权益要好很多。

办理

办理其实没有太多技巧,就是打联通客服电话或者联系在线客服,说自己要办理联通智家AI云套餐畅越版99元,还有5折优惠包,这时候在线客服一般会帮你反馈专员,电话客服会说自己最高权限只有多少折,你继续表示你要办理5折优惠包,她就会帮你反馈给专员,然后等待专员回电即可,如果回电专员仍然无法支持你的诉求,就要求联系携转专员。

这个套餐和折扣优惠包的出现有一段时间了,互联网上有很多办理成功的分享贴,加上最近湖南移动的全民百G活动,以及湖南电信星卡40G流量包的加持,基本上没有太大难度,毕竟它的短板也很明显,就是流量非常少,当然你可能会看到本套餐+折扣优惠包带流量包和权益包的截图,但那个目前是办理不了的,基本可以不用尝试。

总结

个人觉得这个套餐方案目前还是比较有性价比的,特别适合家里有老人,对流量要求没那么高的用户,虽然流量少,但是也有30GB,偶尔出门应急绰绰有余,不至于一用流量就扣话费,如果对流量有需求,可以适当增加档位,看联通客服是否有相应流量包添加,但即使有流量也不会太多,加上还有两张副卡,流量需求高的情况下,该套餐方案不适合,另外该套餐方案没有合约限制,套餐和优惠都是长期有效。

湖南联通智家AI云套餐畅越版详细评测(49元千兆宽带2张免费副卡1000分钟通话)最先出现在龙鲲博客。

如何开发一个权威信息搜索Skill(附免费领华为云200元券)

2026-10-16 16:51:43

本文于 2026年10月16日 7:06 更新,注意查看最新内容

前言

接触Ai之后,频繁看到Skill这个词,但每次都是浅尝辄止,稍微了解了一下就没深入了,这次趁着2026华为开发者大赛·小红书Skill创新赛,详细了解了一下Skill是什么,并且编写了自己的第一个Skill,这里记录详细的开发过程,以备日后查阅。

需求

目前主要获取信息的渠道还是搜索引擎,但由于搜索引擎的权重等问题,有时候即使提炼关键词后,搜索的结果仍然不尽人意,需要查找许久才能找到需要的信息,这时候如果搜索的是政务类、教育类的信息,会使用搜索语法来限制搜索范围,但使用搜索语法每次都要手动输入语法,并且人为进行筛选,效率比较的低,需要编写一个Skill,代替人为筛选网页。

原理

在我国互联网域名体系下,根据不同的用途,在.CN域名下设置专门的二级域名,例如政府机构GOV、教育机构EDU、科研机构AC。此时通过通用搜索语法,限制在该二级域名下搜索,就能保证搜索到的网页权威可靠。例如:关键词 site:gov.cn,则代表在所有政务类的网页中进行查找;关键词 site:edu.cn,则表示在所有教育机构(仅限使用edu.cn域名的教育机构,极少教育机构未使用该域名)的网页中进行搜索。

开发

有了需求和手动实现流程的原理,我们通过华为云码道智能体 https://codearts.huaweicloud.com/ 发送我想编写一个Skill,这时就会进入Skill开发流程,根据智能体的提问进行回答,就可以一键进行开发了。

开发完成后,我下载整个Skill安装包,导入到了我常用的智能体中进行测试。在测试的过程中,我发现不是这里缺个环境,就是那里缺个工具,导致智能体一直都在装东西。

这和我的初衷肯定是不符的,我的想法是在任意智能体中导入该Skill就能直接进行搜索,而无需安装太多工具,于是我果断中止了执行,回到了智能体平台进行升级迭代。方法也很简单,就是用自然语言描述你的需求,例如我不想让Skill依赖某个工具,就可以说让它不依赖即可。

一番等待后,Skill再次被开发好,我开始进行第二次真实环境测试。在测试的过程中,我又发现了问题,不再依赖工具执行的搜索语法似乎没有有效执行,导致其有效链接为0,也就是说搜到了一堆网页,拿到了一堆链接,但没有一个是权威渠道的来源。

这时我在想是不是这种方式的搜索本身就无法正常调用搜索语法,我开始思考解决问题的方法,突然我看到了每个智能体都有的联网搜索功能,意识到似乎每个支持导入Skill智能体本身都有自己内置的联网搜索,那么我完全可以以内置搜索结果为主,以搜索引擎结果为辅来实现我的搜索需求。

于是我再次将我的需求发送给了智能体,因为考虑到各家智能体不一样,导入该Skill后能否都调用内置搜索功能尚未可知,还特别强调了通用性的问题。开发完成后,实际测试所有引用网页、PDF链接均为官方权威信息(gov.cn、edu.cn等),至此这个简单的Skill便开发完成。

通过这个简单的Skill开发,让我再次深刻明白原理的重要性,知其然知其所以然,才能真正带来便利,也明白了万事万物永远在动态的发展变化,问题一直会有,但也终有解决问题的办法。

如果你也想尝试开发属于自己的Skill,欢迎参加2026华为开发者大赛·小红书Skill创新赛 https://developer.huaweicloud.com/competition/information/1300000350,现在报名就送200元华为云无门槛云资源券,云资源领取:https://developer.huaweicloud.com/competition/information/1300000350/html1 (切记先报名才能领券)。

 

如何开发一个权威信息搜索Skill(附免费领华为云200元券)最先出现在龙鲲博客。

虚惊一场的盗号风波:一直收到验证码怎么办

2026-10-03 22:38:23

本文于 2026年10月3日 10:38 更新,注意查看最新内容

昨天下午的时候,因为需要用到备用手机号登录A平台,于是看了一眼备用机的短信,发现备用机收到了很多来自B平台的验证码,大概有二三十条。

因为最近在写一个B平台的小工具,以为是AI在编写的过程中,触发了平台风控,所以也没太在意。

一直到晚上,我随手看了一眼备用机,发现手机一直在接收来自A平台的验证码,这时我意识到事情有点不太对劲,一瞬间各种盗号的新闻案例在脑子中开始浮现,于是随即着手进行排查和防范。

当时排查的方向有如下几个方面:

1.浏览器有问题,使用的插件存在恶意代码。

2.电脑有问题,使用的软件存在后门。

3.网络有问题,使用的宽带被攻击了。

我先查看了浏览器的插件,大部分的插件都是直接通过Edge的官方市场直接安装的,小部分插件是开源的项目以及二开或者自用的,一圈排查下来,看不出来太多问题,加上虽然浏览器登录过A平台,但浏览器中A平台的账号与一直收到短信验证码的手机号并非同一个账号。一直收到短信验证码登录的A平台是PC端,如果浏览器插件存在问题,很难影响到PC端软件,除非浏览器出现了什么漏洞,但一般这种级别的漏洞,辐射范围非常广,在我之前大概率已经有人中招,我查了一下,没有查到相关资料,所以基本上就排除了浏览器插件问题。

这时我想看下网上有没有类似的情况,于是就打开了社交软件,搜索关键词:一直收到短信验证码。看了几篇分享,也没看到好的解决方案,但短信验证码仍然还在继续发送中,此时我决定先把一直在发送短信验证码的平台账号修改密码、清除所有历史登录设备,并且把能开启的安全措施都开启。

紧接着排查电脑方向的问题,首先就怀疑上了之前使用AI编写的B平台小工具,但转瞬就被我排除了,虽然该工具使用了开源项目,但在使用前,我已经让AI审查了所有代码,没有非B平台的数据请求。那有没有可能电脑中其他软件存在后门呢,我当时觉得是有可能的,虽然本地安装了火绒,但火绒的查杀能力比较的一般,于是想着安装卡巴斯基查杀一下全盘,结果安装不上,最后安装了360杀毒进行全盘扫描。

在这个全盘扫描的过程中,我开始考虑第三个方向,有没有可能是网络问题,这个也有一定可能,因为之前连只有一墙之隔的邻居家WiFi时出现过劫持现象(邻居家WiFi与我家宽带是同一个运营商,用的是同一个运营商的箱子,之前有时候我家没网的时候他家会有网,那时候连过邻居家WiFi),如果是网络存在问题,那连接过该网络下的设备中的账号应该都会出现类似问题,我看了好几个同网络下的设备,只有我的备用机出现了该问题,所以可能也不是网络的问题。

此时全盘扫描仍然还在进行中,看着已经扫出来的结果,基本都在可预测的范围之内,问题一直没有有效进展。这时我收到了一条C平台的短信验证码,让我无比震惊,因为之前不管是A平台还是B平台,由于我在多设备多端都有进行登录,其中的变量非常的多,很难确定到底是哪里出现了问题,但这一条C平台的短信验证码我非常确定,只在半小时前的PC端Edge浏览器中登录过,这说明这个“漏洞”几乎是实时获取的,而浏览器我已经排查过,电脑的问题还在查杀,我继续打开社交平台进行搜索,看有没有类似的分享,这时我发现了一条动态,说自己一直收到重复的验证码,我抱着试一试的想法,仔细查看了一下收到的短信验证码,发现部分短信验证码是一样的,再查看该条动态评论,经过仔细辨认,几乎可以确认我与他遇到的情况一致,然后我按照他提供的解决方案,将手机重启,现象不再出现,至此该事件完美解决。

直到事情解决,我仍然不清楚,这到底是怎么一回事,但根据已有的信息,如果你重复收到一模一样的短信验证码,并且该平台最近几天有在使用,且随着收到主动触发的短信验证码增加而增加重复收到的验证码,可以尝试将手机重启(开启飞行模式后关闭无效),看该问题是否继续出现,如果重启后,仍然收到非主动触发的多平台多条验证码,可以尝试打开移动数据,修改这些平台的密码并清除所有登录设备。

虚惊一场的盗号风波:一直收到验证码怎么办最先出现在龙鲲博客。

利用AI智能体+Cloudflare给任意网页制作即时RSS

2026-09-05 15:26:02

本文于 2026年9月5日 3:37 更新,注意查看最新内容

前言

最近在使用RSS的过程中遇到即时性的问题,发现很多不提供RSS的网站使用公共解决方案时,RSS内容更新都不够及时,对于想要把RSS作为主要获取信息来源的我来说非常的不方便,中间也尝试过一些方案,RSSHub就不用说了,虽然功能强大,但对于我这种不想要深度了解的人来说,始终满足不了我想要的效果,一键制作RSS的工具也使用过,例如RssEverything等,不是收费太贵,就是没法对非公开页面进行一键处理,直到最近看到篇帖子,于是来了灵感,按照帖子的思路举一反三,便有了本文的方案。

原理

利用AI智能体抓取已登录的Edge浏览器会话,然后将网页内容转换成RSS内容,再部署到Cloudflare Pages。

准备

一台Windows服务器/云电脑/24小时开机的电脑/云龙虾(MiMo Claw、Kimi Claw等)。

一个Cloudflare账号。

一个域名(可选)。

教程

1.设备安装AI智能体软件,这里推荐WorkBuddy,轻量不花钱也能用。

2.登录Cloudflare账号,获取帐户API令牌。

路径:管理账户-创建令牌-搜索权限组“Cloudflare Pages”-勾选Read和Edit权限-审核令牌即可。

3.将下列代码发给AI智能体学习后,告知其需要制作RSS的真实网页,并一起发送上方的API令牌。

"""
论坛 RSS 生成器 — 纯案例文件(已脱敏)
========================================
通过浏览器 CDP 协议复用已登录会话,自动化抓取论坛帖子列表,
生成标准 RSS 2.0 XML,并通过 CLI 工具部署到 Pages 服务。

适用场景:
  - 任意 Discuz! 系论坛版块的 RSS 订阅生成
  - 需登录才能访问的内容RSS化
  - 静态 Pages 托管 + CDP 抓取 的轻量方案

使用前请替换所有 <<PLACEHOLDER>> 为实际值。
"""

import asyncio
import json
import os
import sys
import urllib.request
import time
import subprocess
import tempfile
import shutil
from datetime import datetime
from email.utils import format_datetime


# ═══════════════════════════════════════════════════════════════════════
# 配置区 — 按需修改
# ═══════════════════════════════════════════════════════════════════════

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
LOG_FILE = os.path.join(SCRIPT_DIR, "rss_log.txt")

# Pages 服务配置
PAGES_API_TOKEN = "<<YOUR_PAGES_API_TOKEN>>"          # API 令牌
PAGES_ACCOUNT_ID = "<<YOUR_ACCOUNT_ID>>"               # 账户 ID
PAGES_PROJECT_NAME = "<<YOUR_PAGES_PROJECT_NAME>>"     # Pages 项目名称
PAGES_DOMAIN = "<<YOUR_PROJECT.pages.dev>>"  # Pages 域名

# 文件路径(使用随机字符串防止猜测)
SUBDIR_L1 = "<<RANDOM_PATH_LEVEL1>>"      # 第一层随机目录
SUBDIR_L2 = "<<RANDOM_PATH_LEVEL2>>"      # 第二层随机目录
RSS_FILENAME = "<<RANDOM_FILENAME>>.xml"  # 随机文件名
RSS_DEPLOY_URL = f"https://{PAGES_DOMAIN}/{SUBDIR_L1}/{SUBDIR_L2}/{RSS_FILENAME}"

# 目标论坛配置
FORUM_URL = "<<TARGET_FORUM_URL>>"          # 目标版块URL
FORUM_TITLE = "<<FORUM_TITLE>>"             # RSS频道标题
FORUM_LINK = "<<FORUM_BASE_URL>>"           # 论坛主页链接
FORUM_DESC = "<<FORUM_DESCRIPTION>>"        # RSS频道描述
BASE_URL = "<<FORUM_BASE_URL>>"             # 论坛根URL


# ═══════════════════════════════════════════════════════════════════════
# 日志工具
# ═══════════════════════════════════════════════════════════════════════

def log(msg: str):
    """统一日志输出:终端 + 文件"""
    ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    line = f"[{ts}] {msg}"
    sys.stdout.buffer.write((line + "\n").encode("utf-8", errors="replace"))
    sys.stdout.buffer.flush()
    with open(LOG_FILE, "a", encoding="utf-8") as f:
        f.write(line + "\n")


# ═══════════════════════════════════════════════════════════════════════
# 日期解析 — 适配 Discuz! 论坛日期格式
# ═══════════════════════════════════════════════════════════════════════

def parse_forum_date(date_str: str) -> str:
    """
    将论坛日期格式转为 RSS 标准 RFC 2822 格式
    输入: "2026-6-20 07:41" / "2026-06-20 07:41"
    输出: "Sat, 20 Jun 2026 07:41:00 +0800"
    """
    date_str = date_str.strip()
    for fmt in ["%Y-%m-%d %H:%M", "%Y-%m-%d"]:
        try:
            dt = datetime.strptime(date_str, fmt)
            return format_datetime(dt)
        except ValueError:
            continue
    log(f"[WARN] 无法解析日期: {date_str},使用当前时间")
    return format_datetime(datetime.now())


# ═══════════════════════════════════════════════════════════════════════
# 浏览器连接 — 通过 Chrome/Edge CDP 端口复用已登录会话
# ═══════════════════════════════════════════════════════════════════════

def ensure_browser_cdp(cdp_port: int = 9222) -> str:
    """
    确保浏览器以调试模式运行,返回 WebSocket CDP URL
    
    前置条件(手动操作一次即可,浏览器会保持登录状态):
      - 启动浏览器并添加参数: --remote-debugging-port=<cdp_port>
      - 在浏览器中手动登录目标论坛
    """
    try:
        data = urllib.request.urlopen(f"http://localhost:{cdp_port}/json/version", timeout=3)
        info = json.loads(data.read())
        log(f"浏览器已运行,CDP 已连接")
        return info["webSocketDebuggerUrl"]
    except Exception:
        log(f"[FAIL] 浏览器调试端口 {cdp_port} 未就绪。请先启动浏览器调试模式")
        sys.exit(1)


# ═══════════════════════════════════════════════════════════════════════
# XML 工具
# ═══════════════════════════════════════════════════════════════════════

def escape_xml(text: str) -> str:
    """转义 XML 五种特殊字符"""
    return (text
            .replace("&", "&amp;")
            .replace("<", "&lt;")
            .replace(">", "&gt;")
            .replace('"', "&quot;")
            .replace("'", "&apos;"))


# ═══════════════════════════════════════════════════════════════════════
# 自定义异常 — 登录状态检测
# ═══════════════════════════════════════════════════════════════════════

class LoginExpiredError(Exception):
    """检测到未登录状态时抛出,避免生成空RSS"""
    pass


# ═══════════════════════════════════════════════════════════════════════
# 核心抓取逻辑 — Playwright CDP 模式
# ═══════════════════════════════════════════════════════════════════════

async def scrape_forum(cdp_port: int = 9222):
    """
    通过 CDP 连接浏览器,抓取论坛帖子列表
    
    返回: [{"tid", "title", "href", "category", "author", "pubDate"}, ...]
    登录失效时抛 LoginExpiredError
    
    适配: Discuz! 论坛模板 (tbody[id^='normalthread_'])
    """
    from playwright.async_api import async_playwright

    ws_url = ensure_browser_cdp(cdp_port)

    async with async_playwright() as pw:
        browser = await pw.chromium.connect_over_cdp(ws_url)
        log("已连接浏览器")

        ctx = browser.contexts[0]

        # 复用已有论坛标签页
        existing_page = None
        for p in ctx.pages:
            if "<<FORUM_DOMAIN_KEYWORD>>" in p.url:    # 替换为论坛域名关键词
                existing_page = p
                log(f"复用已有标签")
                break

        if existing_page:
            page = existing_page
        else:
            page = await ctx.new_page()
            log("创建新标签页")

        log(f"导航到 {FORUM_URL}")
        await page.goto(FORUM_URL, wait_until="domcontentloaded", timeout=20000)
        await asyncio.sleep(3)  # 等待 JS 渲染完毕

        # ── 登录状态检测 ──
        page_text = await page.inner_text("body")
        # 根据目标论坛的未登录特征调整检测条件
        if ("<<LOGIN_REQUIRED_TEXT1>>" in page_text or 
            "<<LOGIN_REQUIRED_TEXT2>>" in page_text):
            await browser.close()
            raise LoginExpiredError("检测到未登录状态")

        log(f"页面标题: {await page.title()}")

        # ── 解析帖子列表(Discuz! 通用 DOM 结构)──
        posts = await page.evaluate("""() => {
            const posts = [];
            const tbodies = document.querySelectorAll("tbody[id^='normalthread_']");

            tbodies.forEach(tbody => {
                try {
                    const th = tbody.querySelector("th.common, th.new");
                    if (!th) return;

                    // 标题和链接
                    const titleLink = th.querySelector("a.s.xst, a.xst");
                    if (!titleLink) return;
                    const title = titleLink.textContent.trim();
                    const href = titleLink.getAttribute("href");

                    // 分类标签
                    const catEl = th.querySelector("em a");
                    const category = catEl ? catEl.textContent.trim() : "";

                    // 作者和发布日期
                    const resTi = th.querySelector("p.res-ti");
                    let author = "";
                    let pubDate = "";
                    if (resTi) {
                        const authorLink = resTi.querySelector("a");
                        if (authorLink) author = authorLink.textContent.trim();
                        const text = resTi.textContent;
                        const parts = text.split("\u2022");  // • 分隔符
                        if (parts.length > 1) pubDate = parts[1].trim();
                    }

                    // fallback: 从 td.by 获取作者
                    if (!author) {
                        const byCite = tbody.querySelector("td.by cite a");
                        if (byCite) author = byCite.textContent.trim();
                    }

                    // fallback: 从 td.by em span 获取日期
                    if (!pubDate) {
                        const dateSpan = tbody.querySelector("td.by em span");
                        if (dateSpan) pubDate = dateSpan.textContent.trim();
                    }

                    // 从 tbody id 提取帖子ID
                    const tidMatch = tbody.id.match(/normalthread_(\\d+)/);
                    const tid = tidMatch ? tidMatch[1] : "";

                    posts.push({ tid, title, href, category, author, pubDate });
                } catch(e) {}
            });
            return posts;
        }""")

        log(f"抓取到 {len(posts)} 条帖子")

        if not existing_page:
            await page.close()
        await browser.close()

    return posts


# ═══════════════════════════════════════════════════════════════════════
# RSS 生成 — 标准 RSS 2.0 XML
# ═══════════════════════════════════════════════════════════════════════

def build_rss_xml(posts: list) -> str:
    """根据帖子列表生成标准 RSS 2.0 XML"""
    now_rfc2822 = format_datetime(datetime.now())

    items_xml = []
    for post in posts:
        link = (post["href"] if post["href"].startswith("http")
                else BASE_URL.rstrip("/") + "/" + post["href"].lstrip("/"))

        pub_date = parse_forum_date(post["pubDate"]) if post["pubDate"] else now_rfc2822

        category_prefix = f"[{post['category']}] " if post["category"] else ""
        title_full = f"{category_prefix}{post['title']}"

        description = f"<p>{escape_xml(title_full)}</p>"
        if post["author"]:
            description += f"<p>作者: {escape_xml(post['author'])}</p>"
        description += f'<p><a href="{escape_xml(link)}">点击查看原文</a></p>'

        item = f"""    <item>
      <title><![CDATA[{escape_xml(title_full)}]]></title>
      <link>{escape_xml(link)}</link>
      <guid isPermaLink="true">{escape_xml(link)}</guid>
      <pubDate>{pub_date}</pubDate>
      <description><![CDATA[{description}]]></description>
    </item>"""
        items_xml.append(item)

    return f"""<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title><![CDATA[{escape_xml(FORUM_TITLE)}]]></title>
    <link>{escape_xml(FORUM_LINK)}</link>
    <description><![CDATA[{escape_xml(FORUM_DESC)}]]></description>
    <language>zh-CN</language>
    <lastBuildDate>{now_rfc2822}</lastBuildDate>
    <pubDate>{now_rfc2822}</pubDate>
    <generator>Forum RSS Generator (CDP)</generator>
    <atom:link href="{escape_xml(RSS_DEPLOY_URL)}" rel="self" type="application/rss+xml"/>
{chr(10).join(items_xml)}
  </channel>
</rss>"""


# ═══════════════════════════════════════════════════════════════════════
# 部署 — Pages 服务 CLI 部署
# ═══════════════════════════════════════════════════════════════════════

def deploy_to_pages(rss_content: str) -> bool:
    """
    将文件部署到 Pages 服务(如 Cloudflare Pages / Netlify)
    
    部署内容:
      - index.html:      空白首页(防目录列表暴露)
      - robots.txt:      全站禁止搜索引擎
      - _headers:        XML 文件 X-Robots-Tag: noindex
      - {SUBDIR_L1}/{SUBDIR_L2}/{RSS_FILENAME}: RSS文件
    """
    tmpdir = tempfile.mkdtemp(prefix="pages_deploy_")

    # 空白首页
    with open(os.path.join(tmpdir, "index.html"), "w", encoding="utf-8") as f:
        f.write("""<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="utf-8"><title>RSS Service</title></head>
<body></body>
</html>""")

    # robots.txt — 全站禁止搜索引擎爬取
    with open(os.path.join(tmpdir, "robots.txt"), "w", encoding="utf-8") as f:
        f.write("User-agent: *\nDisallow: /\n")

    # _headers — XML 文件响应头防索引
    with open(os.path.join(tmpdir, "_headers"), "w", encoding="utf-8") as f:
        f.write(f"/{SUBDIR_L1}/{SUBDIR_L2}/{RSS_FILENAME}\n")
        f.write("  X-Robots-Tag: noindex\n")

    # 两层随机子目录 + RSS 文件
    subdir_path = os.path.join(tmpdir, SUBDIR_L1, SUBDIR_L2)
    os.makedirs(subdir_path, exist_ok=True)
    with open(os.path.join(subdir_path, RSS_FILENAME), "w", encoding="utf-8") as f:
        f.write(rss_content)

    # ── 调用 Pages CLI 部署 ──
    # 示例: Cloudflare Wrangler
    # 替换为实际 CLI 路径和命令
    log("通过 CLI 部署到 Pages 服务...")
    try:
        env = os.environ.copy()
        env["PAGES_API_TOKEN"] = PAGES_API_TOKEN
        env["PAGES_ACCOUNT_ID"] = PAGES_ACCOUNT_ID

        # -- 替换为实际 CLI 可执行文件路径 --
        node_path = "<<YOUR_NODE_PATH>>"
        cli_path = "<<YOUR_CLI_PATH>>"

        cmd = [
            node_path, cli_path,
            "pages", "deploy", tmpdir,
            "--project-name", PAGES_PROJECT_NAME,
            "--branch", "main"
        ]

        result = subprocess.run(
            cmd, env=env,
            capture_output=True, text=True, encoding="utf-8",
            errors="replace", timeout=120
        )
        output = (result.stdout or "") + (result.stderr or "")
        log(output.strip())

        if result.returncode != 0:
            log(f"[FAIL] 部署失败 (exit {result.returncode})")
            return False

        log(f"[OK] 部署成功!")
        log(f"[OK] RSS 地址: {RSS_DEPLOY_URL}")

    except subprocess.TimeoutExpired:
        log("[FAIL] 部署超时")
        return False
    except Exception as e:
        log(f"[FAIL] 部署失败: {e}")
        return False
    finally:
        shutil.rmtree(tmpdir, ignore_errors=True)

    return True


# ═══════════════════════════════════════════════════════════════════════
# 入口 — 含重试与异常处理
# ═══════════════════════════════════════════════════════════════════════

def main():
    log("=" * 50)
    log("论坛 RSS 生成器启动 (CDP + Pages 部署)")
    log(f"目标: {RSS_DEPLOY_URL}")

    try:
        posts = None
        for attempt in range(2):
            try:
                posts = asyncio.run(scrape_forum())
                break
            except LoginExpiredError as le:
                if attempt == 0:
                    log(f"[WARN] 第1次抓取失败: {le},5秒后重试...")
                    time.sleep(5)
                else:
                    log(f"[FAIL] 第2次抓取仍失败: {le}")
                    log("[INFO] 登录状态失效,本次RSS更新已跳过")
                    sys.exit(0)

        if not posts:
            log("[FAIL] 未抓取到任何帖子")
            sys.exit(1)

        log(f"共抓取 {len(posts)} 条帖子,生成 RSS...")

        rss_content = build_rss_xml(posts)
        log(f"RSS 生成完毕,大小: {len(rss_content)} 字符")

        # 本地备份
        local_path = os.path.join(SCRIPT_DIR, RSS_FILENAME)
        with open(local_path, "w", encoding="utf-8") as f:
            f.write(rss_content)
        log(f"本地备份: {local_path}")

        # 部署
        ok = deploy_to_pages(rss_content)
        if ok:
            log(f"[OK] 全部完成! RSS 地址: {RSS_DEPLOY_URL}")
        else:
            log("[FAIL] 部署失败")
            sys.exit(1)

        # 预览
        log("\n--- 前5条帖子 ---")
        for p in posts[:5]:
            cat = f"[{p['category']}] " if p.get("category") else ""
            log(f"  {cat}{p['title']} | {p.get('author','?')} | {p.get('pubDate','?')}")

    except Exception as e:
        log(f"[FAIL] 脚本异常: {e}")
        import traceback
        with open(LOG_FILE, "a", encoding="utf-8") as f:
            f.write(traceback.format_exc())
        sys.exit(1)


if __name__ == "__main__":
    main()

注意

Cloudflare Pages默认域名可能无法直接访问,建议绑定自己的域名。

利用AI智能体+Cloudflare给任意网页制作即时RSS最先出现在龙鲲博客。

免费领取豆包会员1个月(含Seedance 2.5视频模型)

2026-08-27 19:49:09

本文于 2026年8月29日 3:05 更新,注意查看最新内容

前言

前几天的时候看新闻,说TRAE、扣子并入豆包,当时还挺诧异的,毕竟TRAE和扣子的风格跟豆包还是有些差异的,面向的用户群体也不太一样,这条消息看完也就抛在了脑后。今天看到消息,说下载豆包工作免费领1个月标准版会员(原价68元),于是下载了一个,确实领到了会员,这里简单记录,以备日后查阅。

方法

1.打开豆包工作官网 https://www.doubao.com/work 。

2.点击下载豆包工作按钮,选择显示当前设备一行进行下载

3.下载好后进行安装,然后登录豆包账号,此时会员会自动到账(全端通用,包括网页端、手机端)。

玩法

1.豆包云电脑

这是我平常用得比较多的功能,但是受限于普通用户的额度,基本上没用几次就无法使用了,使用路径如下,可切换会员模型。

2.AI创作图片使用Seedream 5.0 Pro模型,AI创作视频可以使用Seedance 2.5模型。

3.AI生成的图片与视频去水印。具体步骤如下:

①先生成一个图片或视频。

②单击任意图片正中间(不要点击下载图标)。

③在打开的侧边窗口右上角点击三个点,

④开启去除“AI 生成”水印开关并保存,此时图片左上角不再显示AI水印。

核心的功能区别主要就是上述这几个,其他主要是额度的不一样,标准会员会比普通用户多几倍。

后话

部分用户有标准版1元连续包月,开通路径在额度状态-升级至标准套餐,具体自行验证,若仅需一个月会员,记得在开通后取消连续包月。

免费领取豆包会员1个月(含Seedance 2.5视频模型)最先出现在龙鲲博客。

无限免费使用MiniMax M3 AI大模型的方法

2026-08-26 15:29:17

本文于 2026年8月26日 7:32 更新,注意查看最新内容

前言

自从进入AI时代,Token一词开始频频出现在人们的视野中,这个AI的计费单位也在以极快的速度消耗着大家的钱包。很多用AI的时候,用着用着就开始提示额度有些紧张,甚至无法继续使用,而本文则是介绍一个短期可以无限使用AI大模型的方法,以供大家参考。方法也很简单,但因为是无限使用,并且并发数极高,所以依旧是手慢无。

方法

MiniMax和GMI Cloud最近有个联名活动,活动大概的内容为将MiniMax M3、M2.7、Speech 2.8和Music 3.0免费使用十四天,时间是2026.08.24 – 2026.09.06,在此期间不限制使用额度,并发数实际测试下来也非常高(200以内不会报429),个人使用完全没问题,下面介绍具体方法:

注册GMI账号

1.打开GMI官网https://www.gmicloud.ai/ ,点击右上角黄色按钮SIGN IN。

2.在登录页面点击Sign in进入注册页面。

3.按照顺序依次输入注册邮箱、密码,并勾选服务条款,最后点击Sign up注册。

4.注册完成后(忘了是否会自动登录,若未登录,重复第1、2步进行登录),在下图同样位置找到Create API Key点击。

5.在弹窗的文本框输入任意文字后,点击Create Key创建密钥。

6.点击下图位置进行复制,并粘贴至记事本中,后续需要使用(该密钥只会显示1次,若遗失可重复第4、5步重新获取)。

至此,前期的准备工作已全部完成,下面介绍如何接入WorkBuddy中。

接入WorkBuddy

1.打开WorkBuddy,选择页面输入框右下角的Auto,点击配置自定义模型。

2.在弹出的窗口中选择供应商,滑到最下面,点击自定义/Custom。

3.此时会打开一个新窗口,按照如下信息填写,并勾选图片输入、推理模式,最后点击确定。

接口地址:https://api.gmi-serving.com/v1/chat/completions

API Key:注册GMI账号中复制粘贴的密钥

模型名称:MiniMaxAI/MiniMax-M3

4.回到WorkBuddy首页切换成自定义接入的M3模型,即可正常使用,此时也不再消耗内置积分。

后话

MiniMax-M3这个模型处理不了特别复杂的任务,但日常用来办公什么的还是绰绰有余,目前在WorkBuddy的内置模型中,消耗积分的速度甚至还超过了DeepSeek-V4-Flash,如果平常主要使用的就是M3模型,那该活动应该能替你省下不少的Token,另外免费的几款模型也有一定可玩性,可以接入相关的工具用来输出语音对话内容。

无限免费使用MiniMax M3 AI大模型的方法最先出现在龙鲲博客。