本篇博文将介绍如何通过Python的代码实现快速下载指定DOI号对应的文献,并且使用Sci-Hub作为下载库。
一、库函数准备
在开始之前,我们需要先安装一些必要的库,包括:
- requests:发送HTTP请求并获取响应的库;
- beautifulsoup4:用于解析HTML页面;
- threading:用于实现多线程处理;
这些库可以通过pip命令进行安装,具体命令如下:
pip install requests
pip install BeautifulSoup
pip install threading
除此之外,还需要在代码所在目录下创建一个名为“papers”的文件夹,用于保存下载下来的文献。同时,需要准备一个包含多个DOI号的txt文件,每个DOI号占一行。
二、实现步骤
整个下载过程大致可以分为以下几个步骤:
- 读取存储有DOI号的txt文件;
- 构造Sci-Hub链接并发送HTTP请求;
- 解析HTML页面,获取文献下载链接;
- 下载文献并保存到本地文件夹;
- 记录下载成功或失败的情况。
三、实现算法
代码通过读取txt文件中的doi号来拼接Sci-Hub的链接,然后解析得到文献下载链接并进行下载
定义了HTTP请求需要的请求头;接着定义了一个download_paper()函数,用于下载文献并保存到本地,其中doi参数是需要下载的文献的DOI号;在 download_paper() 函数内,我们首先根据DOI号构造了Sci-Hub链接,并发送HTTP请求;然后通过解析HTML页面,获取到了文献的下载链接,并使用requests库下载文献到本地,并将下载成功和失败的信息输出到控制台或记录到一个日志文件中;最后,我们打开存储有DOI号的txt文件,并遍历其中的每一行,调用download_paper()函数下载对应的文献。
需要注意的是,由于Sci-Hub常常会更换域名,因此在实际应用中,我们需要通过浏览器访问Sci-Hub,找到当前可用的域名,并将其替换到上述代码中的链接中。
四、加速下载
虽然上述代码已经可以完成文献下载的任务,但是由于单线程下载速度较慢,因此我们可以使用多线程来加速下载过程。具体来说,我们可以将需要下载文献的DOI号作为参数传递给download_paper()函数,并创建多个线程来并行下载文献。下面是一种使用多线程下载文献的代码实现方式:
import requests
from bs4 import BeautifulSoup
import os
import threading
# 创建papers文件夹用于保存文献
path = "C:/Users/ypzhao/Desktop/papers/"
if not os.path.exists(path):
os.mkdir(path)
# 请求头
head = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36"
}
# 下载文献的函数
def download_paper(doi):
# 拼接Sci-Hub链接
url = "https://www.sci-hub.ren/" + doi + "#"
try:
download_url = ""
# 发送HTTP请求并解析HTML页面
r = requests.get(url, headers=head)
r.raise_for_status()
soup = BeautifulSoup(r.text, "html.parser")
# 解析得到文献下载链接
if soup.iframe == None:
download_url = "https:" + soup.embed.attrs["src"]
else:
download_url = soup.iframe.attrs["src"]
# 下载文献并保存到文件
print(doi + "\t正在下载\n下载链接为\t" + download_url)
download_r = requests.get(download_url, headers=head)
download_r.raise_for_status()
with open(path + doi.replace("/", "_") + ".pdf", "wb+") as temp:
temp.write(download_r.content)
print(doi + "\t文献下载成功.\n")
# 下载失败时记录错误信息
except Exception as e:
with open("error.log", "a+") as error:
error.write(doi + "\t下载失败!\n")
if download_url.startswith("https://"):
error.write("下载url链接为: " + download_url + "\n")
error.write(str(e) + "\n\n")
# 打开包含doi号的txt文件
with open(path + "doi.txt", "r", encoding="utf-8") as f:
# 遍历读取doi号,并启动多线程下载文献
threads = []
for line in f:
doi = line.strip()
t = threading.Thread(target=download_paper, args=(doi,))
threads.append(t)
# 启动所有线程
for t in threads:
t.start()
# 等待所有线程完成
for t in threads:
t.join()