一、
需求说明:
入口文件:http://data.marsgis.cn/3dtiles/bim-youeryuan/tileset.json
从这个JSON开始,里面还有其他JSON的URL
然后再打开其他的JSON,依次找里面的JSON和b3dm文件,全部下载
注意:文件的路径也要创建。
二、
代码:
'''
此代码实现了下载影像的功能。
比如,给定入口URL和存储影像的根路径。
启动代码:
命令行:
python download_json_b3dm3.py(可以拖动过来) entranceURL(入口文件) resourceRootDirectory(爬取资源的根路径)
'''
from urllib import request
import os
import re
import sys
def get_html(url, user_agent='Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0', num_retries=10):
"""支持user-agent并且可以尝试多次爬取数据的爬虫"""
#print('Downloading:', url)
# user-agent设置
headers = {'User-agent': user_agent}
req = request.Request(url, headers=headers)
# print(req)
try:
response = request.urlopen(req)
html = response.read()
# 出错的处理
except urllib.error.URLError as e:
##print('Download error:', e.reason)
html = None
# 多次出错的处理
if num_retries > 0:
if hasattr(e, 'code') and 500 <= e.code < 600:
# retry 5XX HTTP errors
# 服务器出错,递归反复尝试
get_html(url, user_agent, num_retries-1)
return html
def mkdirs(path):
# 去除首位空格
path = path.strip()
# 去除尾部 \ 符号
path = path.rstrip("\\")
# 判断路径是否存在
# 存在 True
# 不存在 False
isExists = os.path.exists(path)
# 判断结果
if not isExists:
# 如果不存在则创建目录
# 创建目录操作函数
os.makedirs(path)
print(path+' 创建成功')
return True
else:
# 如果目录存在则不创建,并提示目录已存在
print(path+' 目录已存在')
return False
def write_json_b3dm(pathFile, fileContent):
'''
此函数用于保存json和b3dm文件。
pathFile,文件的绝对路径,类似这样:D:/3dtiles/bim-youeryuan/tileset.json。
fileContent,文件内容,二进制形式。
'''
mkdirs("/".join(pathFile.split("/")[:-1]))
with open(pathFile, "wb") as f:
f.write(fileContent)
print(pathFile + " 已下载。")
def saveJsonPathFile(jsonPathFile):
'''
此函数用于,保存所有下载的json文件的全路径。
jsonFilePath, json文件的全路径,包含文件名。
'''
global jsonPathFiles
jsonPathFiles.append(jsonPathFile)
def isJsonFile(pathFile):
'''
判断pathFile是json文件吗?
是,return True;
否,return False。
'''
if pathFile.split(".")[-1] == "json":
return True
else:
return False
def readJson(jsonPathFile):
'''
读取一个json文件,匹配里边的url字段,并把这些url保存到全局变量toDownloadFilesURLs。
toDownloadFilesURLs列表,此时只保存相对路径。类似这样:
['4/13/0/0.b3dm', '4/13/0.b3dm',...]。
jsonPathFile, 要读取的json文件的绝对路径。
'''
with open(jsonPathFile, "rb") as f:
content = f.read().decode("utf-8")
pattern = re.compile(r'{"url":"(.*?)"}') # 查找url
results = pattern.findall(content)
global toDownloadFilesURLs
toDownloadFilesURLs.extend(results)
def handleDownloadFailure(pathFile):
'''
此函数用于,处理获取到的html=None的情况。
处理操作:
在保存根目录下,创建downloadFailure.txt文件,记录下载失败的情况。
'''
global saveRootFolder
# 该文件存在,则添加内容。
if os.path.exists(saveRootFolder + "downloadFailure.txt"):
with open(saveRootFolder + "downloadFailure.txt", "a") as f:
f.write(pathFile + " downloadFailure!\n")
# 不存在,则创建、添加内容。
else:
with open(saveRootFolder + "downloadFailure.txt", "w") as f:
f.write(pathFile + " downloadFailure!\n")
def downloadFile(url, saveRootFolder):
'''
下载一个文件。
url, 该文件的接口,比如:http://data.marsgis.cn/3dtiles/bim-youeryuan/tileset.json
saveRootFolder,该文件要保存的根路径。
该文件保存的真实路径,要由url + saveRootFolder共同决定,
比如:D:/3dtiles/bim-youeryuan/tileset.json。
'''
# 保存文件的绝对路径。
pathFile = saveRootFolder + "/".join(url.split("/")[3:])
# 文件内容。字节串,或None。
html = get_html(url)
if html == None:
print("error: html == None!!!")
handleDownloadFailure(pathFile)
return
# 写文件。
write_json_b3dm(pathFile, html)
# 如果是json文件,则保存其绝对路径到全局变量jsonPathFiles列表。
if isJsonFile(pathFile):
saveJsonPathFile(pathFile)
def main(url, saveRootFolder):
'''
主函数。
'''
# 下载入口json文件。
downloadFile(url, saveRootFolder)
# 使用全局变量
global jsonPathFiles, toDownloadFilesURLs, resourceRootDirectory
# 循环匹配下载。
while True:
# 如果有待匹配的json文件,就一直循环。
if jsonPathFiles:
# 循环读取json文件,获取待下载url。
for jsonPathFile in jsonPathFiles:
readJson(jsonPathFile)
# 读完就清空该列表。
jsonPathFiles = []
# 循环下载任务列表,逐个下载。
for fileURL in toDownloadFilesURLs:
downloadFile(resourceRootDirectory + fileURL, saveRootFolder)
# 下载完就清空下载任务列表。
toDownloadFilesURLs = []
# 否则,打断。
else:
break
if __name__ == "__main__":
try:
# 计划文件保存路径类似这样: D:/3dtiles/bim-youeryuan/tileset.json
# 入口URL。
# url = "http://data.marsgis.cn/3dtiles/bim-youeryuan/tileset.json"
# 从命令行读取入口url参数。
url = sys.argv[1]
print("url:", url)
# 要爬取的影像资源的根路径。比如: http://data.marsgis.cn/3dtiles/bim-youeryuan/
resourceRootDirectory = sys.argv[2]
print("resourceRootDirectory:", resourceRootDirectory)
# 下载文件的根目录。
saveRootFolder = "D:/"
print("saveRootFolder:", saveRootFolder)
# 存放待匹配url的json文件的全路径。
jsonPathFiles = []
# 存放待下载的文件接口(匹配出来的相对路径。)
toDownloadFilesURLs = []
main(url, saveRootFolder)
print("done")
except IndexError:
print("请输入足够多的参数。类似这样:\
\n python prog.py(可以拖动过来) entranceURL(入口文件) resourceRootDirectory(爬取资源的根路径)")