CrossRef (参考文献链接协会组织)是官方DOI注册非盈利组织, 用于可以实现不同学术杂志交叉引用 wiki. 可以通过搜索引擎来搜索doi/文章标题等信息查询文献信息, 并且具有方便的API供用户使用.
- 搜索引擎支持直接doi搜索(结果唯一),甚至短doi搜索.
- 支持通过ISSN号搜索指定杂志内. 例如0022-2623搜出所有JMC文献.
- 搜索引擎支持
+word
强制具有该词, 或者!word
强制不出现. 但效果不甚佳..
如果只是使用网址形式控制搜索, 可以像以下使用(更多可参考:link)
http://search.crossref.org/?q=keywords
进行关键词搜索, 空格可以保留可以换成+
号&year=2015
限定年份&publication=
限定杂志
API接口
如果要进行数据处理, CrossRef提供API接口使用JSON数据传输其metadata. 十分方便用于文献信息获取和数据挖掘.
除了json结果外, 更改headers的Accept信息还可以获得其余格式的结果!
资源信息
提供以下资源:
- works : 就是一般的记录,包括journal, conference, book等
- funders : 所有funder信息
- members : 所有CrossRef的member(一般是出版商)信息
- prefixes : 出版商前缀, 如http://api.crossref.org/prefixes/10.1021
- types : work的类型,参见,例如常见类型”journal-article”
- journals : CrossRef的杂志信息
- licenses : 返回licenses授权信息
获取得到的结果分为单项Singletons和列表Lists, 前者结果只有一个,结果就在jsonresult['message']
内; 后者结果在jsonresult['message']['items']
内.
- 如果使用``http://api.crossref.org/journals`,获取的将是所有的journals的信息,即多项结果.
- 如果使用如
http://api.crossref.org/journals/0022-2623
或者http://api.crossref.org/works/10.1021/jm0203783
获取得到的, 是单个的信息结果, 即资源名/项目名
格式,资源名就是上面的信息罗. - 格式
/journals/{issn}/works
可以获取该杂志所有的paper信息.works
资源名可以加在别的资源名后面,返回所有相应的works. 多项结果.
主要参数
- query 受限 DisMax 搜索项
- filter={filter_name}:{value} 使用过滤器过滤结果, 过滤器可用词参考后面.每个filter之间用
,
分隔! - rows={#} 每页结果数
- offset={#} 从offset后面(即offset+1开始)开始列出结果
- sample={#} 返回随机N个结果, 会cancel掉rows和offset作用
- cursor={*/string} 使用分页器浏览结果, 要比offset的快,结合rows使用, 和sample/offset冲突. 下一页在上一次搜索结果的
json['message']['next-cursor']
当中. »»»> ccea31030575c5eaa3bd73843e685016b042d196 - sort={#} 使用相应field来排序
- order={#} 设置排序升序
asc
还是降序desc
- facet=t 在相应中激活 facet information, t/1/true都是打开, 就是对所有结果每个field的值进行计数(count).
参数第一项跟在资源名?
后, 参数形式为参数名=参数值
, 每个参数使用&
隔开, filter中使用,
隔开,如:
http://api.crossref.org/funders/100000015/works?query=global+state&filter=has-orcid:true,from-pub-date:2004-04-04&rows=1
即搜索为funders ID为100000015的文章, 搜索关键词尾global state, 使用过滤器, 每页一个结果.
细节:
- query 中使用
+word
连接需要的每个词, 使用+-word
来排除某词. - sort 使用排序, order升序
asc
还是降序desc
控制. sort使用支持例如- score或relevance: 根据相关性排序
- updated或deposited: 根据最近更新或入库信息排序
- indexed: 根据最近索引时间排序
- published: 根据发布的时间排序
- filter使用的是过滤, 最常用, 包括多种过滤器, 更多参考API介绍. 每个filter之间用
,
分隔! 较常用如:- from-pub-date (yyyy-mm-dd或yyyy-mm或yyyy) >=某年某月某日publish
- until-pub-date <= 某年某月某日publish
- issn 格式xxxx-xxxx.
- prefix 就是DOI拥有者前缀, 例如10.1002. 更常用
http://api.crossref.org/prefixes/10.1016/works?filter=
形式 - container-title 就是杂志名, 不建议.
- type 文献类型,例如 “journal-article”
- directory : DOAJ, 可以过滤出文献在DOAJ收录
使用python抓取信息实例
抓取后用json()方法处理结果即可得到一个字典.信息基本都在message里, 如有多项结果, 每项结果在data['message']['items']
里.
import requests
ls
r=requests.get("http://api.crossref.org/works/10.1021/jm0203783")
data=r.json()
data['message']['DOI']
# u'10.1021/jm0203783'
data['message']['title'][0]
# Comparative Evaluation of 11 Scoring Functions for Molecular Docking
data['message']['container-title']
# [u'J. Med. Chem.', u'Journal of Medicinal Chemistry']
data['message']['issued']['date-parts'][0][0]
# 2003, [[2003,6]]
data['message']['volume']
# 46
data['message']['issue']
# 12
data['message']['page']
# u'2287-2303'
data['message']['ISSN']
# [u'0022-2623', u'1520-4804']
data['message']['URL']
# u'http://dx.doi.org/10.1021/jm0203783'
data['message']['author']
# [{u'affiliation': [], u'family': u'Wang', u'given': u'Renxiao'},
# {u'affiliation': [], u'family': u'Lu', u'given': u'Yipin'},
# {u'affiliation': [], u'family': u'Wang', u'given': u'Shaomeng'}]
r.status_code
# 200
# 无效DOI返回响应码404
r=requests.get("http://api.crossref.org/works?query=Comparative%20Evaluation%20of%2011%20Scoring%20Functions%20for%20Molecular%20Docking&rows=5")
data=r.json()
data['message']
#->facet: 空白字典, 不明
#->items: 一个结果列表,每一项是个字典, 每个字典就是上面的data['message']获得的内容. 其中score项是相关性打分
#->total-results: 搜出的结果总数
#->items-per-page: 5, 由关键词rows=5限定
#->query: 搜索内容, 有'search-terms' 就是搜索query部分; 'start-index' 不明.
一个封装的简单CrossRefAPI类
class CrossRefAPI(object):
'''Simple wrapper for CrossRef API'''
def filterstr(self,filterdict):
'''Generate string for filter'''
filters=[]
for k,v in filterdict.items():
filters.append(k+':'+str(v))
return ','.join(filters)
def getqueryurl(self,query,rows=10,offset=0,papertype='journal-article',sample=0,filterdict={},cursor=''):
'''Get query url, support rows/offset/cursor/sample
Default get journal-article. Support more filters in dict format'''
if (not query):
return ""
query=str(query)
# Basic options
if (sample>0):
optstrbase='sample='+str(sample)
elif (cursor):
optstrbase="rows="+str(rows)+'&cursor='+cursor
elif offset<=0:
optstrbase="rows="+str(rows)
else:
optstrbase="rows="+str(rows)+"&offset="+str(offset)
optstr=optstrbase
# Deal with filter
if (papertype):
optstr+="&filter=type:"+papertype
if (filterdict):
optstr+=','+self.filterstr(filterdict)
elif (filterdict):
optstr+='&filter='+self.filterstr(filterdict)
if (len(query) == 9 and query[4] == '-'):
return "http://api.crossref.org/journals/"+query+"/works?"+optstr
elif ('10.' in query):
return "http://api.crossref.org/prefixes/"+query+"/works?"+optstr
elif ( query.isdigit()):
return "http://api.crossref.org/members/"+query+"/works?"+optstr
else:
return "http://api.crossref.org/works?query="+query+"&"+optstr
def getquerytotol(self,query,papertype=None,filterdict={}):
'''Get total result number for a query'''
if (not query):
return 0
j1= self.getqueryurl(query,rows=1,papertype=papertype,filterdict=filterdict)
if (j1):
r=urllib2.urlopen(j1,timeout=timeout_setting)
j=json.loads(r.read())
r.close()
return int(j['message'].get('total-results',0))
else:
return 0
def getalldoi2file(self,query,fname,papertype=None,filterdict={},getissn=False):
'''Get All doi for a query to a file.
getissn can also analyse all issn for this query'''
if (not query or not fname):
return
issns=set()
total=self.getquerytotol(query,papertype=papertype,filterdict=filterdict)
f=open(fname,'w')
print "Total articles:",total
f.write("# Total articles: "+str(total)+'\n')
step=1000
maxround=total/step+1
nextcursor="*"
for i in range(maxround):
needurl=self.getqueryurl(query,rows=step,cursor=nextcursor,papertype=papertype,filterdict=filterdict)
r=urllib2.urlopen(needurl,timeout=timeout_setting_download)
js=json.loads(r.read())
newcursor=js['message'].get('next-cursor',nextcursor)
if nextcursor == newcursor:
break
nextcursor=newcursor
for j in js['message']['items']:
doi=j.get("DOI","")
if (getissn):
issn=j.get('ISSN')
issns.update(issn)
f.write(doi+'\n')
if (getissn):
for issn in issns:
f.write('# '+issn+'\n')
f.close()
def is_doaj(self,query):
'''Test a query is in DOAJ, often use doi'''
return self.getquerytotol(query,papertype=None,filterdict={'directory':'DOAJ'})>0
使用sample随机采样:
使用上述API的封装类采样随机DOI
class RandomGet(object):
'''Wrapper for random get for query list'''
def __init__(self,query,randnum=100):
if (not isinstance(query,list)):
raise ValueError("Should give a list to initialize!")
sys.exit(1)
self.query=query
self.crapi=CrossRefAPI()
self.qdois={}
for q in self.query:
self.qdois[q]=self.sampledois(q,randnum=randnum)
def sampledois(self,query,randnum=100):
if not query:
return []
needurl=self.crapi.getqueryurl(query, sample=randnum)
if (needurl):
r=urllib2.urlopen(needurl,timeout=timeout_setting)
js=json.loads(r.read())
r.close()
return [ item.get("DOI","") for item in js['message'].get('items',[{}]) ]
return []
可以支持ISSN, prefix, member号等进行随机采集.
使用cursor进行遍历结果
参考API类的getalldoi2file
方法, 使用cursor参数, 第一次使用*
采集, 需要指定rows, 随后从上一次结果中采next-cursor
的字符串值, 将该值赋予给cursor作为下一次的搜索. 需要判断是否到尾(这里用cursor是否再次相等判断, 也可以用该次采集数量是否小于rows设置来判断(到头了会没有结果))