最后的代码
先贴下最后的代码,再慢慢道来心路历程:
# -*- coding: utf-8 -*-
# Python 3.6.6
# 内置模块: time,os,webbrowser
import time,os,webbrowser
filename='GOCI_L1_2011.txt'
#读取下载链接,下载链接已保存到本地
def get_d_urls(filename):
d_urls = []
with open(filename,'r',encoding='utf-8') as f:
for line in f:
line = line.replace('\n','')
d_urls.append(line)
return d_urls
#下载文件
def get_file(d_url):
name_gz = d_url.split('/')[-1].split('.')[0]+'.gz'
name_he_gz = d_url.split('/')[-1]
#文件名有些是.he5.gz结尾,有些是.gz
#若文件名存在则跳过并返回0
if (os.path.exists(name_gz) or os.path.exists(name_he_gz)):
return 0
#否则下载,并返回1
webbrowser.open(d_url)
return 1
if __name__=="__main__":
d_urls = get_d_urls(filename)
for d_url in d_urls:
res = get_file(d_url)
#若res=0,说明文件已存在,跳过
if res:
name_gz = d_url.split('/')[-1].split('.')[0]+'.gz'
name_he_gz = d_url.split('/')[-1]
print(time.ctime(),": ", name_he_gz)
start = time.perf_counter()
while(True):
dur = time.perf_counter()- start
#文件下载完成或下载时间超过两分钟,则进行下一个任务
if ((dur>120) or os.path.exists(name_he_gz) or os.path.exists(name_he_gz)):
break
新的任务
今天GOCI L2数据总算下完了,想着我这边网速比较快,索性把L1的数据也下了。本以为就是L2的重复性劳动,结果发现被坑大了。
问题所在
L2数据在下载的时候是不需要登录的,把下载链接复制到任意的下载器或浏览器基本上都是可以直接下载的,但L1数据必须登录,而且中间会重定向链接。此外,L2数据比较小,平均200多M,新的数据有些还在100M以下,而L1数据大概在七八百兆。
各种尝试
下载链接的爬取不再赘述,把L2代码中的L2全改为L1就可以了。
首先还是希望能直接用BitComet下载最好了,但把下载链接直接复制到下载器,会下载到一个叫authorize的2K大小的文件,Notepad打开后就是要登录需要授权的的意思。然后我加上了用户名和密码,下载到的竟然是一个.html文件,应该是URL重定向的问题。试了下FDM,没找到可以登录账号密码的地方,又试了下IDM,IDM也连不上。
然后就逛了逛nasa的论坛,其中一篇帖子提到了批量下载:Can I download data in bulk via HTTP?GUI下载就甭想了,然后就开始尝试帖子中提到的wget和cURL。之前也百度过怎样在Windows下使用wget和cURL。在win10的PowerShell中是可以直接使用这两个命令的,可惜这两个都是另一个Invoke-WebRequest的别名。既然windows都把这个叫wget和cURL了,那也应该可以实现他们的功能吧。然后就搜了下Invoke-WebRequest的用法,发现例子中的不管是百度还是谷歌的网站都可以访问,但就是访问不了nasa的网站,弃之。
之后想到或许python中有可以使用cURL和wget的模块呢。百度后发现确实有,但wget模块又太简单,不带登录的功能,pycurl模块又略难,学的脑袋疼。
windows快走到死胡同了,就想到用Linux啊,先是安装虚拟机,结果发现没有VT不能使用,又没有在BIOS中找到开启Inter Virtualization Technology的地方。下面又想到在U盘中安装个miniLinux系统,仔细想想在使用wget和cURL下载数据之前大概还要学下LInux的使用,放弃。
冷静下来后把有可能实现批量下载的方法一一列下:
Linux | wget |
---|---|
cURL | |
Windows | cmdlet Invoke-WebRequest |
pycurl | |
py requests |
这样看来就只剩python中的requests模块了,但其中又遇到了相当多的问题。首先是死活登录不进去,参考了下Python模拟登录NASA
发现是authenticity_token的问题。之后成功登录。然后就get下载连载,发现返回的头文件中竟然没有长度数据,查看返回的内容发现有光重定向的问题,把重定向后的链接提取出来作为真实的下载链接,胜利在望了,但为什么总是连接断开呢,感觉要彻底凉凉了,尝试的代码如下:
import requests,time,re,os,
from bs4 import BeautifulSoup
from tqdm import tqdm #显示进度条
url_home = 'https://urs.earthdata.nasa.gov/home'
url_login = 'https://urs.earthdata.nasa.gov/login'
session = requests.Session()
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'}
login_html = ''
resp = session.get(url_home, headers=headers)
login_html = resp.text
soup = BeautifulSoup(login_html,'html.parser')
authenticity_token = soup.select('input')[1]['value']
print(authenticity_token)
username = 'xxxxxx'
password = 'xxxxxx'
data = {
'utf8':'✓',
'authenticity_token':authenticity_token,
'username':username,
'password':password,
'commit':'Log in',
}
resp = session.post(url_login, data = data, headers = headers)
print(resp.text)
url_raw='https://oceandata.sci.gsfc.nasa.gov/goci/getfile/COMS_GOCI_L1B_GA_20110404021640.he5.gz'
resp = session.get(url_raw,headers=headers)
url_redirect = re.findall(r'redirectURL = "(.*)"',resp.text)[0]
resp = session.get(url=url_redirect,headers=headers,stream=True)
os.chdir('D:')
filename = 'try.gz'
with tqdm(total = int(resp.headers['Content-Length']),desc='下载',unit='b',unit_scale=True,unit_divisor=1024,dynamic_ncols=True) as pbar:
with open(filename,'wb') as f:
for chunk in resp.iter_content(1024*1000):
f.write(chunk)
pbar.update(1024*1000)
最后突然灵光一闪,批量下载本质上是为了避免在浏览器中一个个的手点,那么为什么不能直接在python中直接调用浏览器下载,来模拟手点的行为呢。百度发现果然有有直接调用浏览器的模块,然后把浏览器的下载设置修改下,避免每个任务都要选择下载位置。具体代码如下:
import time,os,webbrowser
filename='GOCI_L1_2011.txt'
#读取下载链接,下载链接已保存到本地
def get_d_urls(filename):
d_urls = []
with open(filename,'r',encoding='utf-8') as f:
for line in f:
line = line.replace('\n','')
d_urls.append(line)
return d_urls
#下载文件
def get_file(d_url):
name_gz = d_url.split('/')[-1].split('.')[0]+'.gz'
name_he_gz = d_url.split('/')[-1]
#文件名有些是.he5.gz结尾,有些是.gz
#若文件名存在则跳过并返回0
if (os.path.exists(name_gz) or os.path.exists(name_he_gz)):
return 0
#否则下载,并返回1
webbrowser.open(d_url)
return 1
if __name__=="__main__":
d_urls = get_d_urls(filename)
for d_url in d_urls:
res = get_file(d_url)
#若res=0,说明文件已存在,跳过
if res:
name_gz = d_url.split('/')[-1].split('.')[0]+'.gz'
name_he_gz = d_url.split('/')[-1]
print(time.ctime(),": ", name_he_gz)
start = time.perf_counter()
while(True):
dur = time.perf_counter()- start
#文件下载完成或下载时间超过两分钟,则进行下一个任务,这里或许可以修改为超过两分钟(ip被限制),停止20分钟再进行下一个任务。
if ((dur>120) or os.path.exists(name_he_gz) or os.path.exists(name_he_gz)):
break
差不多是可以下载了,这里不得不感慨下,下个数据还要翻墙,做科研真难。