Hom's Blog


CrossRef获取文献信息

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设置来判断(到头了会没有结果))



◆ 本文地址: http://platinhom.github.io/2016/01/07/crossref/, 转载请注明 ◆

前一篇: Python:difflib字符串差别
后一篇: sftp命令


Contact: Hom / 已阅读()
Source 类别: IT  标签: Software  Python