最近在学习蒙特卡洛方法相关的理论知识,在证明置信概率与打靶次数的关系时用到了Hoeffding不等式,于是查了一部分文献,发现一篇论文的引用是一个讲义的资源网站,有很多PDF形式的讲义,因此想批量下载下来。之前只是大致有印象可以用python完成,但没有做过,因此本着学习和鼓捣的双重目的查了一下操作方法。
网上有很多大佬早就做过类似的事了,主要参考了
@WittyLu
的一篇文章,顺便学习了一下正则表达式。主要的区别在于原文是采用python自带的urllib库实现的,本文出于简单采用了requests库,并根据自己的理解进行了一些修改。
由于在下载文件的同时也想对方法本身进行学习,因此对一些细节都进行了研究。按照我自己折腾的顺序,主要工作主要分为以下几个部分:
1.requests库/urllib库相关
urllib库是参考文章采用的方法,在开始时也对其进行了一定的学习,并仿照原文进行了实现,达成了目标,
# 批量下载PDF,采用python原生urllib的版本
# 另一种方法为使用第三方的requests库
import urllib.request
import re
import os # 主要用于定位下载地址的
# 获取网页的全部内容
def getHTML(url):
page = urllib.request.urlopen(url, timeout=30)
html = page.read()
return html
# 通过正则表达式提取待下载的PDF的URL信息,需通过检查元素观察得到
def getURL(html):
reg = r'lecture'
reURL = re.compile(reg)
listURL = reURL.findall(html.decode('utf-8')) # page.read 返回值是byte型,需要转成str
return listURL
# 进行下载
def getFile(url):
file_name = url.split('/')[-1]
u = urllib.request.urlopen(url, timeout=60)
f = open(file_name, 'wb')
f.write(u.read())
f.close()
print(file_name + '下载成功')
rootURL = 'http://nowak.ece.wisc.edu/SLT09/'
rawURL = 'http://nowak.ece.wisc.edu/SLT09/'
html = getHTML(rawURL)
listURL = getURL(html)
# print(html)
# print(listURL)
# 用于划定下载目录
os.mkdir('Lectures')
os.chdir(os.path.join(os.getcwd(), 'Lectures'))
for url in listURL:
getFile(rootURL + url)
getHTML函数:用于获取待抓取网页的全部内容,urllib.request.urlopen()函数会返回一个HTTPResponse对象page,read()方法则给出byte形式的网页内容,这里为urlopen函数设置了请求超时时间(30s),因为网络比较差,将允许时间设置长一些能够增加下载的成功率。
getURL函数:使用正则表达式提取当前网页中待下载PDF的链接信息,具体在下一部分记录。
getFile函数:设定下载地址后,使用前两个函数得到的PDF文件URL对文件进行下载。网页上的音频、视频、图片本质上都是采用二进制码组成的,而read()方法返回值类型即为二进制,因此可以使用Python的文件操作直接对其进行存储。
采用urllib库成功完成了既定目标,期间有几次由于网络超时导致下载失败,但网络条件正常时能够成功。
本着折腾不止的原则,又对采用requests库的方法进行了学习,实现上大同小异,只需对原代码稍加修改即可
# 使用Requests爬
import requests as req
import os
import re
def getHTML(url):
page = req.get(url)
html = page.text
return html
def getURL(html):
reg = r'lecture'
reURL = re.compile(reg)
listURL = reURL.findall(html) # page.read 返回值是byte型,需要转成str
return listURL
def getFile(url, name):
r = req.get(url)
f = open(name, 'wb')
f.write(r.content)
f.close()
print(name + '下载成功')
rootURL = 'http://nowak.ece.wisc.edu/SLT09/'
rawURL = 'http://nowak.ece.wisc.edu/SLT09/'
html = getHTML(rawURL)
listURL = getURL(html)
os.mkdir('LEC/Lectures')
os.chdir(os.path.join(os.getcwd(), 'Lectures'))
for url in listURL:
getFile(rootURL + url, url)
使用resquest包的get()方法能够直接得到网址的内容,并返回一个Response对象page,此对象的text属性将以str形式返回网页编码内容,而content属性将以byte形式返回,这也导致了在进行正则表达式匹配和文件下载时的一些区别。这种方法同样完成了目标,而且似乎看起来更简单一些。
2.正则表达式
第一次用到正则表达式,之前只是听说而没有真正研究和使用过,因此耗费了一些时间对语法规则等进行了学习。主要参考了
Python学习网
的入门教程和一些博客内容,大概了解后感觉这东西还是很神奇和强力的,直接扒一个图片过来作为笔记,具体也懒得再记录了
个人理解正则表达式的基本功能是对用户给定的信息类型给出某种通用的描述范式,并借此将其从大量其他信息中提取出来并进行查找、替换、删除等操作,其操作对象为字符串。在这里,其主要功能为从原网址的内容中提取出想要下载的PDF文件们的URL信息,资源网址的界面(非常简陋)
脚本也非常简单
随便打开一个PDF
发现其URL只是在根网址的基础上添加了lecturex.pdf,因此在已知根网址URL的情况下只需对脚本中的相关内容进行提取,由于这个网站形式非常简单,甚至不用正则表达式也没有任何问题。这里提取红圈圈住的内容,因此正则表达式为
r'lecture'
使用re库中的compile方法可以将该表达式转换为一个对象,并使用findall()方法得到脚本中所有满足范式的内容,最终拼凑成待下载PDF的URL。
3.os模块
python中的os模块主要用于操作系统的访问操作,包括对目录的增删改查,判断等,这里主要用到它进行下载目录的创建以及当前目录的更改等。os模块的常用方法有
os.getcwd():获取当前路径
os.listdir(path):得到指定路径下的所有目录和文件名
os.mkdir(name):创建一个目录文件
os.chdir(path):改变当前目录至指定目录
os.path.isfile(path):判断是否为文件
os.path.join(path,name):将目录和文件名或目录合成一个目录
总结
通过这个问题初步学习了爬资源的一些手段,主要问题是研究这一通花费的时间远远大于了一个一个下载所花费的时间。
目前对异常的处理完全没有考虑到,且对于更复杂的情况后续都可以进行考虑。