本篇博文将介绍如何通过Python的代码实现快速下载指定DOI号对应的文献,并且使用Sci-Hub作为下载库。

一、库函数准备

在开始之前,我们需要先安装一些必要的库,包括:

  1. requests:发送HTTP请求并获取响应的库;
  2. beautifulsoup4:用于解析HTML页面;
  3. threading:用于实现多线程处理;

这些库可以通过pip命令进行安装,具体命令如下:

pip install requests
pip install BeautifulSoup
pip install threading

除此之外,还需要在代码所在目录下创建一个名为“papers”的文件夹,用于保存下载下来的文献。同时,需要准备一个包含多个DOI号的txt文件,每个DOI号占一行。

python 文献下载分析和管理_python

二、实现步骤

整个下载过程大致可以分为以下几个步骤:

  1. 读取存储有DOI号的txt文件;
  2. 构造Sci-Hub链接并发送HTTP请求;
  3. 解析HTML页面,获取文献下载链接;
  4. 下载文献并保存到本地文件夹;
  5. 记录下载成功或失败的情况。

三、实现算法

代码通过读取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()

五、运行结果

python 文献下载分析和管理_txt文件_02