最近看论文,看到了自己需要的数据,就想着下载下来,结果发现这个东西并不好下载,也可能是自己的知识存储不够,捣鼓了一天,终于下载下来了。这里记录一下,方便以后查阅。
Harvard Dataverse 数据批量下载
Harvard Dataverse
Harvard Dataverse,一个包含了海量论文实验数据的网站,在这里你可以找到相当多的论文实验数据。我们要下载的数据就在这里。
首次使用,需要点击右上角Sign Up进行注册,之后点击Log In 进行登陆。想要下载数据一定要注册,注册后的信息,在之后也会用到。
我们可以随便找个数据看一下都有什么信息:
点开上图数据地址,就可以看到下图的信息:
接下来我们主要解决的是当数据超过20G,我们应该如何操作。首先我会给出下载代码,然后给出一些补充知识方便理解代码,最后记录一下下载过程。
批量下载代码
#!/bin/bash
API_TOKEN="YOUR-DATAVERSE-API-TOKEN"
PERSISTENT_ID=doi:10.7910/DVN/xxxxxx
output="/home/pytorch/LiangXiaohan/MI_Dataverse/MI_same_limb/MI"
curl -H "X-Dataverse-key: $API_TOKEN" https://dataverse.harvard.edu/api/datasets/:persistentId/versions/3/files?persistentId=$PERSISTENT_ID | tee >(jq '.data[].dataFile.persistentId' >persistentid) >(jq '.data[].dataFile.filename' >filenames)
paste persistentid filenames > arg
cat arg | xargs -L1 bash -c ' wget -O '$output'$1 -P '$output' https://dataverse.harvard.edu/api/access/datafile/:persistentId?persistentId=$0'
rm filenames persistentid arg
补充知识
URL
理解URL(Uniform Resource Locator)
URL 是Uniform Resource Locator的首字母缩写词,是 Internet 上资源的引用(地址)。
当我们在点击一个链接或在浏览器中输入网址时,就已经接触到URL了,只不过脑海没有这种术语罢了。 中文名是统一资源定位器。把它想象成一个街道地址,URL 的每个部分都是地址的不同部分,每个都会给你不同的信息。
协议标识符(schema)
、域名/主机名(domain name)
、文件路径(File path)
、 参数(parameter)
、锚点(Anchor)
以上这些元素组合在一起时,就构成了一个 URL,尽管并非所有 URL 都包含所有五个部分。
协议标识符(schema)
指示用于获取资源的协议名称。
Every URL begins with the scheme. This tells your browser what type of address it is so the browser connects to it correctly. There are many types of schemes, but for typical web browsing you will mostly see http and https.
schema通常不会在浏览器地址栏中显示,在输入网址时也不需要输入;相反,你可以直接输入域名。但这并不意味着它不是 URL 的一部分(可有可无);它只是没有被显示出来。
http与https的区别
之前就一直有这样的疑问,这两个有什么区别,正好今天整理一下。
基本概念
HTTP(HyperText Transfer Protocol:超文本传输协议) 是一种用于分布式、协作式和超媒体信息系统的应用层协议。 简单来说就是一种发布和接收 HTML 页面的方法,被用于在 Web 浏览器和网站服务器之间传递信息。
HTTP 默认工作在 TCP 协议 80 端口,用户访问网站 http:// 打头的都是标准 HTTP 服务。
HTTP 协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。
HTTPS(Hypertext Transfer Protocol Secure:超文本传输安全协议) 是一种透过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信,但利用 SSL/TLS 来加密数据包。HTTPS 开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。
HTTPS 默认工作在 TCP 协议443端口
HTTP 与 HTTPS 区别
- HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。
- 使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。
- HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。
- http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
- HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,要比较 HTTPS 比 HTTP 要更耗费服务器资源。
域名/主机名(domain name)
资源所在机器的名称。
这是整个URL最显眼的部位。通常,同一站点上的不同页面将继续使用相同的域名。例如,百度站点上的所有页面共享 baidu.com 域名。
以句点分隔的域名的每一段称为域。最右边的域称为一级域名(top-level domain),往左过来依次为二级域名(second-level domain),三级域名(third-level domain)。
我们可以从域中了解有关该站点的信息。一级域名更多一般可能会为您提供有关它是哪种站点类型的信息。比如以xx.gov或xx.org为域名后缀的URL,说明了它们的指向是政府机构或公益非营利性的站点。
在大多数 URL 中,可以省略 www 域。baidu.com 和 www.google.com 指向同一个页面。但是不能省略其他子域。例如,baike.baidu.com 下的所有页面都需要 URL 中的baike子域。
文件路径(File path)
机器上的文件路径名。
The file path—often just called the path—tells your browser to load a specific page. If you don’t specify a path and only enter a domain name, your browser is still loading a specific page; it’s just loading a default page, which usually will help you navigate to other pages.
参数(parameter)
某些 URL 在路径后包含一串字符以问号开头,叫参数字符串(parameter string)。
You have probably noticed this part of a URL appear in your address bar after performing a search on Google or YouTube. The parameter string can be clear or confusing to a human user, but it is critical information for the server.
锚点(Anchor)
锚点也出现在URL路径之后,它指示浏览器滚动到或加载至页面的特定部分。通常锚点以#号开头,用于引导到很长的页面特定部分,类似书签。不同的锚点不会加载不同的页面,它们只是告诉浏览器要显示的是页面的哪个部分而已。
常见的百度百科目录就是利用锚点实现跳转的。
curl
- curl是一个利用URL规则在命令行下工作的文件传输工具,
- 是一款很强大的http命令行工具。
- 它支持文件的上传和下载,是综合传输工具,习惯称url为下载工具
这一部分主要是针对这句代码:
curl -H "X-Dataverse-key: $API_TOKEN" https://dataverse.harvard.edu/api/datasets/:persistentId/versions/3/files?persistentId=$PERSISTENT_ID | tee >(jq '.data[].dataFile.persistentId' >persistentid) >(jq '.data[].dataFile.filename' >filenames)
其中有个-H
和 tee
不知道是干啥的,下面解释一下。
-H
-H “name: value”
–header “name: value” (HTTP)添加一个http header(http请求头);
tee
tee : 从标准输入读取并写入标准输出和文件
下面这条命令的输出就是,下面这个网址中的信息。
curl -H "X-Dataverse-key: $API_TOKEN" https://dataverse.harvard.edu/api/datasets/:persistentId/versions/3/files?persistentId=$PERSISTENT_ID | tee
随便举个栗子看看:
https://dataverse.harvard.edu/api/datasets/:persistentId/versions/2/files?persistentId=doi:10.7910/DVN/CEFZLV
versions
在上面的网址中有个versions
字样,这个有关这个的解释在Data Access API的Download By Dataset By Version中有解释。
这里就是按照数据的版本进行下载,我试过Data Access API中的Basic Download By Dataset方式,但是打不开网址。
这里的versions
后面的数字是怎么来的呢?我们可以从数据详情页面看到:
API_TOKEN
curl -H "X-Dataverse-key: $API_TOKEN" https://dataverse.harvard.edu/api/datasets/:persistentId/versions/3/files?persistentId=$PERSISTENT_ID | tee >(jq '.data[].dataFile.persistentId' >persistentid) >(jq '.data[].dataFile.filename' >filenames)
上面的代码中还有一个值API_TOKEN
,有关它的解释在下面的链接中有:
https://guides.dataverse.org/en/latest/user/account.html#api-token
In many cases, such as when depositing data, an API Token is required to interact with Dataverse Software APIs. The word “token” indicates a series of letters and numbers such as c6527048-5bdc-48b0-a1d5-ed1b62c8113b. Anyone who has your API Token can add and delete data as you so you should treat it with the same care as a password.
也就是说API_TOKEN就类似于你的一个令牌或者密码。
按照下图进行操作即可得到自己的token值。
jq
curl -H "X-Dataverse-key: $API_TOKEN" https://dataverse.harvard.edu/api/datasets/:persistentId/versions/3/files?persistentId=$PERSISTENT_ID | tee >(jq '.data[].dataFile.persistentId' >persistentid) >(jq '.data[].dataFile.filename' >filenames)
再看一下完整的这段代码,还有一个关键词jq
,我们再来看一下这是个什么东西:
jq可以对json数据进行分片、过滤、映射和转换
我们可接接着从下面网站的内容来分析:
我们截取一部分,并将其进行分段:
{"status":"OK","data":[
{"label":"cfs_2011041800.pkl","restricted":false,"version":1,"datasetVersionId":155639,"dataFile":
{"id":3348953,"persistentId":"doi:10.7910/DVN/CEFZLV/J8QKGW","pidURL":"https://doi.org/10.7910/DVN/CEFZLV/J8QKGW","filename":"cfs_2011041800.pkl","contentType":"application/octet-stream","filesize":64961961,"storageIdentifier":"s3://dvn-cloud:1689ba85f50-eda996245980","rootDataFileId":-1,"md5":"2980a7ee05580ddb1e3727541e8ee484","checksum":{"type":"MD5","value":"2980a7ee05580ddb1e3727541e8ee484"},"creationDate":"2019-01-29"}},
{"label":"cfs_2011050200.pkl","restricted":false,"version":1,"datasetVersionId":155639,"dataFile":
{"id":3348921,"persistentId":"doi:10.7910/DVN/CEFZLV/HUV1PO","pidURL":"https://doi.org/10.7910/DVN/CEFZLV/HUV1PO","filename":"cfs_2011050200.pkl","contentType":"application/octet-stream","filesize":64961961,"storageIdentifier":"s3://dvn-cloud:1689ba8701d-bda3d154192d","rootDataFileId":-1,"md5":"ec6fdac0f018cc3400cab123ac703d6c","checksum":{"type":"MD5","value":"ec6fdac0f018cc3400cab123ac703d6c"},"creationDate":"2019-01-29"}},
{"label":"cfs_2011051600.pkl","restricted":false,"version":1,"datasetVersionId":155639,"dataFile":
{"id":3348879,"persistentId":"doi:10.7910/DVN/CEFZLV/EAHO02","pidURL":"https://doi.org/10.7910/DVN/CEFZLV/EAHO02","filename":"cfs_2011051600.pkl","contentType":"application/octet-stream","filesize":64961961,"storageIdentifier":"s3://dvn-cloud:1689ba88182-7fc4f94f5b72","rootDataFileId":-1,"md5":"285f2859512c27b046594fae50e9ee47","checksum":{"type":"MD5","value":"285f2859512c27b046594fae50e9ee47"},"creationDate":"2019-01-29"}},
从上面的数据我们就可以知道下面这段代码实现的功能是什么了:
(jq '.data[].dataFile.persistentId' >persistentid)
这段代码截取的是每条数据的persistentId
字段,这个字段很重要,主要是用来现在数据的。
persistentId
cat arg | xargs -L1 bash -c ' wget -O '$output'$1 -P '$output' https://dataverse.harvard.edu/api/access/datafile/:persistentId?persistentId=$0'
这段代码中,后面有个网址,当我们吧网址后面的$0
用persistentId
替换后,就会发现神奇的东西:
https://dataverse.harvard.edu/api/access/datafile/:persistentId?persistentId=doi:10.7910/DVN/CEFZLV/J8QKGW
在浏览器中输入上述网址,就会发现,浏览器下载了一个文件,而这个文件就是下面这段代码获得的文件名对应的文件。
(jq '.data[].dataFile.filename' >filenames)
到这里,们已经可以通过网址来下载数据了,只要能拿到数据,我们就完成了一大半的的工作了!
paste
paste persistentid filenames > arg
这段代码主要是一个paste
命令:
paste命令用于合并文件的列。
paste指令会把每个文件以列对列的方式,一列列地加以合并。
这个就很好理解了,通过下面这张图就可以明白这段代码是干了什么了:
cat
cat arg | xargs -L1 bash -c ' wget -O '$output'$1 -P '$output' https://dataverse.harvard.edu/api/access/datafile/:persistentId?persistentId=$0'
cat("concatenate"的缩写)命令是 Linux/Unix 操作系统中最常用的命令之一。cat命令允许我们创建单个或多个文件,查看文件的内容,连接文件并在终端或文件中重定向输出。cat 命令将文件内容显示到屏幕上。Cat 命令将标准输入连接到标准输出。
xargs
命令格式:
somecommand |xargs -item command
-L num 从标准输入一次读取 num 行送给 command 命令。
bash -c
-c 的意思是 command,所以 bash -c 后面应该跟一个 command。
用法:
bash -c “cmd string”
通常使用shell去运行脚本,两种方法
-
bash xxx.sh
-
bash -c “cmd string”
wget -O
-O:下载并以指定的文件名保存;
这里对应代码中的下面这一部分
' wget -O '$output
其中需要注意的是,$output这个应该是个文件名,而不是路径,也就是下面这个意思:
如果output我这样赋值,运行代码就会报错:
output="/home/pytorch/LiangXiaohan/MI_Dataverse/MI_same_limb/"
如果我改成下面这样的就不报错了,但是这样下载的文件,会在原文件名的基础上加上MI。
output="/home/pytorch/LiangXiaohan/MI_Dataverse/MI_same_limb/MI"
$1 $0
cat arg | xargs -L1 bash -c ' wget -O '$output'$1 -P '$output' https://dataverse.harvard.edu/api/access/datafile/:persistentId?persistentId=$0'
上面这段代码中还有$1
和 $0
两个参数,这个也不是倒是个啥啊!
Linux—— 1 、 1、 1、#、$@、$0、$1、$2
$1在shell中称为“位置参数”,表示传入的第1个参数(第1个入参)。
注:
这句代码里的参数我也没太搞懂,初步猜测:$1是arg文件中的第二列,代表着文件名;$0是arg文件中的第一列,代表着persistentId。
下载数据
首先创建文件,并把上述下载代码拷贝到文件中:
vim test.sh
然后给文件权限:
sudo chmod +x test.sh
运行文件:
bash ./test.sh
出现了如下问题
下载地址不对,看一下代码生成的三个文件:
发现arg内容不对,然后运行下面的代码,重新生成arg文件:
paste persistentid filenames > arg
生成如下的arg即为正确的,第一列是persistentId,第二列是文件名。
然后在test.sh中注释掉刚才执行的代码,并重新运行该文件:
我们可以看到数据已经开始下载了:
参考资料
理解URL(Uniform Resource Locator)
https://guides.dataverse.org/en/latest/user/account.html#api-token