前一篇文章《CURL帮助文档》中简单介绍了如何用curl命令下载RedPajama数据集。在下载的过程中,前期使用huggingface里面提供的脚本下载比较顺利。但是到中后期,尤其是下载common crawl部分的数据集,就开始出现很多问题。目前下载过程中遇到的各种问题如下:
curl (18) transfer closed
主要报错代码如下:
curl (18) transfer closed with xxxx bytes remaining to read
curl (92) HTTP/2 stream not closed cleanly
主要报错代码如下:
curl (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
curl (56) HTTP code 407
主要报错代码如下:
curl (56) Received HTTP code 407 from proxy after CONNECT
处理方案
导致以上错误代码的原因不同,但是结果就是有些数据文件已经下载成功了,有些数据文件没有下载成功,有些下载到一半。首先看一下我下载文件的最初脚本:
#!/bin/bash
while read line; do
dload_loc=${line#https://data.together.xyz/redpajama-data-1T/v1.0.0/}
mkdir -p $(dirname $dload_loc)
echo $line
curl -k "$line" -o "$dload_loc"
done < url.txt
从url列表文件url.txt中读取url并且下载保存。其中url.txt是一行一个URL的纯文本文件(注意必须是Unix格式的换行),例如:
https://data.together.xyz/redpajama-data-1T/v1.0.0/common_crawl/2022-05/en_middle_0079.json.gz.dedup.classifier.jsonl.zst
https://data.together.xyz/redpajama-data-1T/v1.0.0/common_crawl/2022-05/en_middle_0080.json.gz.dedup.classifier.jsonl.zst
https://data.together.xyz/redpajama-data-1T/v1.0.0/common_crawl/2022-05/en_middle_0081.json.gz.dedup.classifier.jsonl.zst
https://data.together.xyz/redpajama-data-1T/v1.0.0/common_crawl/2022-05/en_middle_0082.json.gz.dedup.classifier.jsonl.zst
https://data.together.xyz/redpajama-data-1T/v1.0.0/common_crawl/2022-05/en_middle_0075.json.gz.dedup.classifier.jsonl.zst
有800多个URL,有些已经下载好了,有些报错下载了一半,有些完全下载失败(本地没有文件)。因此首先使用以下命令从日志中把报错的URL都归集在一起:
grep -B4 ^curl log.txt | grep http > error.txt
grep -B3 "curl: (56)" log.txt | grep http >> error.txt
随后,修改以下原来脚本中的curl语句,加上“-C -”参数即可。这样如果本地已经有文件存在,则会断点续传,否则直接下载。
然而,世界中是那么无情的。“-C -”参数并不是每次都能断点续传。至少在下载RedPajama的common crawl数据集时,时好时坏。通常会报错:
curl: (33) HTTP server doesn't seem to support byte ranges. Cannot resume.
处理方案更新
另外,并不是每次都有日志文件的,比如说第一次运行时没有把日志保存在文件中。这时就无法通过grep提取下载失败的URL了。在这种情况下就需要对比本地文件大小和网络文件大小,决定那些文件需要重新下载。更新后的脚本如下(此方案仍未解决无法断点续传的问题):
#!/bin/bash
while read line; do
dload_loc=${line#https://data.together.xyz/redpajama-data-1T/v1.0.0/}
mkdir -p $(dirname $dload_loc)
echo $line
# 如果文件不存在ls会报错,2>/dev/null,将报错信息不要打印在屏幕上
# -n 测试变量不为空
fileSize=$(ls -l $dload_loc 2>/dev/null | awk '{print $5}')
if [ -n "$fileSize" ]; then
# 存在本地文件,比较下载进度
remoteSize=$(curl -k --head -s "$line" | grep "content-length" | awk '{print $2}')
if [[ "$fileSize" == "$remoteSize" ]]; then
echo "$fileSize == $remoteSize"
else
# 断点续传(有时候有问题,报错curl: (33) HTTP server doesn't seem to support byte ranges. Cannot resume.)
curl -k -C - --retry 3 "$line" -o "$dload_loc"
fi
else
# 不存在本地文件,直接下载
curl -k --retry 3 "$line" -o "$dload_loc"
fi
done < e.txt
处理方案更新:解决-C无法续传问题
上节说道有时-C无法续传,我尝试使用–header指定range的方式下载,并把内容重定向到目标文件中。更新后的代码如下:
#!/bin/bash
while read line; do
dload_loc=${line#https://data.together.xyz/redpajama-data-1T/v1.0.0/}
mkdir -p $(dirname $dload_loc)
echo $line
# 如果文件不存在ls会报错,2>/dev/null,将报错信息不要打印在屏幕上
# -n 测试变量不为空
fileSize=$(ls -l $dload_loc 2>/dev/null | awk '{print $5}')
if [ -n "$fileSize" ]; then
# 存在本地文件,比较下载进度
remoteSize=$(curl -k --head -s "$line" | grep "content-length" | awk '{print $2}')
if [[ "$fileSize" == "$remoteSize" ]]; then
echo "$fileSize == $remoteSize"
else
# 断点续传,使用header指定Range(有时候-C有问题,报错curl: (33) HTTP server doesn't seem to support byte ranges. Cannot resume.)
curl -k --header "Range: bytes=$fileSize-$remoteSize" "$line" >> "$dload_loc"
fi
else
# 不存在本地文件,直接下载
curl -k --retry 3 "$line" -o "$dload_loc"
fi
done < e.txt
文件大小错误
本来以为CURL下载显示100%就算成功了,结果在最后文件校对阶段发现并不是那么回事儿。Common Crawl的文件大小一般在1G以上,但是文件夹中发现很多4k不到,或者5M左右的文件,明显是有问题的。因此没有办法只能全量扫一遍,看看那些文件有问题。比较科学的做法应该是使用SHA256 Checksums对比,但是有点懒了,使用现成的脚本搞一下吧。
#!/bin/bash
while read line; do
dload_loc=${line#https://data.together.xyz/redpajama-data-1T/v1.0.0/}
mkdir -p $(dirname $dload_loc)
echo $line
# 如果文件不存在ls会报错,2>/dev/null,将报错信息不要打印在屏幕上
# -n 测试变量不为空
fileSize=$(ls -l $dload_loc 2>/dev/null | awk '{print $5}')
if [ -n "$fileSize" ]; then
# 存在本地文件,比较下载进度
remoteSize=$(curl -k --head -s "$line" | grep "content-length" | awk '{print $2}')
if [[ "$fileSize" == "$remoteSize" ]]; then
echo "$fileSize == $remoteSize"
else
# 断点续传(有时候有问题,报错curl: (33) HTTP server doesn't seem to support byte ranges. Cannot resume.)
echo "需下载 $fileSize != $remoteSize"
fi
else
# 不存在本地文件,直接下载
echo "需下载 0"
fi
done < all.txt
扫完之后会发现一些问题,比如之前很多4k不到或者5M左右的文件最后显示实际大小超过1G。然而有些本来下载好的超过1G的文件,显示远端大小为5M。因此决定把小于1G的都重新扫描。以下是使用GREP对比文件后筛选出需要下载的URL。
grep -B1 == check.log | grep http > ok.txt
grep -v -f ok.txt all.txt > error.txt
扫码联系船长