1. 这个每日更新项目到底在做什么
每天早上八点半,我习惯性地打开终端,敲下一条拉取命令,然后去冲咖啡。等我端着杯子回来,屏幕上已经整整齐齐地躺着一份当天新增的计算机视觉方向论文清单——标题、作者、摘要、PDF链接,甚至还有我自定义的标签分类。这个习惯我坚持了快两年,而支撑这个习惯的,就是一套围绕ArXiv CV论文每日更新搭建的自动化追踪系统。
说白了,这个项目的核心目标只有一个:把ArXiv上每天新发布的计算机视觉论文,用最低的时间成本筛选出值得我花时间精读的那几篇。ArXiv的CV板块每天新增论文数量在几十到上百篇之间波动,如果靠人工逐条浏览标题和摘要,每天至少要消耗四十分钟以上,而且很容易因为疲劳而漏掉真正重要的内容。这套系统解决的就是这个信息过载问题。
它适合谁用?我认为有三类人最需要:第一类是正在做CV方向研究的研究生和博士生,需要持续跟踪领域前沿动态;第二类是在工业界做视觉算法落地的工程师,需要了解最新的技术方案和开源实现;第三类是对AI视觉感兴趣、想保持技术敏感度的开发者。不管你用的是Python还是其他语言,只要你能跑几条命令行脚本,这套方案就能直接抄作业。
我搭建这套系统的初衷其实很朴素。2024年底那会儿,我同时在跟三个项目,一个是目标检测的工业质检落地,一个是多模态检索的预研,还有一个是视频理解相关的技术调研。三个方向都要跟踪最新论文,但我实在没有精力每天手动刷ArXiv。于是我开始琢磨怎么用脚本把这件事自动化,从最开始的简单爬虫,到后来加入关键词过滤、摘要语义排序、每日邮件推送,前后迭代了七八个版本,踩了不少坑,也积累了一些真正好用的经验。
2. 整体架构设计与核心思路拆解
2.1 为什么选择ArXiv作为唯一信息源
做论文追踪,信息源的选择是第一步。我试过好几个渠道:Google Scholar的订阅、Semantic Scholar的API、还有一些第三方论文聚合平台。最终我把ArXiv作为核心信息源,原因有三。
第一,ArXiv的更新节奏最稳定。CV板块(cs.CV)的论文发布时间集中在美东时间工作日的下午到晚上,对应北京时间第二天早上,这个节奏非常适合做每日定时拉取。第二,ArXiv的元数据格式统一且免费开放。每篇论文都有标准的标题、作者列表、摘要、分类标签和PDF链接,解析起来非常规整,不需要处理各种奇怪的HTML结构。第三,ArXiv的覆盖面最广。很多CV方向的重要工作都是先在ArXiv上挂预印本,等正式发表时可能已经过了半年,对于追踪前沿来说,ArXiv的时效性无可替代。
当然,ArXiv也有它的局限。比如它不提供引用量数据,也不做质量筛选,每天上百篇论文里真正有价值的可能只有个位数。所以我的系统设计里,ArXiv只负责提供原始数据,后续的过滤和排序才是真正体现个人需求的部分。
2.2 从拉取到推送的完整链路设计
整个系统的链路我拆成了四个环节:拉取、解析、过滤排序、推送。每个环节都有明确的输入输出,方便单独调试和替换。
拉取环节,我用的是ArXiv官方提供的API接口。这个接口支持按分类、日期范围、关键词等条件查询,返回的是Atom格式的XML数据。相比直接爬网页,API的方式更稳定,不容易因为页面结构变化而失效。我设置的时间窗口是每天拉取前一天发布的所有cs.CV论文,同时也会拉取cs.CV下的子分类,比如cs.CV.CL(计算与语言交叉)、cs.CV.LG(学习与几何)等。
解析环节,我把XML里的关键字段提取出来,包括论文ID、标题、作者、摘要、主分类、交叉分类、发布时间、PDF链接、评论信息等。这里有个细节:ArXiv的摘要里经常包含LaTeX公式和特殊符号,直接展示会很难看,所以我加了一步清洗,把常见的LaTeX标记替换成可读的文本。
过滤排序环节是整个系统的灵魂。我设计了三层过滤:第一层是关键词黑名单,把明显不相关的方向排除掉,比如医学影像里某些过于细分的子领域;第二层是关键词白名单加权,对我关注的方向(比如目标检测、多模态、视频理解、模型压缩)给予更高的权重;第三层是摘要语义相似度排序,用一个小型的文本嵌入模型,把我过去收藏的论文摘要作为参考集,计算新论文与参考集的相似度,按相似度从高到低排序。
推送环节,我做了两个通道:一个是终端输出,每天早上跑完脚本直接在终端看结果;另一个是邮件推送,把排序后的Top 20篇论文以HTML格式发到我的邮箱,方便在手机上快速浏览。邮件里每篇论文包含标题、作者、摘要前200字、PDF链接和ArXiv链接,点击就能跳转。
2.3 为什么不用现成的论文推荐服务
市面上确实有一些论文推荐服务,比如基于协同过滤的推荐、基于社交网络的推荐等。但我最终选择自己搭建,核心原因是推荐的可解释性和可控性。现成的推荐服务往往是一个黑盒,你不知道它为什么推荐这篇而不是那篇,也无法根据自己当前的研究重点动态调整推荐策略。而自己搭建的系统,每一层过滤和排序的逻辑都是透明的,我可以随时修改关键词权重、调整相似度阈值、增加新的参考论文,系统会立刻响应我的调整。
另一个原因是数据隐私和长期可维护性。我的论文收藏列表、阅读笔记、研究方向偏好,这些都是个人研究资产,放在自己的服务器上更放心。而且自己维护的脚本,出了问题可以自己排查,不依赖第三方服务的稳定性。
3. 核心细节解析与实操要点
3.1 ArXiv API的调用细节与参数调优
ArXiv API的基础地址是http://export.arxiv.org/api/query,支持的主要参数包括search_query、start、max_results、sortBy、sortOrder等。我常用的查询语句是这样的:
import urllib.request import urllib.parse import xml.etree.ElementTree as ET from datetime import datetime, timedelta def fetch_arxiv_cv_papers(days_back=1, max_results=200): base_url = "http://export.arxiv.org/api/query" end_date = datetime.utcnow() start_date = end_date - timedelta(days=days_back) date_range = f"[{start_date.strftime('%Y%m%d')}0000 TO {end_date.strftime('%Y%m%d')}2359]" search_query = f"cat:cs.CV AND submittedDate:{date_range}" params = { "search_query": search_query, "start": 0, "max_results": max_results, "sortBy": "submittedDate", "sortOrder": "descending" } url = base_url + "?" + urllib.parse.urlencode(params) with urllib.request.urlopen(url, timeout=30) as response: xml_data = response.read().decode("utf-8") return xml_data这里有几个实操要点值得展开。第一,时间窗口的设置。ArXiv的submittedDate用的是UTC时间,而论文的实际提交时间可能跨越多个时区,所以我会把窗口稍微放宽一点,比如拉取过去36小时的数据,然后在解析阶段根据论文ID去重。第二,max_results的限制。ArXiv API单次请求最多返回2000条结果,但实际使用中我建议不要超过500条,因为返回数据量太大会导致解析变慢,而且CV板块每天的新论文数量很少超过300篇。第三,请求频率的控制。ArXiv官方建议每次请求之间至少间隔3秒,我在脚本里加了time.sleep(3),避免因为请求过于频繁而被限流。
3.2 论文摘要的清洗与关键信息提取
ArXiv返回的摘要里经常包含LaTeX公式,比如$L_{total}$、\textbf{...}、\cite{...}等。如果直接展示,阅读体验会很差。我写了一个清洗函数,把常见的LaTeX标记替换成可读文本:
import re def clean_abstract(abstract): # 移除LaTeX公式标记,保留公式内容 abstract = re.sub(r'\$([^$]+)\$', r'\1', abstract) # 移除常见的LaTeX命令 abstract = re.sub(r'\\[a-zA-Z]+\{([^}]*)\}', r'\1', abstract) # 移除多余的空白字符 abstract = re.sub(r'\s+', ' ', abstract).strip() # 替换特殊符号 abstract = abstract.replace('~', ' ').replace('--', '-') return abstract除了清洗,我还从摘要里提取了几个关键信息:是否包含开源代码链接(通常出现在摘要末尾的"Code is available at...")、是否提到了具体的模型名称(比如YOLO、Transformer、Diffusion等)、是否涉及特定的数据集(比如COCO、ImageNet、KITTI等)。这些信息会作为额外的标签,帮助我在浏览时快速判断论文的相关性。
3.3 关键词过滤与权重设计的经验
关键词过滤看起来简单,但实际调优需要不少经验。我最初的做法是维护一个关键词列表,只要标题或摘要里出现就保留。但很快发现两个问题:一是误报率高,比如"detection"这个词在医学影像、遥感、自动驾驶里都出现,但我只关心通用目标检测;二是漏报率高,有些论文用的是同义词或新造词,比如用"localization"代替"detection",用"segment anything"代替"segmentation"。
后来我改成了分层关键词体系。第一层是核心关键词,比如"object detection"、"semantic segmentation"、"vision transformer",这些词出现时权重加3分。第二层是扩展关键词,比如"anchor-free"、"feature pyramid"、"attention mechanism",权重加2分。第三层是排除关键词,比如"medical image"、"remote sensing"、"autonomous driving"(如果我不做这些方向),出现时直接过滤掉。
权重的计算方式是这样的:每篇论文的初始分数为0,标题中出现核心关键词加5分,摘要中出现加3分;标题中出现扩展关键词加3分,摘要中出现加1分;如果出现排除关键词,直接标记为不相关。最后按总分排序,取Top N篇。
提示:关键词列表需要定期更新。我每个月会花半小时回顾一下过去一个月的论文标题,看看有没有新的热门术语出现,及时补充到关键词列表里。
3.4 语义相似度排序的实现方案
关键词过滤能解决大部分问题,但对于一些用词新颖、跨领域的论文,关键词可能覆盖不到。这时候语义相似度排序就派上用场了。我的做法是:维护一个参考论文集合,里面是我过去半年收藏的、认为高质量的论文摘要。然后用一个轻量级的文本嵌入模型(比如all-MiniLM-L6-v2)把所有参考摘要编码成向量,存成一个矩阵。每天新拉取的论文摘要也编码成向量,计算与参考矩阵的余弦相似度,取最大值作为该论文的语义得分。
from sentence_transformers import SentenceTransformer import numpy as np model = SentenceTransformer('all-MiniLM-L6-v2') def compute_semantic_scores(new_abstracts, reference_abstracts): ref_embeddings = model.encode(reference_abstracts, normalize_embeddings=True) new_embeddings = model.encode(new_abstracts, normalize_embeddings=True) # 计算余弦相似度矩阵 similarity_matrix = np.dot(new_embeddings, ref_embeddings.T) # 取每篇新论文与所有参考论文的最大相似度 max_similarities = np.max(similarity_matrix, axis=1) return max_similarities这个方案的优点是不需要训练,直接用预训练模型就能跑,而且效果相当不错。我实测下来,语义得分高的论文,确实和我当前的研究方向更相关。缺点是计算资源消耗,如果参考论文有几百篇,每天新论文也有几百篇,编码和相似度计算需要几秒钟。不过对于每天跑一次的脚本来说,这点时间完全可以接受。
4. 实操过程与核心环节实现
4.1 环境准备与依赖安装
这套系统对硬件要求很低,一台普通的开发机或者云服务器就能跑。我目前是跑在一台2核4G的轻量服务器上,每天定时执行,资源占用可以忽略不计。操作系统我用的是Ubuntu 22.04,Python版本是3.10。
依赖安装很简单,核心的库就几个:
pip install requests feedparser sentence-transformers numpy pandas jinja2这里解释一下每个库的作用。requests用于发送HTTP请求,虽然我用的是urllib,但requests在处理超时和重试时更方便;feedparser是专门解析Atom和RSS格式的库,比手动解析XML省事很多;sentence-transformers提供文本嵌入模型;numpy用于向量计算;pandas用于数据整理和导出;jinja2用于生成HTML邮件模板。
注意:
sentence-transformers第一次运行时会自动下载模型文件,大约80MB左右。如果服务器网络环境不好,可以提前手动下载模型放到缓存目录。
4.2 完整脚本的编写与调试
我把整个脚本拆成了几个模块,放在同一个目录下:
arxiv_daily/ ├── config.py # 配置文件,存放关键词列表、参考论文路径等 ├── fetcher.py # 拉取ArXiv数据 ├── parser.py # 解析XML,提取字段 ├── filter.py # 关键词过滤和语义排序 ├── pusher.py # 终端输出和邮件推送 ├── main.py # 主入口,串联所有模块 └── data/ ├── references.txt # 参考论文摘要 └── history.json # 历史拉取记录,用于去重main.py的逻辑很直接:
from fetcher import fetch_arxiv_cv_papers from parser import parse_arxiv_xml from filter import filter_and_rank from pusher import push_to_terminal, push_to_email def main(): # 1. 拉取数据 xml_data = fetch_arxiv_cv_papers(days_back=1, max_results=300) # 2. 解析数据 papers = parse_arxiv_xml(xml_data) print(f"拉取到 {len(papers)} 篇论文") # 3. 去重 papers = deduplicate(papers, history_file="data/history.json") print(f"去重后剩余 {len(papers)} 篇论文") # 4. 过滤和排序 ranked_papers = filter_and_rank(papers, config) # 5. 推送 push_to_terminal(ranked_papers, top_n=20) push_to_email(ranked_papers, top_n=20, recipient="your_email@example.com") # 6. 更新历史记录 update_history(papers, history_file="data/history.json") if __name__ == "__main__": main()调试过程中我遇到的最大问题是编码问题。ArXiv返回的XML里有些特殊字符,比如作者名字里的重音符号、摘要里的数学符号,直接用utf-8解码有时会报错。我的解决方案是在解码时加上errors='ignore',把无法解码的字符直接跳过,虽然会丢失少量信息,但保证了脚本的稳定性。
另一个问题是邮件推送的格式。最初我用的是纯文本邮件,但论文列表在手机上看起来很不方便。后来改用HTML格式,用jinja2模板渲染,每篇论文一个卡片,包含标题、作者、摘要、链接,视觉效果好了很多。
4.3 定时任务的配置与监控
脚本写好后,我用cron设置了每天定时执行。具体配置如下:
# 每天早上8点30分执行 30 8 * * * /usr/bin/python3 /path/to/arxiv_daily/main.py >> /path/to/arxiv_daily/logs/cron.log 2>&1这里有几个细节值得注意。第一,使用绝对路径。cron的环境变量和用户登录时的环境变量不一样,所以Python解释器的路径和脚本的路径都要写绝对路径。第二,日志重定向。把标准输出和标准错误都重定向到日志文件,方便排查问题。第三,执行时间的选择。ArXiv的论文发布时间集中在美东时间下午到晚上,对应北京时间第二天早上,所以早上8点30分执行,刚好能拉到前一天的所有论文。
监控方面,我加了一个简单的心跳检测:每次脚本执行成功后,会往一个本地的heartbeat.txt文件写入当前时间戳。然后我另外写了一个小脚本,每天检查这个文件的时间戳是否在24小时内,如果超过24小时没有更新,就发一封告警邮件给我。这个机制帮我发现过几次问题,比如API接口临时不可用、服务器磁盘满了导致脚本无法写入等。
4.4 推送内容的排版与阅读体验优化
邮件推送的排版我调整过很多次,最终定下来的格式是这样的:邮件标题是"ArXiv CV Daily - 2026.10.06 - 共23篇精选",正文开头是一段简短的统计信息,比如"今日共拉取187篇论文,经过滤排序后精选23篇"。然后每篇论文一个卡片,卡片里包含:
- 标题:加粗显示,字号稍大
- 作者:显示前三位作者,后面加"et al."
- 摘要:截取前200字,末尾加"..."
- 标签:显示关键词匹配的标签,比如"目标检测"、"多模态"、"开源代码"
- 链接:PDF链接和ArXiv摘要页链接
为了让邮件在手机上也能正常显示,我用了响应式的HTML模板,卡片宽度自适应屏幕。另外,我把每篇论文的摘要截取长度控制在200字左右,太长了在手机上要滑很久,太短了又看不出论文的核心内容。
实操心得:邮件推送的Top N不要设太多。我最初设了50篇,结果每天早上要花20分钟才能看完,后来降到20篇,反而效率更高。因为排在前面的论文相关性最高,后面的论文即使看了,大概率也不会精读。
5. 常见问题与排查技巧实录
5.1 拉取失败与超时处理
ArXiv API偶尔会出现响应慢或者超时的情况,尤其是在北京时间早上八九点这个时间段,因为很多人的脚本都在这个时候跑。我遇到过几次urllib的超时错误,后来加了重试机制:
import time import urllib.request def fetch_with_retry(url, max_retries=3, timeout=30): for attempt in range(max_retries): try: with urllib.request.urlopen(url, timeout=timeout) as response: return response.read().decode("utf-8", errors="ignore") except Exception as e: print(f"第{attempt+1}次请求失败: {e}") if attempt < max_retries - 1: time.sleep(5 * (attempt + 1)) # 指数退避 else: raise这个重试机制的核心是指数退避:第一次失败等5秒,第二次失败等10秒,第三次失败等15秒。这样既能应对临时性的网络波动,又不会因为频繁重试而被ArXiv限流。
5.2 论文去重与历史记录管理
ArXiv的论文ID是唯一的,但有时候同一篇论文会因为版本更新(v1、v2、v3)而重复出现。我的去重策略是:只保留论文ID的基础部分,忽略版本号。比如2401.12345v2和2401.12345v1视为同一篇论文,只保留最新的版本。
历史记录我用一个JSON文件存储,结构是这样的:
{ "seen_ids": ["2401.12345", "2401.12346", "..."], "last_updated": "2026-10-06T08:30:00Z" }每次拉取后,把新论文的ID追加到seen_ids列表里。为了避免文件无限增长,我设置了一个上限:只保留最近30天的记录,超过30天的自动清理。这样既保证了去重的准确性,又不会让文件变得太大。
5.3 关键词过滤的误报与漏报调优
关键词过滤的调优是一个持续的过程。我整理了一个常见问题速查表,供大家参考:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 过滤后论文数量太少 | 关键词列表太窄 | 增加扩展关键词,降低权重阈值 |
| 过滤后论文数量太多 | 关键词列表太宽 | 增加排除关键词,提高权重阈值 |
| 相关论文被漏掉 | 关键词未覆盖新术语 | 定期回顾论文标题,补充新词 |
| 不相关论文被保留 | 关键词歧义 | 使用更精确的短语,如"object detection"代替"detection" |
| 语义排序效果差 | 参考论文太少或太杂 | 增加高质量参考论文,清理不相关的参考 |
我个人的经验是,关键词列表不要超过50个,太多了反而不好维护。而且关键词要定期清理,把那些长期没有匹配到相关论文的关键词删掉,保持列表的精简。
5.4 邮件推送被拦截或进入垃圾箱
邮件推送最头疼的问题是被邮件服务商拦截。我最初用SMTP直接发送,结果很多邮件都进了垃圾箱。后来我做了几件事来解决这个问题:第一,使用专业的邮件发送服务,而不是直接用自己的邮箱SMTP;第二,设置SPF和DKIM记录,提高邮件的可信度;第三,控制发送频率,每天只发一封,不要短时间内发送大量邮件;第四,在邮件内容里加入退订链接,虽然是我自己用的,但加上这个能降低被判定为垃圾邮件的概率。
如果不想折腾邮件服务,还有一个替代方案:用即时通讯工具的机器人推送。很多团队协作工具都支持自定义机器人,通过Webhook把消息推送到指定的频道。这种方式比邮件更即时,而且不容易被拦截。
5.5 脚本执行时间过长与性能优化
随着参考论文数量的增加,语义相似度计算的时间会逐渐变长。我实测下来,当参考论文超过500篇时,每天的脚本执行时间会从几秒增加到十几秒。虽然不算慢,但还有优化空间。
我的优化方案是预计算参考论文的嵌入向量。参考论文集合相对稳定,不需要每天重新编码。我把参考论文的嵌入向量存成一个.npy文件,每天只需要编码新论文,然后和预计算的参考矩阵做相似度计算。这样能把执行时间缩短一半以上。
import numpy as np import os def get_reference_embeddings(reference_abstracts, cache_file="data/ref_embeddings.npy"): if os.path.exists(cache_file): return np.load(cache_file) else: embeddings = model.encode(reference_abstracts, normalize_embeddings=True) np.save(cache_file, embeddings) return embeddings注意:如果参考论文集合有更新,需要删除缓存文件,让脚本重新计算。我一般在每月初更新参考论文后,手动删一次缓存。
6. 系统扩展与个性化定制
6.1 多分类追踪与标签体系
如果你同时关注多个CV子方向,比如目标检测、图像分割、多模态、视频理解,可以在关键词体系里增加分类标签。每篇论文根据匹配到的关键词,自动打上对应的标签。这样在浏览时,可以按标签筛选,快速定位到某个方向的论文。
我的标签体系是这样的:
| 标签 | 关键词示例 | 权重 |
|---|---|---|
| 目标检测 | object detection, anchor-free, DETR | 5 |
| 图像分割 | semantic segmentation, instance segmentation, SAM | 5 |
| 多模态 | vision-language, CLIP, multimodal | 4 |
| 视频理解 | video understanding, action recognition | 4 |
| 模型压缩 | quantization, pruning, knowledge distillation | 3 |
| 生成模型 | diffusion, GAN, image generation | 3 |
标签的权重会影响论文的最终排序。比如我当前的重点是目标检测和多模态,那么这两个标签的权重就设得高一些,相关论文会排在前面。
6.2 论文笔记与阅读状态管理
光推送还不够,我还加了一个阅读状态管理的功能。每篇推送的论文,我可以在终端里用快捷键标记为"已读"、"收藏"、"忽略"。这些状态会记录在一个本地数据库里,下次推送时,已经标记为"已读"或"忽略"的论文不会再出现。
这个功能用sqlite3实现,表结构很简单:
CREATE TABLE paper_status ( paper_id TEXT PRIMARY KEY, status TEXT DEFAULT 'unread', updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );终端交互我用的是curses库,实现了一个简单的文本界面,可以用上下键浏览论文列表,按r标记已读,按s收藏,按i忽略。虽然界面简陋,但用起来很顺手。
6.3 周报与月报的自动生成
除了每日推送,我还加了一个周报生成的功能。每周日晚上,脚本会自动汇总过去一周的论文,按标签分类,统计每个标签下的论文数量,并挑选出语义得分最高的10篇,生成一份周报邮件。月报也是类似的逻辑,只是时间跨度更长,统计维度更多。
周报的价值在于回顾和整理。每天看论文是碎片化的,周末花半小时看一下周报,能对过去一周的领域动态有一个整体的把握。而且周报里的论文是经过一周时间沉淀的,质量相对更高。
7. 我踩过的坑与独家经验
7.1 不要过度依赖自动化筛选
我最初的想法是:让脚本自动筛选出最相关的论文,我只看脚本推荐的就行了。但实际用下来发现,自动化筛选只能解决80%的问题,剩下的20%需要人工判断。有些论文的标题和摘要写得很抽象,关键词匹配不到,语义相似度也不高,但实际内容可能非常有价值。所以我现在每天还是会花几分钟快速浏览一下被过滤掉的论文标题,看看有没有漏网之鱼。
7.2 参考论文的质量比数量更重要
语义相似度排序的效果,很大程度上取决于参考论文的质量。我最初往参考集合里塞了200多篇论文,结果发现排序效果反而变差了,因为里面有一些论文其实和我当前的研究方向并不完全一致。后来我精简到50篇,只保留我真正精读过、认为高质量、且方向高度相关的论文,排序效果明显提升。
7.3 定时任务的时间要避开高峰期
ArXiv API在北京时间早上8点到10点之间响应最慢,因为很多人的脚本都在这个时间段跑。我后来把执行时间调整到早上6点30分,响应速度明显快了很多,而且邮件也能在8点前送到,正好赶上我早上到办公室的时间。
7.4 日志要详细,但不要冗余
脚本的日志我调整过好几次。最初只记录成功或失败,后来发现排查问题时信息不够。现在我的日志分三级:INFO记录每天拉取了多少篇、过滤后剩多少篇、推送了多少篇;WARNING记录重试、超时、解析失败等异常;ERROR记录脚本崩溃、API不可用等严重问题。日志文件按天切割,保留最近30天。
7.5 不要忽视邮件模板的兼容性
邮件HTML模板在不同客户端里的渲染效果差异很大。我最初用了一些CSS3的特性,结果在某个常用邮箱的网页端显示正常,但在手机客户端上布局全乱了。后来我改用表格布局,虽然老土,但兼容性最好。另外,图片尽量用外链,不要用内嵌的base64图片,因为很多邮件客户端会拦截base64图片。
8. 后续可以这样扩展
这套系统目前满足了我的日常需求,但还有一些可以扩展的方向。比如加入引用量数据,虽然ArXiv不提供,但可以通过其他公开接口获取,帮助判断论文的影响力。再比如加入代码可用性检测,自动检查论文是否关联了开源仓库,并抓取仓库的Star数,作为质量参考。还有一个想法是加入论文之间的引用关系图,看看哪些论文被同一天的其他论文引用了,这样能快速发现热点方向。
另外,如果你对移动端体验有要求,可以把推送内容做成一个简单的静态网页,部署在本地或者内网,每天更新。这样在手机浏览器里打开就能看,比邮件更灵活。我用pelican搭了一个静态站点,每天生成一个HTML页面,效果还不错。
最后分享一个小技巧:把论文PDF自动下载到本地。我在推送脚本里加了一个可选步骤,对于语义得分最高的5篇论文,自动下载PDF到本地文件夹,按日期和标签分类存放。这样即使ArXiv临时不可访问,我本地也有备份,而且离线阅读更方便。下载的时候注意控制频率,不要一次性下载太多,避免给ArXiv服务器造成压力。