恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
链接解析与卡片生成实战:让陌陌分享在微信QQ中显示富媒体卡片
首页
资讯中心
/
链接解析与卡片生成实战:让陌陌分享在微信QQ中显示富媒体卡片
链接解析与卡片生成实战:让陌陌分享在微信QQ中显示富媒体卡片
发布时间:2026/9/20 16:40:52
简介面向社交应用开发者的陌陌自定义卡片链接源码包专注于解决直播或聊天场景中动态卡片消息的构造与发送问题代码仅 8KB 却包含完整后端逻辑。核心实现集中在两个 Java 方法mo131684a 用 HashMap 封装 URL、标题、内容及图片路径等字段并针对好友、群组、讨论组等不同同步场景定制参数后发起 HTTP POST 请求startTask 则通过反射读取群组或好友ID监听发送按钮事件从剪贴板取得 JSON 数据并解析按数据类型拼装卡片内容。整个资源共 6 个文件包括 2 个 Java 源文件、1 个 XML 配置、1 个 Markdown 说明以及 gitignore、inscode 等辅助文件目录简洁、注释详细便于二次开发。截至目前已有 87 人学习适合想了解社交平台自定义消息机制的中高级 Android 开发者参考但需注意项目仅供学习交流严禁用作商业用途。 先说结论这个项目解决的问题非常具体——当你把一条陌陌直播间或动态的链接分享到微信、QQ、外部网站时对方看到的基本就是一串光秃秃的URL点开还可能被“已停止访问该网页”拦截。我做的这套自定义卡片链接源码就是把这些链接抓取解析后重新封装成带标题、描述、缩略图的可预览卡片同时保留跳转回陌陌对应页面的能力。这个项目源码我已经跑通整套代码不依赖任何付费接口纯靠HTTP请求解析和数据提取。适合三类人看一是做社交裂变和用户增长的同学二是对链接解析、页面信息抽取感兴趣的开发者三是想了解社交平台分享链路如何运作的爬虫入门者。文章里我按实际踩坑顺序来讲从链接协议分析到卡片渲染再到线上部署每一步都给出能直接用的方案。1. 陌陌卡片链接的构成与解析思路1.1 链接形态与信息载体陌陌的分享链接通常长这样https://www.immomom.com/加上一串短码或者带?share参数的动态地址。你在App里点“复制链接”拿到的往往是短链接因为陌陌要统计分享来源和渠道。链接背后的信息载体其实分三层短链接本身只是一个索引服务端会302重定向到真实页面。落地页HTML包含og:title、og:description、og:image等Open Graph协议标签这是社交平台抓取卡片的依据。动态接口数据部分页面信息不在HTML里而是通过XHR请求异步加载比如直播间在线人数、主播头像高清图。我解析时先把短链接还原成完整地址再从HTML里提取OG标签如果字段缺失再补发请求到页面内嵌的JSON数据接口。这套链路看着简单但有一个坑陌陌的落地页对不同UA返回的HTML版本不同桌面UA和移动UA的节点结构完全不一样解析逻辑要分两套。1.2 短链接还原时的跳转处理短链接还原不是简单发一个GET请求就完事。真实的跳转链路可能是短链接 → 302到中间统计页 → 再302到最终落地页。所以代码里要手动关闭自动重定向逐跳记录响应头既能拿到最终的URL也能顺便抓取每一跳的Set-Cookie。import requests def resolve_short_url(url): session requests.Session() resp session.get(url, allow_redirectsFalse, timeout10) redirect_count 0 while resp.status_code in (301, 302, 303, 307, 308) and redirect_count 6: next_url resp.headers.get(Location) if next_url.startswith(/): next_url urllib.parse.urljoin(url, next_url) url next_url resp session.get(url, allow_redirectsFalse, timeout10) redirect_count 1 return url, session.cookies.get_dict()这里有几个细节allow_redirects必须设为False否则拿不到中间跳的信息跳转超过6次直接放弃防止死循环每次请求最好保持同一个Session因为部分中间页会种Cookie后续落地页要带这些Cookie才能返回完整内容。1.3 为什么不能绕过解析直接硬编码有些同学图省事想自己造一个卡片生成接口固定传标题、图片、链接。这种做法做内部测试没问题但放到真实环境就会发现用户分享的链接千奇百怪有直播间、有动态、有个人主页、有群聊邀请信息结构完全不同。而且陌陌会定期调整落地页模板硬编码的字段这两天能用下周可能就抓不到图了。所以源码里我把解析器设计成“先识别页面类型再匹配对应解析规则”的模式。判断依据从URL路径和HTML里的特征节点入手比如/live/路径进直播解析器/moment/进动态解析器老版本链接没有路径特征的就靠页面上>app.get(/go/{token}) async def go_redirect(token: str, request: Request): link_data await redis.get(fcard:link:{token}) if not link_data: raise HTTPException(status_code404, detaillink expired) # 记录点击日志包括来源页面、UA、IP await track_click(token, request) return {schema: link_data[schema], fallback_url: link_data[fallback_url]}点击日志我直接写到SQLite数据量大了再换PostgreSQL。日志字段包括token、来源页、UA、IP、时间戳后期可以按token维度统计每个卡片的点击转化率。4. 线上实测遇到的坑与完整排查链路4.1 图片防盗链与Referer校验第一个真实遇到的坑卡片里的缩略图在微信里能显示在陌陌App内置浏览器里却不显示。排查过程是这样的——先在微信开发者工具里看卡片页图片能加载再用陌陌App打开卡片页图片区域空白。打开浏览器Network面板发现图片请求返回403。接着看请求头发现陌陌内置浏览器发请求时不会带Referer字段而陌陌的图片CDN对空Referer直接拒绝。知道了根因修复方案就有两种。一种是给图片请求加meta namereferrer contentno-referrer让浏览器不发Referer但CDN同样拒绝。另一种是把图片拉到自己的服务器或对象存储再输出相当于做一次代理。最终我选择了后者用FastAPI写了一个/imgproxy接口请求时带上正确的Referer: https://www.immomom.com/去拉原图然后流式返回给前端。app.get(/imgproxy) async def img_proxy(url: str): headers { Referer: https://www.immomom.com/, User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) } resp requests.get(url, headersheaders, streamTrue, timeout10) if resp.status_code ! 200: raise HTTPException(status_code502) return StreamingResponse(resp.raw, media_typeresp.headers.get(Content-Type))这个接口上线后卡片图在陌陌、微信、QQ三个环境里都能正常显示了。要注意给这个接口加一层缓存否则每刷新一次卡片页就回源拉一次图服务器流量撑不住。4.2 卡片信息偶发空白的缓存与失效问题第二个坑是卡片信息偶尔返回空白但刷新几次又好了。刚开始怀疑是陌陌限流查日志发现是落地页返回了空HTML但HTTP状态码是200。进一步排查发现这种空HTML响应里往往带一个Set-Cookie: verifyxxx的字段说明这是风控系统返回的验证页而不是真正的页面内容。验证页通过JS动态写入真实数据单纯用requests去请求当然拿不到内容。我的处理分三层第一层请求时带上足够真实的Cookie和Header第二层在解析代码里判断HTML长度如果小于2KB就认为被风控拦截触发重新请求第三层对同一个链接增加解析频率限制比如同一链接5分钟内最多解析3次超过就返回上次成功缓存的数据。这里Redis的TTL设置很关键我默认设24小时但热点直播间信息可以缩短到30分钟避免用户看到过期的在线人数。4.3 微信、QQ与陌陌内置浏览器的差异兼容同样一张卡片HTML在微信里表现和QQ里不一样在陌陌内置浏览器里又是另一个表现。我整理了一个对照表环境缩略图加载schema跳转JS执行限制备注微信正常需iframe兜底较宽松需要备案域名QQ有时referrer异常直接跳转成功率低较严格建议走下载页兜底陌陌内置必须代理图片直接唤起成功率高支持注意不要触发内部拦截普通浏览器正常正常无无微信里最大的限制是域名备案且HTTPS证书有效否则连分享卡片都发不出去。QQ内置浏览器对302跳转的容忍度低我测试时发现它会把schema跳转当成非法重定向直接拦截所以QQ环境下我有单独的页面按钮直接跳H5详情页而不是唤起App。陌陌内置浏览器里反而最简单schema协议和URL Scheme都支持只是图片Referer问题比较明显。这三个环境的兼容逻辑我抽成了一个compat.py文件根据UA里的关键字做判断返回不同的前端模板变量。4.4 链接解析频率与IP质量对成功率的影响整个项目上线两周后我发现解析成功率从95%降到了80%左右。逐步排查最终定位到两个变量请求频率和IP质量。请求频率方面陌陌对短链服务的限制不是按照IP维度而是按照「IP UA Cookie」的组合维度。同一个IP下只要UA轮换够充分Cookie保持稳定频率控制在每分钟20次以内基本不会被拦截。我写了一个简单的令牌桶限流器放在解析模块前面。IP质量这个变量是后知后觉的。本机测试时用的家庭宽带IP质量高解析成功率一直在95%以上部署到便宜的云服务器后由于该机房IP段被大量爬虫用过陌陌那边明显更谨慎同样的请求头成功率掉了15个百分点。这两个变量的影响在日志里非常清晰建议你在排查成功率问题时先把日志按IP分组看一眼再动手改代码。5. 项目部署与二次开发方向5.1 Docker一键部署与域名配置源码里带了Dockerfile和docker-compose.yml跑起来很简单docker-compose up -d主要包含三个容器FastAPI应用、Redis缓存、Nginx静态文件和反向代理。Redis在docker-compose里指定了持久化volume重启不丢缓存。Nginx配置里提前写了/imgproxy和静态资源目录的转发规则。部署到公网后有三件必做的事域名解析到服务器并配置HTTPS证书微信/QQ对HTTP环境非常不友好。在Nginx层加一个基本限流防止卡片接口被刷。修改config.py里的域名白名单防止别人直接调用你的接口生成恶意卡片。5.2 从单条卡片到批量链接管理单条卡片功能跑通后我顺手加了一个管理端页面支持批量导入陌陌链接表格里直接看到每条链接的解析状态、标题、缩略图和最近点击量。这个功能改动不大解析服务本来就是把输入链接转成卡片数据加个批量任务队列就行。任务队列我没有引入Celery这么重的组件而是直接用FastAPI的BackgroundTasks加Redis列表实现了一个简易队列。后台任务每次从列表里取一个链接调用解析和渲染流程把结果写回MySQL前台页面通过WebSocket推送状态。对一个小型增长团队来说这套方案完全够用。5.3 开源结构里的模块拆分源码我按“能不能独立复用”拆成了三块。momo-parser是纯解析库不依赖FastAPI你可以单独pip安装用命令行方式跑momo-card-renderer是渲染层依赖Jinja2模板不关心数据从哪来momo-server是把前两者组合起来的HTTP服务。这样的拆分有什么好处如果你只需要在服务端生成卡片数据就不必部署整个Web服务如果你只想研究陌陌的分享链路协议跑一下parser就够了。我在parser的README里留了完整的字段说明和调用示例花半小时就能跑通。最后分享一个经验这类解析类项目不要试图跟平台的反爬策略硬刚保持低频率、真实UA、合理TTL项目反而跑得长久。我见过太多人写几个小时的多线程并发采集模块上线半天IP就被封了得不偿失。代码已经完整跑通拿去做链接管理、做内容监测、做用户增长都可以直接复用到自己的场景里。本文还有配套的精品资源点击获取