使用Python脚本订阅arxiv每日上新论文

news/2025/4/1 4:22:10/文章来源:https://www.cnblogs.com/pomolnc/p/18799599

本文涉及代码主要由deepseek提供。

这个事情主要是为了能够每天订阅到新的论文,另外是能够自动整理到知识库里面去,免得像邮件订阅或者 CSS 订阅一样去搬运。

主要涉及以下内容:

  1. 根据关键字搜索 arxiv 的论文,并提取信息
  2. 将摘要内容翻译成中文
  3. 按照指定格式,保存成 md 文件到指定位置

爬虫

搜索 arxiv 信息直接使用了 [[Python]] 的库 arxiv。

import arxiv

需要进行一些基础的配置,重点是搜索的关键字

# 配置参数
ARXIV_CONFIG = {"save_dir": os.path.expanduser("./"),  # 指定保存的位置"categories": [{"name": "机器人操作","query": "(ti:\"robot manipulation\" OR abs:\"grasping\" OR abs:\"motion planning\") AND cat:cs.RO","max_results": 30},{"name": "强化学习","query": "(abs:\"reinforcement learning\" OR abs:\"RL\" OR abs:\"Q-learning\") AND (cat:cs.LG OR cat:cs.AI)","max_results": 30},{"name": "VLA模型","query": "(abs:\"vision-language-action\" OR abs:\"VLA\" OR abs:\"embodied AI\") AND (cat:cs.CV OR cat:cs.CL)","max_results": 30}],"timezone_offset": 8,  # 时区偏移(UTC+8)"retries": 5,          # API请求重试次数"delay_seconds": 5     # 请求间隔
}# 日志配置
logging.basicConfig(level=logging.INFO,format="%(asctime)s - %(levelname)s - %(message)s",handlers=[logging.FileHandler(os.path.join(ARXIV_CONFIG["save_dir"], "arxiv.log")),logging.StreamHandler()]
)

接着创建请求客户端

def get_arxiv_client() -> arxiv.Client:"""创建带重试机制的arXiv客户端"""return arxiv.Client(page_size=100,delay_seconds=ARXIV_CONFIG["delay_seconds"],num_retries=ARXIV_CONFIG["retries"])

客户端可以根据关键字来进行检索

def fetch_category_papers(category: Dict) -> List[arxiv.Result]:"""抓取单个分类的最新论文"""client = get_arxiv_client()search = arxiv.Search(query=category["query"],max_results=category["max_results"],sort_by=arxiv.SortCriterion.SubmittedDate)try:papers = list(client.results(search))logging.info(f"[{category['name']}] 获取到{len(papers)}篇论文")return papersexcept:logging.error(f"[{category['name']}] API请求失败: {str(e)}")return []

检索到的文章放到命名为 papers 的列表中。

翻译

脚本中使用了腾讯翻译、百度翻译、和小牛翻译,用免费的额度就应该够了。

from hashlib import md5
import urllib.error
import urllib.parse
import urllib.request
import requests
import randomfrom tencentcloud.common import credential
from tencentcloud.tmt.v20180321 import tmt_client, models
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException

腾讯提供了封装好的库,其他两个用 request 来调用翻译的 API。

三种翻译服务的调用翻译的方式:

  • 腾讯云翻译
def tengxun_translate_text(text: str) -> str:try:cred = credential.Credential("your id", "you key")client = tmt_client.TmtClient(cred, "ap-beijing")req = models.TextTranslateRequest()req.SourceText = textreq.Source = "en"req.Target = "zh"req.ProjectId = 0resp = client.TextTranslate(req)return resp.TargetTextexcept Exception as e:logging.error(f"腾讯翻译失败: {str(e)}")return ""
  • 百度翻译
def make_md5(s, encoding='utf-8'):return md5(s.encode(encoding)).hexdigest()def baidu_translate_text(text: str) -> str:try:# Set your own appid/appkey.appid = 'your appid'appkey = 'your appkey'# For list of language codes, please refer to `https://api.fanyi.baidu.com/doc/21`from_lang = 'en'to_lang = 'zh'endpoint = 'http://api.fanyi.baidu.com'path = '/api/trans/vip/translate'url = endpoint + pathquery = text# Generate salt and signsalt = random.randint(32768, 65536)sign = make_md5(appid + query + str(salt) + appkey)# Build requestheaders = {'Content-Type': 'application/x-www-form-urlencoded'}payload = {'appid': appid, 'q': query, 'from': from_lang,'to': to_lang, 'salt': salt, 'sign': sign}# Send requestr = requests.post(url, params=payload, headers=headers)result = r.json()# Show responsereturn result["trans_result"][0]["dst"]except Exception as e:logging.error(f"百度翻译失败: {str(e)}")return ""
  • 小牛翻译
def xiaoniu_translate_text(text: str) -> str:url = 'http://api.niutrans.com/NiuTransServer/translation?'apikey = "your   apikey "data = {"from": "en", "to": "zh", "apikey": apikey, "src_text": text}data_en = urllib.parse.urlencode(data)req = url + "&" + data_entry:res = urllib.request.urlopen(req)res = res.read()res_dict = json.loads(res)return res_dict["tgt_text"]except Exception as e:logging.error(f"小牛翻译失败: {str(e)}")return ""

总的翻译接口

def translate_text(text: str) -> str:zh_abstract = tengxun_translate_text(text)if zh_abstract == "":zh_abstract = xiaoniu_translate_text(text)if zh_abstract == "":zh_abstract = baidu_translate_text(text)return zh_abstract

要在各自的翻译服务控制台设置一下,如果额度用完了就禁用,这样就会选还有额度的服务,避免自动扣钱。

保存成 md 文件

创建文件夹

首先根据当天日期创建相应的目录路径,然后根据该路径创建文件夹

# 生成每日目录路径
def get_daily_dir() -> str:local_date = datetime.now(timezone(timedelta(hours=ARXIV_CONFIG["timezone_offset"]))).date()return os.path.join(ARXIV_CONFIG["save_dir"], local_date.strftime("%Y%m%d"))

保存已检索的文章

创建一个 json 文件用来保存已检索的文章的 id

    exist_papers = []if os.path.exists(ARXIV_CONFIG["save_dir"]+"arxiv_papers.json"):with open(ARXIV_CONFIG["save_dir"]+"arxiv_papers.json", 'r') as f:papers_dict = json.load(f)exist_papers = papers_dict["papers"]else:with open(ARXIV_CONFIG["save_dir"]+"arxiv_papers.json", 'w') as f:json.dump({"papers": exist_papers}, f)

前面用 arxiv 的客户端检索了一个 papers 的列表,现在来对这个列表里面的文章进行处理。
如果文章已经在 json 文件里,直接跳过。如果没有,则整理它的信息,并放到已有文章的列表里

	for paper in papers:# 生成安全文件名# paper_id = paper.entry_id.split('/')[-1]paper_id = paper.get_short_id()if paper_id in exist_papers:logging.info(f"文献已存在 → {paper_id}")continueelse:exist_papers.append(paper_id)

这里先根据 arxiv 抓取的文章信息提取元数据,并整理成 md 的元数据。

		safe_title = re.sub(r'[^\w_()()\-]', ' ', paper.title).strip(' ')[:200]# filename = f"{paper_id}_{safe_title}.md"filename = f"{safe_title}.md"filepath = os.path.join(daily_dir, filename)# 获取DOI(需要根据实际情况调整)doi = getattr(paper, 'doi', []) or extract_doi_from_links(paper.links)# 构建元数据metadata = f"""---
title: "{paper.title}"
id: "{paper_id}"
authors: {[author.name for author in paper.authors]}
tags: {[tag.replace(".","/") for tag in paper.categories]}
category: {paper.primary_category}
doi: "{doi}"
url: "{paper.entry_id}"
published: "{paper.published.strftime('%Y-%m-%d')}"
update: "{paper.updated.strftime('%Y-%m-%d')}"
---"""

再对摘要进行翻译

# 处理摘要翻译en_abstract = paper.summary.replace('\n', ' ')zh_abstract = ""zh_abstract = translate_text(en_abstract)if zh_abstract == "":logging.error(f"翻译失败: {paper.title}")time.sleep(5)content = f"""{metadata}
## Abstract
{en_abstract}{"## 摘要" if zh_abstract else ""}
{zh_abstract if zh_abstract else ""}## PDF Links
- [arXiv PDF]({paper.pdf_url})
"""

最终将提取的信息写入文章名对应的 md 文件。并将已有文章的列表更新到 json 文件。

 # 写入文件with open(filepath, 'w', encoding='utf-8') as f:f.write(content.strip())logging.info(f"文献保存 → {filepath}")with open(ARXIV_CONFIG["save_dir"]+"arxiv_papers.json", 'w') as f:json.dump({"papers": exist_papers}, f)

最终脚本地址归档

arxiv-daily-subscriber

More Reading

Reference

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/907682.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

判断 Python 代码是不是 AI写的几个简单方法

作者:Laurel W来源:Adobe作为一名数据科学和数学老师,我其实不介意我的学生使用像 ChatGPT 这样的 LLM,只要它是用来辅助他们学习,而不是取代学习过程。加州理工学院的申请文书指南启发了我为编程和机器学习课制定 AI 使用政策: 哪些是加州理工申请文书中不道德的 AI 使用…

Golang学习Ⅱ

iota,函数多返回值,init函数,import导包 常量定义方式:const a int = 10; const{ a=10 b=20 }1 const{ 2 BeiJing = iota*10 //iota为0 3 ShangHai 4 NanJing 5 } //使用const定义枚举,BeiJing为0,ShangHai为10,NanJing为20View Code

SpringBoot整合RabbitMQ--Direct和Topic模式

一.Direct模式 这几个模式使用SpringBoot的整合和前面使用源生Java整合其实是差不多的,故而步骤就不再详细赘述了,直接先导入依赖:<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId&g…

CMS和G1的区别

悲观者从机会中看到困难。乐观者从困难中看到机会。 ——温斯顿丘吉尔区别一:使用的范围不一样:CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用。 G1收集器收集范围是老年代和新生代。不需要结合其他收集器使用区别二:STW的时间:CMS收集器以最小的停…

nfls 游记。

省流:三场模拟赛。rk1(2) rk3 rk4Day 1 3.26: 在前面的博客里面。 下午补了 noip2024 T1 。我怎么还是不会写????? Day 2 3.27: 没有模拟赛。组合数学专题。 写了一堆数学题。 中午逃离校园去吃了饭,终于有饭吃了!!!!111 晚上打了一场比赛,后三题全拼的暴力 /q…

PHP2 攻防世界

这题进去之后看到的:介绍该网站?gs,用f12,ctrl+u看都没看出啥。 看了别的博客才知道要看index.phps。第一次知道还有index.phps这个文件好像是扫描index.php的源代码啥的。操蛋 然后就看index.phps里的代码吧:这里看代码, `<?php if("admin"===$_GET[id]) {…

垃圾回收算法哪些阶段会STW

悲观者从机会中看到困难。乐观者从困难中看到机会。 ——温斯顿丘吉尔标记-复制算法应用在CMS新生代(ParNew是CMS默认的新生代垃圾回收器)和G1垃圾回收器中。标记复制算法可以分为三个阶段:标记阶段,即从GC Roots集合开始,标记活跃对象; 转移阶段,即把活跃对象复制到新的内存…

【unity】学习制作2D横板冒险游戏-4-

敌人的基本逻辑和动画 创建文件如图所示c#文件继承父类Enemy给boar挂载代码在敌人脚本中定义基本的变量并实例化面朝方向 在游戏中我们可以看到野猪的默认方向为左边 此时的transform.localscale的值为1我们希望当野猪面向右边时facedir的值为1,以此来判断敌人的面朝方向野猪的…

判断垃圾的方法

悲观者从机会中看到困难。乐观者从困难中看到机会。 ——温斯顿丘吉尔在Java中,判断对象是否为垃圾(即不再被使用,可以被垃圾回收器回收)主要依据两种主流的垃圾回收算法来实现:引用计数法和可达性分析算法。 引用计数法(Reference Counting)原理:为每个对象分配一个引用计数…

mRNA,IncRNA,miRNA

mRNA、lncRNA 和 miRNA 的核心区别 三者均为 RNA 分子,但在结构、功能和生物学作用上有显著差异: 1. mRNA(信使RNA)功能 :将 DNA 的遗传信息转录后传递至核糖体,指导蛋白质合成(基因表达的核心步骤)。结构 :单链线性结构,长度通常为数百至数千个核苷酸(nt)。 包含编码…

Training-WWW-Robots 攻防世界

进入网站看到根据提示可知:robots.txt 是关键点 进去看到:看到关键路径:进入看到flag

python第三章课后练习题

3.19 import time date_str = time.strftime("%Y年%m月%d日",time.localtime()) print("当前日期:",date_str)3.20 import time current_time = time.localtime() format1 = time.strftime("%Y年%m月%d日",current_time) print("格式1:&q…