ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于arXiv API的计算机视觉论文每日自动抓取与筛选流水线

基于arXiv API的计算机视觉论文每日自动抓取与筛选流水线 1. 这个每日更新项目到底在解决什么问题每天早上刷论文列表这件事做过视觉研究的人应该都懂那种感受。arXiv 的 cs.CV 分区每天新挂出来的稿件少则几十篇多的时候能到两三百篇标题和摘要混在一起光是滚动浏览就要花掉大半个小时。更麻烦的是真正和你手头课题相关的那几篇往往藏在某个不起眼的角落等你翻到的时候已经过去三天了。我最初做这个每日更新项目动机特别朴素——就是想让自己在通勤路上用手机也能快速过一遍当天的新稿把值得精读的挑出来剩下的直接归档。这个项目本质上是一条自动化流水线定时抓取 arXiv 计算机视觉分区当日新增论文的元数据做一轮轻量筛选和分类再以固定格式输出成一份可读性强的日报。它解决的核心痛点有三个第一是信息过载把几百篇压缩成一份带重点标记的清单第二是时效性每日固定时间更新不用自己反复刷新第三是可追溯历史日报按日期归档回头找某篇论文时能按时间线定位。适合谁来参考这份经验如果你是在读研究生、刚进实验室的本科生、或者任何需要持续跟踪视觉领域动态的从业者这套流程都能直接搬过去用。哪怕你之前没写过爬虫、没碰过定时任务只要会基本的 Python 和一点点命令行操作跟着走一遍就能跑起来。我下面会把每个环节的取舍逻辑、踩过的坑、以及可以直接抄的配置都摊开讲尽量让不同基础的人都能落地。2. 整体架构设计与方案选型思路2.1 为什么选择抓取-筛选-渲染三段式一开始我也想过偷懒直接用现成的论文推荐服务或者订阅别人的邮件列表。但实际用下来发现两个问题一是别人的筛选标准未必符合我的方向二是格式固定死了想加个自己的标记都不行。所以最终还是决定自己搭一条链路。三段式的划分不是拍脑袋定的而是对应了三个完全独立的关注点——数据获取、信息降噪、呈现输出。这样拆的好处是每一段都能单独替换和调试比如哪天抓取源换了我只需要改第一段后面的筛选规则和渲染模板完全不用动。具体来说第一段负责和 arXiv 打交道把当天的原始条目拉下来存成结构化数据第二段根据关键词、分类标签、作者等维度做打分和归类第三段把处理好的数据套进模板生成 Markdown 或 HTML 格式的日报。三段之间用统一的中间数据格式我用的就是 JSON衔接这样任何一段出问题都不会污染其他环节。2.2 抓取方式的选择官方接口还是页面解析arXiv 官方是提供 API 的走export.arxiv.org/api/query这个入口返回的是 Atom 格式的 XML。我强烈建议优先用官方接口原因很实在页面结构说变就变今天能用的 CSS 选择器明天可能就失效了而接口的字段相对稳定。官方接口支持按分类、按日期范围、按关键词查询还能分页对于每日更新这个场景完全够用。不过官方接口有个坑要注意它默认返回的是最近更新而不是最近提交而且时间戳用的是协调世界时。如果你在北京时间早上八点跑实际上拿到的是前一天下午到当天凌晨这个窗口的数据。我后来是显式指定了时间范围参数把窗口对齐到过去24小时这样每天抓到的内容不会重叠也不会漏。2.3 筛选策略规则打分还是模型分类筛选这块我纠结过一阵。用现成的文本分类模型听起来很高级但实际跑下来有两个现实问题一是模型推理有延迟每天几百篇跑一遍要等好几分钟二是模型对新兴方向的敏感度不够容易把一些刚冒出来的冷门但重要的稿子过滤掉。最后我选的是规则打分为主的方案——给每篇论文算一个分数分数由几个维度加权得到然后按分数排序取前若干篇作为重点推荐剩下的作为完整列表。打分的维度包括标题和摘要里是否命中我预设的关键词表权重最高、是否属于我关注的细分分类比如目标检测、图像分割、多模态、作者是否在关注列表里、以及摘要长度和是否有代码链接这类辅助信号。这套规则的好处是完全透明我能清楚知道某篇论文为什么被推上来调整起来也直接改配置就行不用重新训练。2.4 输出格式为什么最终选了 Markdown渲染格式我试过三种纯文本、HTML 邮件、Markdown。纯文本太朴素重点不突出HTML 邮件好看但排版在不同客户端里表现不一致而且写起来啰嗦。Markdown 是折中方案——结构清晰、重点可以用加粗和列表突出、在任何编辑器里都能读而且我后续想转成别的格式也方便。日报的模板我固定成几个区块头部是日期和统计信息接着是今日重点打分靠前的几篇带一句话点评然后是完整列表按分类分组最后是归档链接。3. 核心环节的实操细节与配置3.1 抓取环节接口参数与分页处理抓取这一步的核心是把查询参数配对。官方接口的几个关键参数我列一下search_query用来指定分类和关键词比如cat:cs.CV就是计算机视觉分区start和max_results控制分页单次最多返回 2000 条但实际用的时候建议一次 100 条避免超时sortBy和sortOrder控制排序我一般用submittedDate配合descending。这里有个细节值得说接口返回的 XML 里每篇论文的published和updated是两个不同的时间字段。published是首次提交时间updated是最近一次修订时间。做每日更新的时候如果你只按published过滤会漏掉那些当天被大幅修订的老论文如果只按updated过滤又会把一些只是改了个错别字的老稿子重新捞进来。我的做法是两个字段都看但给published更高的优先级updated只在published不在窗口内时才作为补充。分页处理上我写了个循环每次请求 100 条直到返回结果为空或者达到预设的上限我设的是 500 条防止某天异常刷屏。每次请求之间加了 3 秒的间隔这是为了不给对方服务器造成压力也是为了避免被限流。实测下来500 条大概需要 15 次请求加上间隔总共一分钟左右能跑完。3.2 数据清洗字段提取与异常处理原始 XML 拉下来之后不能直接用得先解析成干净的 JSON。我用的是 Python 标准库里的xml.etree.ElementTree没有额外装依赖。需要提取的字段包括论文 ID从链接里截取、标题、摘要、作者列表、分类标签、提交日期、修订日期、PDF 链接、以及是否有代码仓库链接。清洗环节最容易出问题的是摘要里的换行和多余空格。arXiv 的摘要字段经常包含硬换行直接渲染出来会断得很难看。我的处理是把所有连续空白字符包括换行、制表符统一替换成单个空格然后再去掉首尾空白。另外标题里偶尔会有 LaTeX 公式残留比如$符号包裹的内容这个我暂时没做深度处理只是把裸露的$去掉因为大部分标题里的公式其实不影响理解。还有一个坑是作者名的格式。接口返回的作者是分开的标签但有些论文的作者名里带逗号或者连字符直接拼接会乱。我的做法是用分号加空格连接这样即使名字里有逗号也不会混淆。如果作者超过 5 个就只显示前 5 个加等。3.3 打分逻辑权重配置与调参经验打分逻辑是整个项目的灵魂我把它写成了一个独立的配置文件用 YAML 格式管理。核心结构是几个维度的权重和对应的匹配规则。关键词表我分了三档核心关键词权重 10、相关关键词权重 5、边缘关键词权重 2。分类标签也类似主分类权重高交叉分类权重低。调参这块我踩过不少坑。最开始关键词给得太宽泛结果每天推上来的重点有二十多篇等于没筛选。后来我把核心关键词收紧到只保留五六个我真正在做的方向重点数量就降到了每天三到五篇这个量级刚好——既不会漏掉重要的也不会多到看不完。另一个经验是定期回顾误判我每周会花十分钟翻一下过去一周被推到重点但实际不相关的论文看看是哪个关键词误触发的然后把它从表里挪走或者降权。这个习惯坚持下来筛选准确率提升很明显。3.4 渲染模板结构设计与可读性优化渲染模板我用的是 Python 的字符串格式化没有引入模板引擎因为结构不复杂手写反而更可控。日报的头部我放了三个统计数字当日新增总数、重点推荐数、以及各分类的分布。这三个数字能让人一眼看出今天的信息密度。重点推荐区块里每篇论文我固定展示标题加粗、作者截断、一句话摘要从原摘要里截取前 150 个字符、以及一个我自己的标记位比如待读已读跳过。这个标记位是纯文本的方便我在手机上看的时候直接改。完整列表区块按分类分组每组里只显示标题和链接尽量紧凑。提示摘要截取的时候不要简单按字符数切最好在句号或分号处断开否则会出现半句话的情况。我写了个小函数从 150 字符位置往前找最近的句号找不到就找逗号再找不到才硬切。4. 定时任务与自动化部署4.1 调度方案本机定时还是云端运行定时这块我试过两种方案。本机用cron最简单但缺点是电脑得一直开着出差或者关机就断了。后来我换成了云端的一台小规格实例用systemd timer来调度。systemd timer比cron好在日志管理更规范而且支持错过补偿——如果某次因为机器重启没跑成开机后它会补跑一次。调度时间我定在每天早上七点半。这个时间点的选择有讲究太早的话 arXiv 当天的更新还没完全挂出来太晚的话我出门前看不完。七点半跑大概八点前能生成日报正好赶上通勤路上看。时区上我显式设成了东八区避免因为服务器默认协调世界时导致时间错位。4.2 失败重试与告警自动化最怕的是静默失败——任务挂了但没人知道。我加了两层保护第一层是脚本内部的重试网络请求失败时自动重试三次每次间隔递增5 秒、15 秒、45 秒第二层是外部告警如果脚本连续两次运行都失败就通过一个简单的邮件通知提醒我。邮件内容只包含错误摘要和日志路径不涉及任何敏感信息。重试策略上有个细节不是所有错误都值得重试。网络超时、连接被拒这类可以重试但如果是接口返回了明确的参数错误重试多少次都没用这时候应该直接记录错误并退出。我在代码里用异常类型做了区分只对网络类异常做重试。4.3 数据归档与历史查询每天的日报生成后我会把原始 JSON 和渲染后的 Markdown 都按日期存一份。目录结构是年份/月份/日期.json和年份/月份/日期.md。这样归档的好处是几个月后我想找某篇论文可以直接用命令行工具在 Markdown 文件里全文搜索比翻网页快得多。归档还带来一个附加价值可以做一些趋势分析。比如我偶尔会统计一下过去一个月里某个关键词出现的频率看看这个方向是不是在升温。这个统计很简单就是遍历归档的 JSON 文件做词频计数但对我判断要不要调整关注方向挺有帮助。5. 常见问题排查与避坑经验5.1 抓取不到数据或数据为空这是最常见的问题排查思路按顺序来先确认接口地址和参数是否正确可以手动在浏览器里拼一个查询 URL 看看返回什么再检查时间窗口是不是设得太窄比如只查了今天但实际数据还没更新最后看是不是被限流了如果短时间内请求太频繁接口可能会返回空结果或者错误码。我的经验是遇到空结果先等十分钟再试大概率是限流。5.2 筛选结果偏差大如果发现推上来的重点论文明显不相关或者真正重要的被漏掉了先检查关键词表是不是有歧义。比如分割这个词在图像分割和实例分割里都是核心词但在某些论文里可能只是顺带提了一句。解决办法是给关键词加上下文约束比如要求它出现在标题里或者和另一个词同时出现才计分。另一个可能是权重配置失衡某个辅助维度的权重给太高压过了关键词的主导作用。5.3 渲染格式错乱Markdown 渲染出问题通常是特殊字符没转义。比如论文标题里如果有竖线|在表格里就会破坏结构如果有反引号会干扰代码块。我的处理是在渲染前对所有文本字段做一次转义把 Markdown 的保留字符替换成对应的实体。另外如果摘要里包含 HTML 标签偶尔会有也要一并去掉。5.4 定时任务不执行systemd timer不执行的原因通常有几个服务文件里的路径写的是相对路径而定时任务的工作目录和交互式 shell 不一样或者环境变量没配全比如 Python 的路径没加到PATH里。排查方法是看systemd的日志用journalctl命令查对应服务的输出。我踩过的坑是脚本里用了一个只在交互式 shell 里才有的环境变量定时任务跑的时候找不到后来改成在服务文件里显式声明才解决。问题现象可能原因排查动作解决方式抓取结果为空接口限流或时间窗口错误手动拼 URL 测试等待重试或放宽时间范围重点推荐不相关关键词歧义或权重失衡检查命中日志收紧关键词或调整权重渲染格式错乱特殊字符未转义检查原始文本渲染前统一转义定时任务不跑路径或环境变量问题查看系统日志改用绝对路径并声明环境变量注意调试抓取脚本的时候不要在生产环境直接改配置然后跑全量。我一般会先在一个测试目录里用少量数据跑一遍确认没问题再同步到正式环境。这个习惯帮我避免了好几次因为配置写错导致日报内容全乱的事故。6. 我个人的使用体会与后续扩展方向这套流程我断断续续维护了大半年最大的感受是自动化省下来的时间远比搭建它花的时间多。前期投入大概两个周末之后每天只需要花五分钟扫一眼日报把标记位改一改就行。相比以前每天手动刷半小时效率提升是实打实的。后续我打算加两个小功能。一个是去重因为有些论文会在不同日期被重复抓到比如修订后重新出现在窗口里目前是靠论文 ID 做简单去重但跨天的去重还没做。另一个是关联推荐当某篇论文被我标记为已读后自动从历史归档里找出主题相近的几篇推给我方便做文献综述。这两个功能都不复杂等有空了慢慢加。如果你也想搭一套类似的流程我的建议是先跑通最小闭环——能抓、能存、能看就行别一上来就追求完美的筛选和漂亮的排版。先把数据流打通用几天看看实际效果再根据真实需求去迭代筛选规则和模板。这样每一步的改动都有明确的反馈不容易半途而废。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进