first commit
This commit is contained in:
@@ -0,0 +1,373 @@
|
||||
# API 使用指南
|
||||
|
||||
本文档详细说明如何使用三个主要 API 进行文献验证。
|
||||
|
||||
## Semantic Scholar API
|
||||
|
||||
### 概述
|
||||
|
||||
Semantic Scholar 是一个免费的学术搜索引擎,提供强大的 API 用于论文检索和元数据获取。
|
||||
|
||||
**优势:**
|
||||
- 免费使用,无需 API key
|
||||
- 覆盖广泛的学科领域
|
||||
- 提供丰富的元数据
|
||||
- 支持模糊搜索
|
||||
|
||||
**限制:**
|
||||
- 请求频率限制:100 requests/5min
|
||||
- 部分论文可能缺失
|
||||
|
||||
### API 端点
|
||||
|
||||
**1. 通过 Paper ID 获取论文**
|
||||
```
|
||||
GET https://api.semanticscholar.org/graph/v1/paper/{paper_id}
|
||||
```
|
||||
|
||||
**2. 搜索论文**
|
||||
```
|
||||
GET https://api.semanticscholar.org/graph/v1/paper/search?query={query}
|
||||
```
|
||||
|
||||
### Python 示例
|
||||
|
||||
**安装:**
|
||||
```bash
|
||||
pip install semanticscholar
|
||||
```
|
||||
|
||||
**基本用法:**
|
||||
```python
|
||||
from semanticscholar import SemanticScholar
|
||||
|
||||
sch = SemanticScholar()
|
||||
|
||||
# 通过标题搜索
|
||||
results = sch.search_paper("Attention is All You Need", limit=5)
|
||||
for paper in results:
|
||||
print(f"Title: {paper.title}")
|
||||
print(f"Authors: {[a.name for a in paper.authors]}")
|
||||
print(f"Year: {paper.year}")
|
||||
print(f"DOI: {paper.externalIds.get('DOI', 'N/A')}")
|
||||
print("---")
|
||||
```
|
||||
|
||||
**通过 DOI 获取:**
|
||||
```python
|
||||
# DOI 格式: DOI:10.48550/arXiv.1706.03762
|
||||
paper = sch.get_paper("DOI:10.48550/arXiv.1706.03762")
|
||||
print(f"Title: {paper.title}")
|
||||
print(f"Citations: {paper.citationCount}")
|
||||
```
|
||||
|
||||
### 字段说明
|
||||
|
||||
**返回的主要字段:**
|
||||
- `paperId` - Semantic Scholar 内部 ID
|
||||
- `title` - 论文标题
|
||||
- `authors` - 作者列表
|
||||
- `year` - 发表年份
|
||||
- `venue` - 发表场所(会议/期刊)
|
||||
- `externalIds` - 外部标识符(DOI, arXiv, PubMed 等)
|
||||
- `citationCount` - 引用次数
|
||||
- `abstract` - 摘要
|
||||
|
||||
### 错误处理
|
||||
|
||||
```python
|
||||
try:
|
||||
paper = sch.get_paper("invalid_id")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
# 处理错误:标记需要人工验证
|
||||
```
|
||||
|
||||
## arXiv API
|
||||
|
||||
### 概述
|
||||
|
||||
arXiv 是预印本论文库,提供免费的 API 用于访问论文元数据。
|
||||
|
||||
**优势:**
|
||||
- 完全免费,无需认证
|
||||
- 覆盖物理、数学、计算机科学等领域
|
||||
- 提供完整的论文 PDF
|
||||
- 更新及时
|
||||
|
||||
**限制:**
|
||||
- 仅限预印本论文
|
||||
- 不包含已发表的期刊版本信息
|
||||
|
||||
### API 端点
|
||||
|
||||
**查询接口:**
|
||||
```
|
||||
GET http://export.arxiv.org/api/query?search_query={query}&start={start}&max_results={max}
|
||||
```
|
||||
|
||||
### Python 示例
|
||||
|
||||
**安装:**
|
||||
```bash
|
||||
pip install arxiv
|
||||
```
|
||||
|
||||
**基本用法:**
|
||||
```python
|
||||
import arxiv
|
||||
|
||||
# 通过 arXiv ID 获取
|
||||
paper = next(arxiv.Search(id_list=["1706.03762"]).results())
|
||||
print(f"Title: {paper.title}")
|
||||
print(f"Authors: {[a.name for a in paper.authors]}")
|
||||
print(f"Published: {paper.published}")
|
||||
print(f"PDF URL: {paper.pdf_url}")
|
||||
|
||||
# 通过标题搜索
|
||||
search = arxiv.Search(
|
||||
query="Attention is All You Need",
|
||||
max_results=5,
|
||||
sort_by=arxiv.SortCriterion.Relevance
|
||||
)
|
||||
|
||||
for result in search.results():
|
||||
print(f"Title: {result.title}")
|
||||
print(f"arXiv ID: {result.entry_id.split('/')[-1]}")
|
||||
print("---")
|
||||
```
|
||||
|
||||
### arXiv ID 格式
|
||||
|
||||
**识别 arXiv ID:**
|
||||
- 新格式: `YYMM.NNNNN` (如 2301.12345)
|
||||
- 旧格式: `arch-ive/YYMMNNN` (如 cs/0703001)
|
||||
|
||||
**从 URL 提取:**
|
||||
```python
|
||||
import re
|
||||
|
||||
def extract_arxiv_id(text):
|
||||
# 匹配新格式
|
||||
match = re.search(r'\d{4}\.\d{4,5}', text)
|
||||
if match:
|
||||
return match.group()
|
||||
# 匹配旧格式
|
||||
match = re.search(r'[a-z-]+/\d{7}', text)
|
||||
if match:
|
||||
return match.group()
|
||||
return None
|
||||
```
|
||||
|
||||
## CrossRef API
|
||||
|
||||
### 概述
|
||||
|
||||
CrossRef 是 DOI 注册机构,提供权威的学术文献元数据。
|
||||
|
||||
**优势:**
|
||||
- DOI 是最可靠的唯一标识符
|
||||
- 覆盖几乎所有正式发表的论文
|
||||
- 数据质量高,权威性强
|
||||
- 支持 BibTeX 格式直接获取
|
||||
|
||||
**限制:**
|
||||
- 仅限有 DOI 的论文
|
||||
- 预印本通常没有 DOI
|
||||
|
||||
### API 端点
|
||||
|
||||
**通过 DOI 获取元数据:**
|
||||
```
|
||||
GET https://api.crossref.org/works/{doi}
|
||||
```
|
||||
|
||||
**通过 DOI 获取 BibTeX:**
|
||||
```
|
||||
GET https://doi.org/{doi}
|
||||
Headers: Accept: application/x-bibtex
|
||||
```
|
||||
|
||||
### Python 示例
|
||||
|
||||
**通过 DOI 获取元数据:**
|
||||
```python
|
||||
import requests
|
||||
|
||||
def get_crossref_metadata(doi):
|
||||
url = f"https://api.crossref.org/works/{doi}"
|
||||
response = requests.get(url)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
return data['message']
|
||||
return None
|
||||
|
||||
# 示例
|
||||
doi = "10.48550/arXiv.1706.03762"
|
||||
metadata = get_crossref_metadata(doi)
|
||||
if metadata:
|
||||
print(f"Title: {metadata['title'][0]}")
|
||||
print(f"Authors: {[f\"{a['given']} {a['family']}\" for a in metadata['author']]}")
|
||||
print(f"Published: {metadata['published']['date-parts'][0]}")
|
||||
```
|
||||
|
||||
**通过 DOI 获取 BibTeX:**
|
||||
```python
|
||||
def doi_to_bibtex(doi):
|
||||
url = f"https://doi.org/{doi}"
|
||||
headers = {"Accept": "application/x-bibtex"}
|
||||
response = requests.get(url, headers=headers)
|
||||
if response.status_code == 200:
|
||||
return response.text
|
||||
return None
|
||||
|
||||
# 示例
|
||||
bibtex = doi_to_bibtex("10.48550/arXiv.1706.03762")
|
||||
print(bibtex)
|
||||
```
|
||||
|
||||
### DOI 格式
|
||||
|
||||
**标准格式:**
|
||||
- `10.XXXX/suffix` (如 10.1038/nature12345)
|
||||
- 前缀 `10.` 是固定的
|
||||
- 中间是注册机构代码
|
||||
- 后缀是出版商定义的
|
||||
|
||||
**从文本中提取 DOI:**
|
||||
```python
|
||||
import re
|
||||
|
||||
def extract_doi(text):
|
||||
# 匹配 DOI 格式
|
||||
match = re.search(r'10\.\d{4,}/[^\s]+', text)
|
||||
if match:
|
||||
return match.group()
|
||||
return None
|
||||
```
|
||||
|
||||
## API 选择策略
|
||||
|
||||
根据引用信息选择最合适的 API:
|
||||
|
||||
### 决策流程
|
||||
|
||||
```
|
||||
有 DOI?
|
||||
├─ 是 → CrossRef API (最可靠)
|
||||
└─ 否 → 有 arXiv ID?
|
||||
├─ 是 → arXiv API
|
||||
└─ 否 → Semantic Scholar API (通用搜索)
|
||||
```
|
||||
|
||||
### 实现示例
|
||||
|
||||
```python
|
||||
def verify_citation(citation_info):
|
||||
"""
|
||||
根据引用信息选择合适的 API 进行验证
|
||||
|
||||
Args:
|
||||
citation_info: dict with keys: doi, arxiv_id, title, authors
|
||||
|
||||
Returns:
|
||||
验证结果字典
|
||||
"""
|
||||
# 策略 1: DOI 优先
|
||||
if citation_info.get('doi'):
|
||||
return verify_with_crossref(citation_info['doi'])
|
||||
|
||||
# 策略 2: arXiv ID
|
||||
if citation_info.get('arxiv_id'):
|
||||
return verify_with_arxiv(citation_info['arxiv_id'])
|
||||
|
||||
# 策略 3: 通用搜索
|
||||
if citation_info.get('title'):
|
||||
return verify_with_semantic_scholar(
|
||||
citation_info['title'],
|
||||
citation_info.get('authors')
|
||||
)
|
||||
|
||||
return {'status': 'insufficient_info'}
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 错误处理
|
||||
|
||||
```python
|
||||
import time
|
||||
from requests.exceptions import RequestException
|
||||
|
||||
def api_call_with_retry(func, max_retries=3):
|
||||
"""带重试的 API 调用"""
|
||||
for i in range(max_retries):
|
||||
try:
|
||||
return func()
|
||||
except RequestException as e:
|
||||
if i == max_retries - 1:
|
||||
raise
|
||||
time.sleep(2 ** i) # 指数退避
|
||||
```
|
||||
|
||||
### 2. 速率限制
|
||||
|
||||
```python
|
||||
import time
|
||||
|
||||
class RateLimiter:
|
||||
def __init__(self, calls_per_minute):
|
||||
self.calls_per_minute = calls_per_minute
|
||||
self.last_call = 0
|
||||
|
||||
def wait_if_needed(self):
|
||||
elapsed = time.time() - self.last_call
|
||||
min_interval = 60.0 / self.calls_per_minute
|
||||
if elapsed < min_interval:
|
||||
time.sleep(min_interval - elapsed)
|
||||
self.last_call = time.time()
|
||||
|
||||
# 使用示例
|
||||
limiter = RateLimiter(calls_per_minute=20)
|
||||
limiter.wait_if_needed()
|
||||
result = api_call()
|
||||
```
|
||||
|
||||
### 3. 缓存结果
|
||||
|
||||
```python
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
class APICache:
|
||||
def __init__(self, cache_dir=".cache"):
|
||||
self.cache_dir = Path(cache_dir)
|
||||
self.cache_dir.mkdir(exist_ok=True)
|
||||
|
||||
def get(self, key):
|
||||
cache_file = self.cache_dir / f"{key}.json"
|
||||
if cache_file.exists():
|
||||
return json.loads(cache_file.read_text())
|
||||
return None
|
||||
|
||||
def set(self, key, value):
|
||||
cache_file = self.cache_dir / f"{key}.json"
|
||||
cache_file.write_text(json.dumps(value))
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
### API 对比
|
||||
|
||||
| API | 优势 | 限制 | 推荐场景 |
|
||||
|-----|------|------|----------|
|
||||
| **CrossRef** | 最权威,支持 BibTeX | 仅限有 DOI 的论文 | 有 DOI 时首选 |
|
||||
| **arXiv** | 免费,更新快 | 仅限预印本 | arXiv 论文 |
|
||||
| **Semantic Scholar** | 覆盖广,模糊搜索 | 部分论文缺失 | 通用搜索 |
|
||||
|
||||
### 验证可靠性排序
|
||||
|
||||
1. **CrossRef (DOI)** - 最可靠
|
||||
2. **arXiv (arXiv ID)** - 可靠
|
||||
3. **Semantic Scholar (标题搜索)** - 较可靠,需要人工确认
|
||||
|
||||
Reference in New Issue
Block a user