python3 爬取影像数据

一、
需求说明:
入口文件: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(爬取资源的根路径)")
 

猜你喜欢

转载自blog.csdn.net/weixin_42193179/article/details/85163967
今日推荐