导师甩过来一个研究方向,让我把这几年相关的Arxiv论文都过一遍,再整理到NoteExpress里方便后面写综述。我一开始老老实实一篇篇手动下载PDF、手动建题录,搞了二十几篇眼睛就花了,整个下午全耗在这上面。后来自己摸索出一套用Arxiv API批量抓题录、脚本批量下载PDF、再统一灌进NoteExpress的流程,现在从拿到关键词到文献库整理好,熟练之后确实能控制在5分钟以内。这篇文章就把这套流程完整拆给你看,包括题录怎么批量生成、PDF怎么自动落盘、NoteExpress导入时有哪些字段坑和编码坑,全是我实际操作中踩过之后总结出来的。
先说明一下这套方案的适用人群:手头有明确的研究方向或关键词,需要批量收集某个主题的Arxiv论文;或者想定期追踪某个子领域的最新投稿;再或者像我一样被导师临时布置了文献调研任务,需要在最短时间内把一批论文变成“白天可引用、晚上可阅读”的文献库。只要你用的是NoteExpress,并且愿意开个Python脚本跑一下,这套流程基本能直接抄作业。下面从头讲。
1. 为什么在Arxiv和NoteExpress之间,最省力的门道是“题录先行”
1.1 NoteExpress导文献的三种常见姿势
用NoteExpress这几年,我总结它接纳文献主要有三条路:在线检索、文件导入、PDF识别导入。三条路各有各的使用场景,但对于“Arxiv批量论文”这个需求,三条路的体验差距非常大。
在线检索是NoteExpress内置的数据库通道,相当于你在软件里直接连到PubMed、知网这类数据源去查。问题是Arxiv并不在它默认的常用数据库列表里,想通过这个入口批量拿Arxiv题录,要么自己配置Z39.50之类的外部连接,要么反复切换数据源,折腾半天还不如手动。我的建议是,在线检索适合补漏单篇,不适合做批量。
文件导入是真正适合批量场景的方式。你先从外部拿到一份标准格式的题录文件,比如BibTeX文件或者RIS文件,然后在NoteExpress里执行“文件→导入题录”,选择一个对应的过滤器,软件就会把整批题录自动解析成条目。Arxiv本身提供BibTeX导出,也提供标准API让你自己生成RIS,这条路最干净。
PDF识别导入是另一种思路,你先把PDF文件下载到本地,然后用NoteExpress的“导入文件”功能,让软件去解析PDF内嵌的元数据来生成题录。这个方案的优点是省去手动建题录的步骤,缺点也很明显:Arxiv下载的PDF元数据并不总是规范,部分论文识别出来的标题带换行,作者被拆成两个人,识别不出来的时候还要手动修。所以PDF识别导入适合数量少、不追求字段完整的情况。
1.2 为什么Arxiv批量场景不推荐在线检索
很多人拿到批量需求后,第一个反应是打开NoteExpress的在线检索,心想直接在软件里搜多省事。但实际用下来你会发现两个问题:第一个是Arxiv在NoteExpress默认数据源里基本搜不到,需要额外配置;第二个是即使配置成功,在线检索一次返回的题录数量也有限,翻页加载要等,遇到网络波动还会中断。
更重要的问题是,Arxiv上的“论文”和传统的“期刊论文”不太一样,很多还是预印本状态,后期可能v1、v2更新好几版。在线检索通常检索的是数据库快照,不一定是最新版本,也不一定能拿到准确的Arxiv编号。所以对于“按主题批量收集近期论文”这种需求,直接从Arxiv自己的API拿数据是最准确的,因为数据源就是它自己。
1.3 “题录先行”的整体流程
我最终采用的方案可以总结成三步:先抓题录,再下PDF,最后做关联。
第一步,用Arxiv API按关键词搜出论文元数据,生成一个RIS格式的题录文件。第二步,用一个简单的Python脚本按Arxiv编号批量下载PDF到本地文件夹。第三步,在NoteExpress中导入RIS文件,然后把PDF按一定规则批量关联到对应题录下。
这个顺序为什么合理?因为题录是PDF的“索引”,有了准确的题录再挂PDF,软件才能把两者匹配上。反过来如果你先下载一堆PDF再让软件识别,可能会因为PDF元数据不全而出现大量脏数据。这一顺序在我跑了几百篇文献后验证下来是最稳的,后面每一步我都会说明理由。
2. 先搞到一批题录:Arxiv API的查询语法与RIS生成
2.1 Arxiv API能做什么,查询语法怎么写
Arxiv的官方API地址是http://export.arxiv.org/api/query,通过HTTP GET请求就能拿回论文元数据。它支持的查询字段相当丰富,常用的有这么几个:
au:按作者查,比如au:Smith。ti:按标题查,比如ti:"diffusion model"。abs:按摘要查。cat:按学科分类查,比如cat:cs.CV表示计算机视觉。all:在所有字段里全局搜。
多个条件用AND、OR、ANDNOT连接,组合起来可以很精细。举个例子,我想找计算机视觉方向标题里带“diffusion model”的论文,查询式就写成:
ti:"diffusion model" AND cat:cs.CV也可以加sortBy=submittedDate和sortOrder=descending,让结果按提交时间倒序排列,非常适合追踪最新论文。请求时还可以通过start和max_results控制分页,一次最多建议取100条,太多会超时。
API返回的是Atom格式的XML,里面包含标题、作者、摘要、发布时间、DOI、PDF链接等信息,非常完整。想快速验证返回结果的话,浏览器直接打开下面这个地址就能看到XML内容:
https://export.arxiv.org/api/query?search_query=ti:%22diffusion%20model%22%20AND%20cat:cs.CV&max_results=32.2 用Python批量抓取并生成RIS
直接读XML对大多数人来说不友好,所以我会用Python的feedparser库来解析。这个库本身就是用来处理RSS/Atom的,解析Arxiv返回结果几乎是开箱即用。
先安装依赖:
pip install feedparser requests然后下面这段脚本,可以根据你的查询式抓取指定数量的论文,生成一个RIS文件,同时打印出每篇论文的标题和Arxiv编号:
import os import re import time import requests import feedparser API_URL = "https://export.arxiv.org/api/query" PDF_BASE = "https://arxiv.org/pdf" def fetch_entries(query, max_results=20): params = { "search_query": query, "start": 0, "max_results": max_results, "sortBy": "submittedDate", "sortOrder": "descending", } resp = requests.get(API_URL, params=params, timeout=30) feed = feedparser.parse(resp.text) return feed.entries def build_ris(entry): # 清理标题和摘要中的多余换行 title = re.sub(r"\s+", " ", entry.title).strip() abstract = re.sub(r"\s+", " ", entry.summary).strip() published_year = entry.published[:4] arxiv_id = entry.id.split("/abs/")[-1] author_lines = "" for author in entry.authors: author_lines += f"AU - {author['name']}\n" # 生成RIS格式的题录 ris = ( f"TY - JOUR\n" f"{author_lines}" f"TI - {title}\n" f"PY - {published_year}\n" f"UR - https://arxiv.org/abs/{arxiv_id}\n" f"DO - 10.48550/arXiv.{arxiv_id}\n" f"AB - {abstract}\n" f"ER - \n\n" ) return ris, arxiv_id, title query = 'ti:"diffusion model" AND cat:cs.CV' entries = fetch_entries(query, max_results=10) ris_all = "" for entry in entries: ris, arxiv_id, title = build_ris(entry) ris_all += ris print(arxiv_id, "-", title) with open("arxiv_papers.ris", "w", encoding="utf-8") as f: f.write(ris_all)这段代码生成的arxiv_papers.ris文件里面,每一条记录包含文献类型、作者、标题、年份、Arxiv链接、DOI和摘要,信息完整度足够NoteExpress导入使用。
2.3 没有编程基础时的替代玩法
如果你完全不想碰代码,也有几条路可以走。Arxiv单篇论文页面上有一个“Export Citation”按钮,可以直接导出BibTeX,你需要做的就是一篇篇点开论文,复制导出内容,再粘贴到一个.bib文件里。论文少的时候这样操作还能接受,超过十篇就开始折磨人。
另一个办法是去Google Scholar搜索相关论文,勾选自己需要的条目,然后通过“导出”功能批量生成BibTeX格式的题录。缺点是Google Scholar对Arxiv预印本的收录有滞后,而且批量勾选的比例尺不如API灵活。
还有一种思路:很多热门方向的综述或者开源项目,作者会在GitHub仓库里放一份references.bib,里面已经整理好了该方向的核心文献,直接下载下来作为导入源也很方便。这个方法最适合“先读一小批核心文献”的场景,不适合“把某个方向近一年所有论文都过一遍”的场景。
3. 把题录灌进NoteExpress:导入过滤器、字段映射与首轮清洗
3.1 文件导入操作与过滤器选择
拿到arxiv_papers.ris之后,打开NoteExpress,选择“文件→导入题录”,在弹出的窗口里选择刚生成的RIS文件。接下来最关键的一步是选择过滤器,NoteExpress内置了多个格式的过滤器,这里面直接选“RIS”就行。如果你下载的是.bib文件,就选“BibTeX”。
选错过滤器的后果是字段全部错位:标题跑到作者栏,年份消失,甚至整条记录显示为乱码。所以导入前先检查右下角预览区域,看看解析结果是否正确,再点确定。
导入完成后,左侧目录树里会多出一个“导入的题录”或类似的临时文件夹,里面就是刚才解析出来的所有条目。这时候建议先不要着急整理,先做一遍字段检查。
3.2 字段映射的几个易错点
我在实际操作中发现,RIS格式导入后最容易出问题的是两个字段:摘要和文献类型。
很多论文摘要特别长,里面带有特殊字符,比如数学公式里的$符号、LaTeX命令、换行符,如果脚本没有提前清理,导入后摘要要么被截断,要么显示成乱码。所以我在上面的脚本里特意使用re.sub(r"\s+", " ", entry.summary)把所有连续空白字符压缩成单个空格,这个处理对字段完整度帮助很大。
文献类型同样需要注意。RIS标准里TY - JOUR表示期刊文章,但Arxiv论文严格来说不是期刊文章,而是预印本。导入后会默认归类为“期刊文章”,这算NoteExpress的一种妥协。如果你们课题组的文献库对文献类型要求比较严格,建议导入后全选这些题录,右键选择“批量编辑”,把文献类型改成“科技报告”或“预印本”,这个操作在NE 3.x里是支持的。
3.3 去重与查漏:导入后先做哪些事
批量操作一旦上了规模,去重就是绕不开的话题。Arxiv上同一篇论文可能有v1、v2、v3多个版本,API默认返回最新版本,但如果你之前已经手动导入过旧版本,两条记录会同时出现在库里。更常见的情况是,同一篇论文既有Arxiv编号又有正式发表的DOI,你在不同时间分别用不同途径导入,就会产生重复条目。
NoteExpress有一个“查找重复题录”的功能,在“检索”菜单下可以找到,选择按标题或DOI匹配,软件会把疑似重复的条目列出来。处理这类重复时,我一般是保留Arxiv编号那条,删掉DOI那条,因为对预印本来说Arxiv编号更原生,能直接链回预印本页面。
另外还要检查一下有没有“孤儿题录”,也就是只有标题、作者,但URL和DOI都是空的条目。这种情况通常是RIS生成时字段没写入,手工补一下Arxiv编号即可。总之导入后花两三分钟做一轮清洗,后面引用的时候能省下大麻烦。
4. PDF自动下载与批量关联,附两种实用姿势
4.1 姿势A:脚本按编号批量下载PDF
Arxiv的PDF下载链接很有规律,论文编号是2410.02644,那么PDF地址就是https://arxiv.org/pdf/2410.02644。知道了这个规律,批量下载就变成了一个简单的循环请求。
下面的脚本直接在上一段生成的题录基础上运行,它会从RIS文件里提取所有Arxiv编号,然后逐一尝试下载PDF到本地:保存文件名就用Arxiv编号,比如2410.02644.pdf。
import os import re import time import requests PDF_BASE = "https://arxiv.org/pdf" def download_pdf(arxiv_id, folder="pdfs"): os.makedirs(folder, exist_ok=True) url = f"{PDF_BASE}/{arxiv_id}" filepath = os.path.join(folder, f"{arxiv_id}.pdf") if os.path.exists(filepath): return filepath headers = {"User-Agent": "Mozilla/5.0"} resp = requests.get(url, headers=headers, timeout=30) if resp.status_code == 200 and resp.content[:5] == b"%PDF-": with open(filepath, "wb") as f: f.write(resp.content) print("下载成功:", arxiv_id) else: print("下载失败:", arxiv_id, resp.status_code) # 从上一步生成的RIS中提取编号 with open("arxiv_papers.ris", "r", encoding="utf-8") as f: content = f.read() ids = re.findall(r"https://arxiv.org/abs/(\d+\.\d+)", content) for aid in ids: download_pdf(aid) time.sleep(1) # 控制请求频率,避免被服务器限流这里有几个下载细节值得注意。第一,我判断文件是否真的是PDF,不只看状态码,还检查了文件头前几个字节是否是%PDF-,这是最稳妥的校验方式,防止服务器返回一个HTML错误页却被当成PDF保存。第二,每次请求后加1秒延时,这是对服务器的基本礼貌,也避免大批量下载时被封IP。第三,如果网络环境访问Arxiv比较慢,可以把PDF_BASE换成你常用的镜像地址,其他逻辑不变。
批量下载完成后,pdfs文件夹里就是所有论文的PDF。这一步走完,主流程最难的部分已经解决了。
4.2 姿势B:先有题录,再用NE在线更新拉全文
说完整脚本方案,再补充一个“懒人方案”。如果你不想自己写下载逻辑,也可以在题录导入NoteExpress之后,右键选中一条题录,选择“在线更新”或者“自动更新”。NE会根据题录的标题、DOI去匹配在线数据源,某些数据源能直接返回开放全文的PDF。
不过根据我的实际体验,这个方案对Arxiv论文并不稳定。Arxiv的DOI通常是10.48550/arXiv.2410.02644这种特殊格式,不是所有数据源都认。几十条题录里能自动拉到一大半就算不错,剩下那些你还得手动找。所以我个人更推荐脚本方案,它能保证100%下载成功,并且完全可控。
4.3 让NE把PDF和题录“对上号”的命名与关联技巧
PDF文件下载好了,题录也导入完了,最后一步是把两者关联起来。这一步最省力的方式,是让PDF文件名和题录标题形成对应关系。
如果你用Arxiv编号作为文件名,而NE题录里恰好有Arxiv链接,两者能对应上,手动关联时也比较容易找。实际操作中,我真正推荐的做法更直接:在NE中选中一条题录,右键选择“添加附件→文件”,然后选择对应的PDF文件。这样PDF会成为题录的附件,双击就能打开阅读。
但一次选中多篇题录再批量添加附件,NE并不支持一个操作把一堆PDF全挂上去。我的土办法是:先把PDF文件按题录顺序排列在文件夹里,然后在NE里从上到下逐条选中题录,依次添加附件。听起来麻烦,其实一百篇以内的量,整个过程不到十分钟。
还有个细节是PDF文件名不要包含/、:、*这些Windows非法字符,否则文件写入失败。脚本里我统一用Arxiv编号命名,就是为了彻底避开这个问题。
5. 一次完整的20分钟实录:从关键词到可阅读的分组库
理论说了这么多,我把最近一次实际操作完整记录一遍。这次的任务主题是“找计算机视觉领域标题含diffusion model的最新论文”,范围限定在cs.CV分类,目标数量15篇。
先确定查询式:
ti:"diffusion model" AND cat:cs.CV在脚本里把max_results设为15,运行抓取脚本,终端会打印出15条论文编号和标题。我扫了一眼,基本覆盖了近期的相关投稿,没有出现其他领域的噪声论文,标题字段匹配效果符合预期。接着运行下载PDF的脚本,15个PDF陆续落入pdfs文件夹,除了第一篇因为服务器响应慢多等了十几秒,其余都很顺利。
打开NoteExpress,执行“文件→导入题录”,选中生成的arxiv_papers.ris,过滤器选“RIS”。导入完成后看预览区域,15条题录全部解析成功,作者、年份、摘要、Arxiv链接都正确填充。随手点开一条,摘要里的数学符号都清理干净了,没有出现截断或乱码。
然后我开始建立分类结构。在NE左侧目录树里新建一个文件夹,命名为“DiffusionModel调研”,把15条题录全选拖进去。接着从pdfs文件夹里按顺序选择PDF,逐条关联到对应题录下。全部关联完成后,每条题录前面多了一个PDF附件图标,双击能直接读全文。
顺手又检查了一遍重复题录,发现有一篇论文同时在列表里出现了两次,原因是API返回的结果里包含了它的v1和v2两个版本。通过“查找重复题录”功能合并掉一条,整个文献库干净了。最后给这个文件夹加了一条备注,写明检索时间和检索式,方便以后写综述时注明文献来源。
从我打开终端到文献库整理完毕,全程大概二十分钟。第一次操作要多花一点时间适应脚本逻辑,跑顺之后确实能接近5分钟一台。
6. 批量操作最容易踩的六个坑与现场修复
6.1 编码乱码:UTF-8与GBK的恩怨
Windows上很多软件对UTF-8的支持并不彻底,NoteExpress在某些版本里默认按GBK去读导入文件。如果你生成的RIS包含中文摘要,导入后很可能看到一串乱码。解决办法是在脚本里明确指定写文件时用UTF-8编码,比如open("arxiv_papers.ris", "w", encoding="utf-8")。如果导入时还乱码,可以先用记事本把RIS文件另存为UTF-8带BOM的格式,再重新导入。
6.2 重复条目:arXiv编号和DOI并存时怎么去重
同一篇论文,正式发表后会有期刊DOI,同时也有Arxiv DOI。你在不同时间分别用在线检索和RIS导入两个渠道把它加进库,就会产生重复。去重时我的原则是保留Arxiv编号记录,因为对于预印本来说,Arxiv链接是更稳定的一手来源。期刊正式版本如果需要,可以后续手动补一个正式DOI字段,不需要单独建一条重复题录。
6.3 特殊字符把BibTeX撑爆:$、%和{}的处理
直接从Arxiv API拿到的标题里偶尔会带LaTeX数学公式,比如Text-to-Image Diffusion Models are Zero-Shot这类还正常,但像Diffusion Models Beat GANs on $256 \times 256$这种标题,里面的$和\times如果原样写进BibTeX文件,很多解析器会出错。解决办法就是生成题录时做一层清理,把标题和摘要里的LaTeX命令用正则表达式去掉,只保留纯文本。我在脚本里用re.sub清理空白其实只是第一步,如果遇到特殊字符问题,可以加一段正则把这些LaTeX标记删掉。
6.4 PDF命名和匹配失败的补救
有一段时间我图省事,直接把PDF文件名设置为论文完整标题,结果Windows不允许文件名包含冒号和斜杠,好几个文件直接保存失败。后来我统一改成Arxiv编号命名,问题迎刃而解。如果你已经有一大堆命名不规范的文件,也不要紧,NE里可以手动指定附件路径,只是操作上繁琐一点。我的建议是,不管用什么方法,从源头上让文件名符合规范最省事。
6.5 导入后作者变“未知”的怪现象
RIS中作者字段如果存在空行或者格式不完整,NE会把这组作者解析失败,显示为“未知”。比如Arxiv上有些论文作者一栏写的是“SomeAuthor et al.”,解析器可能直接把后面那段丢掉。这种问题只能手动修正,导入后扫一眼作者列,发现异常条目就点开补充完整。
6.6 备份意识:NE数据库损坏的止损方案
最后这一点很重要。NE的数据库文件是一体的,批量导入大量题录和附件时,如果软件异常退出,有一定概率导致数据库损坏。我身边真有同学一次性导入了两百多篇论文,结果NE闪退,重新打开后整个文献库变成只剩几十条。所以我养成一个习惯:批量操作之前,先把NE数据目录整个复制一份作为备份。现在很多网盘都支持自动同步,直接把数据目录放进同步盘,出问题也能随时回滚。
7. 进阶玩法:定时增量追踪、网页端导出和Zotero移植
7.1 定期跑一次,增量追踪某个方向的最新论文
如果你不只是做一次性调研,而是想长期跟踪某个研究方向,前面这套脚本完全可以改成定时任务。比如每周一早上自动跑一次脚本,查询条件固定好,max_results设为10,下载新增论文的PDF,并生成新的RIS文件。然后在NE里定期导入一次就行。
我自己的做法是把这个脚本放到一台长时间开机的电脑或者服务器上,配合系统的计划任务,每周自动执行。执行完后,把生成的RIS和PDF文件夹同步到网盘,在需要的时候打开NE导入即可。这样等于给自己做了一个轻量级的“论文订阅提醒”。
7.2 从Arxiv网页端和第三方工具导出题录
不想用脚本的时候,Arxiv网页端也有导出功能。在论文详情页找“Export Citation”按钮,可以选择导出BibTeX或EndNote格式。对单篇论文来说足够用。
第三方工具里,我比较常用的是Connected Papers和Semantic Scholar,前者适合按引用关系扩展文献,后者适合按作者或关键词批量获取题录。这些工具导出的BibTeX文件,也可以直接用前面说的“文件→导入题录”功能导入NoteExpress。遇到脚本不好使的场景,这是一个不错的备选方案。
7.3 Zotero或EndNote用户也能照抄逻辑
很多科研党用的不是NoteExpress,而是Zotero或EndNote,这个没关系。Arxiv API生成的RIS文件是通用的,Zotero直接导入RIS即可,EndNote同样支持。PDF批量下载那套逻辑更是和文献管理软件无关,谁都能用。本质上,这套方案的通用逻辑就一句话:从数据源头拿到结构化题录,再让文献管理软件去解析,不要让软件替你去“猜”文献元数据。
最后再分享一个我自己的使用习惯。我现在往NE里导入Arxiv论文前,会在RIS文件的KW字段里手动补充几个关键词,比如研究方向、方法类型、是否包含代码实验,导入后NE会把这些关键词识别成标签。后续写综述或者做文献分组时,直接按标签筛选,比挨个看标题效率高得多。这个习惯我坚持了大半年,文献库越大越觉得值得。