天天看點

GOCI L1資料批量下載下傳最後的代碼新的任務問題所在各種嘗試

最後的代碼

先貼下最後的代碼,再慢慢道來心路曆程:

# -*- 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也連不上。

GOCI L1資料批量下載下傳最後的代碼新的任務問題所在各種嘗試

然後就逛了逛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
           

差不多是可以下載下傳了,這裡不得不感慨下,下個資料還要翻牆,做科研真難。