python 网页重定向_小试牛刀:python爬虫爬取springer开放电子书.

本文记录了一次使用Python爬虫批量下载Springer开放电子书的过程。通过读取Excel文件获取链接,处理网页重定向,提取PDF下载地址,并利用迅雷进行批量下载。在实现过程中遇到了超时和链接分辨等问题,最终通过多线程和超时控制进行了优化。
摘要由CSDN通过智能技术生成

首先声明,本文旨在记录反思,并没有资源,代码也不具有借鉴意义(水平实在不行.

某天,水群的时候发现群友发了一个文件,里面是疫情时期springer开放的免费电子书名单,同时还附有下载链接,总共有400多本,这要是一个一个下载不得累死个人,只下载自己感兴趣的书也是一个好主意,但是,我全都要,它不爽吗?

因此就产生了写个爬虫下载电子书的想法,就在今天付诸于实践.

最初思路:

1.读取excel文件中所有书籍的链接,放在列表类中.

2.格式化列表中的链接,然后依次访问链接,提取下载pdf的链接地址.

3.将下载pdf的链接地址批量加入到迅雷的下载任务中.

理想很丰满,然而实际操作起来……

步骤1:首先网上bing如何读取excel文件中的数据。然后复制、黏贴、修改……

import xlrd
def get_bookurl_list(site):
    book = xlrd.open_workbook(site)
    sheet1 = book.sheet()[0] #第一张工作表
    urls = sheet1.col(18) #书籍地址在第18列所以里面也就是18
    urls = urls[1:] #去除第一行的列名 #xlrd库读出来的excel每一个小格都是一个cell类,cell.value才是真正的数据
    return urls

然鹅最初的思路在第二步就出现了问题……

我虽然可以用requests库访问网址,但是我找不到下载pdf的链接在哪里(虽然我看得见,也点的了(笑,但是在运行程序的时候我无法指定程序返回那个链接,也就是说,我无法操作爬虫返回指定的内容。

于是我打算直接返回网页内全部链接,然后我找到了一个更加傻瓜式的库——requests-html。里面的HTMLSession类有返回网页内所有链接绝对路径的方法。结果还是行不通,因为返回来的链接数量超出了我的预料,这还不算,更加致命的是,书记的页面还包含相关书籍的部分章节,单从链接上看基本没区别,更难顶的是,这书居然还能分章节下载。

这条路也行不通,我的心态发生了一些变化……

就在这时我发现,pdf下载地址和网页地址高度相似,而且具备确定的对应关系。但是问题也很明显,就是excel里给的地址是重定向了的,真正的地址只有进入网页才能获得。

但是总归有办法了,问题就在于重定向,只要我能获得进入页面的链接,就能够得到pdf的下载地址。

那么步骤2就变成了……网上bing如何获得重定向后的网页地址。复制黏贴修改……

import requests
def get_redirect_url(url):# 获得重定向前的链接
    #url = "重定向前的url"
    # 请求头,这里我设置了浏览器代理
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}
    # 请求网页
    response = requests.get(url,headers)
    print(response.status_code)  # 打印响应的状态码
    print(response.url)  # 打印重定向后的网址
    # 返回重定向后的网址
    return response.url

好了,现在我得到了原本的网站链接,经过一些修改就可以加入到迅雷下载了。

具体修改放到最后的总函数里,这里就先搁置,然后找到python调用迅雷加入下载任务的方法

然后步骤3:bingpython如何使用迅雷下载……复制黏贴修改……

from win32com.client import Dispatch #这都是啥玩意儿,咱也不知道,咱也不敢问
def thunderDownload(urls): #处理后网址的列表
    thunder = Dispatch('ThunderAgent.Agent.1') #这个也可以试试'ThunderAgent.Agent64.1',反正我错了(笑
    for i in urls:
        thunder.AddTask(i)
    thunder.CommitTasks()

最后的总函数:

def url_process(urls):
    list1 = []
    num = 0
    for i in urls:
        url = i.value #i为cell类,i.value是真正的数据
        url = get_redirect_url(url) #调用之前的函数,获得原本的网页链接。
        url1 = url.replace('book', 'content/pdf')
        url1 = url1 + '.pdf' #这两行都是对原来网址的处理,处理之后就可以加入迅雷下载啦。
        list1.append(url1)
        print(urls.index(i))
        if len(list1)>5: #本来预想的是每5个就加入迅雷下载任务,没想到我还是太年轻了。
            thunderDownload(list1)
            list1 = []
            num += 1
            print(num)

至此,爬虫程序基本的框架就完成了。

然鹅,实际运行也是一塌糊涂……动不动就超时,以及来自库里的报错……

我尝试加了一个监测程序运行时间,超时就跳进下一个循环的功能

然鹅……程序总是动不动就瘫痪

开始请求接口
开始执行
请求完成
请求超时
开始请求接口
开始执行
请求完成
请求超时
开始请求接口
开始执行

这是我添加双线程时间控制程序后……

所以最后的优化是,添加一个功能,超时跳入下一个循环。

尝试使用eventlet,加monkey_patch()方法后报错。

于是使用threading库,增加返回值

import threading

class MyThread(threading.Thread):
    def __init__(self, target, args=()): #目标函数
        super(MyThread, self).__init__()
        self.func = target
        self.args = args

    def run(self):
        #接收返回值
        self.result = self.func(*self.args)

    def get_result(self):
        #线程不结束,返回值为None
        try:
            return self.result
        except Exception:
            return None

def limit_decor(limit_time): #限制真实请求时间的装饰器
    def functions(func):
        def run(*params):
            thre_func = MyThread(target=func,args=params)
            #主线程结束(超出时长),则线程方法结束
            thre_func.setDaemon(True)
            thre_func.start()
            #计算分段沉睡次数(?
            sleep_num = int(limit_time // 1)
            sleep_nums = round(limit_time % 1, 1)
            #多次短暂沉睡并尝试获取返回值
            for i in range(sleep_num):
                time.sleep(1)
                infor = thre_func.get_result()
                if infor:
                    return infor
            time.sleep(sleep_nums)
            #最终返回值
            if thre_func.get_result():
                return thre_func.get_result()
            else:
                return "请求超时"
        return run
    return functions

def a1(url):
    print('开始请求接口')

    #把逻辑封装成一个函数,使用线程调用
    a_theadiing = MyThread(target=a2,args=url)
    a_theadiing.start()
    a_theadiing.join()

    a = a_theadiing.get_result()

    print("请求完成")
    print(a)
    return a,a_theadiing.result

@limit_decor(300) #将时长限制为5分钟,

def a2(url):
    print("开始执行")
    url = get_redirect_url(url)
    print("执行完成")
    return url

修改后的总函数:

def url_process(urls):
    list1 = []
    num = 0
    for i in urls:
        url = i.value
        #url = get_redirect_url(url)
        url = a1([url])[1]
        if url == "请求超时": continue
        else:
            url1 = url.replace('book', 'content/pdf')
            url1 = url1 + '.pdf'
            list1.append(url1)
            print(urls.index(i))
            if len(list1)>2:
                thunderDownload(list1)
                list1 = []
                num += 1
                print(num)

运行还算差强人意,主要也受到网络状态的影响。

最后,请不要吐槽我的代码可读性(笑,当然也欢迎大佬给出建议。

还有就是知乎这个鬼排版,找到了个markdown在线编辑器,下次试试在那写完再导入知乎。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值