栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

爬虫对网盘文件下载

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

爬虫对网盘文件下载

目录

前因

需求分析

1、网盘目录结构

2、大致分析一下包含的文件类型

3、分析文件如何下载

代码实现

1、伪代码编写

1.1、文件目录递归伪代码

1.2、文件下载伪代码

2、请求参数

2.1、目录获取的请求参数

2.2、文件下载的请求参数

3、代码实现

问题分析


前因

先说一下前因,女朋友刚接了一个尽调项目,客户发给了她一堆尽调材料,结果我一看,好家伙,东西还不少,而且更可气的是,这网盘禁止下载,网页右键都被禁用了,所以另存的路子也行不通。

女朋友问我,有没有办法下载下来?

我当然说有,毕竟...男人不能说自己不行!

下面分析一下需求开干!

需求分析

1、网盘目录结构

首先尽调材料包含两个目录

图片1

每级目录向下还有多级目录

图片2

这个时候,如果我们想拿到所有的目录和目录文件,需要用到的最好的方式就是递归了。记下来,重点!!!

2、大致分析一下包含的文件类型

先随便打开几个目录,会看到存在最多的是.docx .xlsx .pdf和图片格式的文件,这基本上为我们写爬虫提供了有限的困难,因为类型越多,可能面临的爬取的困难就越大。

图片3

3、分析文件如何下载

我们首先随便打开一个文件,例如打开图片3第一个pdf,通过浏览器抓包工具分析该文件的实际地址。通过分析,可以看到可能有用的包为以下几个,我们逐个分析

图片4

点开第一个listdir请求,查看返回值,会发现是一个json数据,返回的其实是图片3的目录结构,那第一个请求就PASS

图片5

 接着再分析第二个请求,看到previewoss,基本就有种预感,这个和文件内容有关系。

图片6

该请求同样返回的是一个json,键值包括size和url。那现在大胆猜测一下,这个就是文件真实的调用地址。或者我们可以计算一下size对应的文件大小是 4717682Bytes = 4.49Mb ,和图片3第一个pdf大小一致,进一步确定这里的url是对我们有用的,然后我们复制这个url粘贴到浏览器搜索框,发现下载下来了一个没有后缀名的文件。当我把这个文件添加上.pdf后缀后,可以正常打开,并显示和网页一致。

图片7

到这里我们就可以开始写代码开始爬虫了,当然也可以把其他类型的文件也一起分析完,然后再写。但是我已经迫不及待了,我喜欢边写边调(别学我)。

代码实现

代码实现之前,我们要先构思一下代码结构,我们要爬取所有的目录文件,那边首先要把递归算法写出来,先定位到各个文件才能进行落地。然后就是对文件的下载代码。

1、伪代码编写

1.1、文件目录递归伪代码
def get_file_dir(主目录):

	import requests
    目录结构 = 请求获取主目录下目录结构

	if 文件类型 in 目录结构:
		下载文件
    
    if 目录结构中目录个数 == 0:
        pass
	else:
		# 循环遍历目录
		for 目录 in 目录结构:
			get_file_path(目录)

 1.2、文件下载伪代码
def get_file_detail(file_path):

	import requests
	resp = 通过requests向file_path发请求

	with open(文件保存地址,'wb') as f:
		f.write(resp.content)

 按照我们分析文件下载的实际情况来看,其实第一次拿到的文件地址只是我们预览地址,实际地址是存放在previewoss的response中,所以需要进一步完善文件下载伪代码。

def get_file_detail(file_path):

	import requests

	resp = 通过requests向file_path发请求
	文件实际引用地址 = resp.json()['url']
	file_resp = 通过requests向文件实际引用地址发请求

	with open(文件保存地址,'wb') as f:
		f.write(file_resp.content)

2、请求参数

2.1、目录获取的请求参数

我们需求分析时已经得知listdir的请求是获取文件目录,那我们直接就去看listdir请求的请求参数。

图片8

请求类型为post请求

图片9

这里需要注意请求参数是个dict,我们请求传参时要处理为dict类型 。请求头就不说了,大家都会。

2.2、文件下载的请求参数

同样,我们已经在数据分析中知道了previewoss请求对应的是获取文件真实地址,而文件真实地址只需要直接请求就可以下载,所以现在只需要分析previewoss的请求参数。

注:实际下载过程中遇到了不同文件请求参数不一致的情况,所以还是需要对每种类型文件进行详尽分析,避免下载出问题。

图片10

 请求还是post请求

图片11

 请求参数和2.1一致,为dict类型

查看两个请求后我们发现,参数的变化只是docid的不同,那么docid从哪来呢?

这个问题很简单,我们需求分析的时候listdir请求的response的每个列表元素中都有docid的键值,通过比对,其实是一致的!其他键值例如rev在其他类型文件的下载请求参数中是有用的。

3、代码实现

都分析完之后,我们最终的代码实现是这样的。

import json
import os

import requests

headers = {
        'cookie': 'xxxx',  # cookie 参数不变
        'Host': 'xxxx',
        'Origin': 'xxxx',
        'Referer': 'xxxx',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36',
    }

def get_file_dir(url, docid, rootpath='att'):
    if not os.path.exists(rootpath):
        os.mkdir(rootpath)

    data = {
        'attr': 'false',
        'by': "name",
        'docid': docid,
        'link': "xxxxx",
        'password': "xxxx",  # password为网盘分享密码
        'sort': "asc", }

    resp = requests.post(url, headers=headers, data=json.dumps(data))
    dir_list = resp.json()['dirs']  # 目录结构
    file_list = resp.json()['files']  # 文件结构

    for file in file_list:
        # 下载.DOCX 和 .XLSX
        if file['name'].endswith('.xlsx') or file['name'].endswith('.docx') :
            file_url = 'http://xxxxxx/api/v1/link?method=previewoss'
            get_file_detail(file_url, rootpath, file['docid'], file['name'])
        # 下载图片
        elif file['name'].endswith('.png') or file['name'].endswith('.jpg') :
            pic_url = 'http://xxxxxx/api/v1/link'
            get_pic_file(pic_url, rootpath, file['docid'], file['name'],file['rev'])
        else:
            # 下载pdf
            file_url = 'http://xxxxxxx/api/v1/link?method=previewoss'
            get_file_detail(file_url, rootpath, file['docid'], file['name'])

    if len(dir_list) == 0:
        pass
    else:
        for dir in dir_list:
            new_docid = dir['docid']
            path = dir['name']
            get_file_dir(url, new_docid, os.path.join(rootpath, path))


def get_file_detail(file_url, path, docid, docname):
    
    if docname.endswith('.xlsx') or docname.endswith('.docx'):
        data = {
            'docid': docid,
            'link': "xxxxxx",
            'password': "xxxx",
            'reqhost': "xxxxxxxxxxxx",
            'usehttps': 'false',}

        docname = docname.split('.')[0]+'.pdf'  # 此处做问题分析

    elif docname.endswith('.pdf'):
        data = {
            'attr': 'false',
            'by': "name",
            'docid': docid,
            'link': "xxxxxx",
            'password': "xxxx",
            'sort': "asc", }

    try:
        resp = requests.post(file_url, headers=headers, data=json.dumps(data))
        print(resp.json()['url'])
        file_real = resp.json()['url']

        file_resp = requests.get(file_real)
        with open(os.path.join(path, docname), 'wb') as f:
            f.write(file_resp.content)
            print(os.path.join(path, docname), '下载成功!!')
    except Exception as e:
        print(e)
        print(path,docname,'下载失败!!')


def get_pic_file(file_url, path, docid, docname,rev):

    data = {
        'method': 'thumbnail',
        'rev': rev,
        'docid': docid,
        'width': 10000000000,   
        'height': 10000000000,
        'quality': 50,
        'link': "xxxxx",
        'password': "xxxx",
        'nostatistic': 'true'
    }

    try:
        resp = requests.get(file_url, headers=headers, params=data)

        with open(os.path.join(path, docname), 'wb') as f:
            f.write(resp.content)
            print(os.path.join(path, docname), '下载成功!!')
    except Exception as e:
        print(e)
        print(path,docname,'下载失败!!')

if __name__ == '__main__':
    url = 'http://xxxxxxx/api/v1/link?method=listdir'
    docid = "xxxx"
    get_file_dir(url, docid)

问题分析

本次实战中遇到了几个问题,有的是需求分析未详尽,有的是网站的设置迷惑了爬虫导致的。现在做总结。

1、图片开始未能爬下来

图片格式的文件和pdf,word,excel的请求方式不同,从代码就可以看出来,请求一次直接落地就可以了。还是需要好好做需求分析啊!

2、word,excel 下载后无法打开

word打开报错“发现无法读取的内容”。这个问题困扰了我很久,一直没办法查明原因,后来查原因是说文件后缀名有问题,但是文件的命名又是完全按照网盘的命名,不会存在问题。百思不得解。

图片12

后来又详细看了看请求,发现一个response中有PDF标识,尝试着把.docx改成.pdf后,发现文件打开了!!好坑!!

图片13

 代码里把word,excel文件名全部处理成.pdf。

docname = docname.split('.')[0]+'.pdf'

重新执行爬虫,发现文件都保存下来了!

图片14

 

好了结束。

要去找女朋友请赏了!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1019165.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号