このブログ投稿では、指定した DOI 番号に対応する文献を Python コードを通じて迅速にダウンロードし、Sci-Hub をダウンロード ライブラリとして使用する方法を紹介します。
1. ライブラリ関数の準備
始める前に、次のような必要なライブラリをインストールする必要があります。
- リクエスト: HTTP リクエストを送信し、レスポンスを取得するライブラリ。
- beautifulsoup4: HTML ページの解析に使用されます。
- スレッド化: マルチスレッド処理を実現するために使用されます。
これらのライブラリは pip コマンドを通じてインストールできます。具体的なコマンドは次のとおりです。
pip install requests
pip install BeautifulSoup
pip install threading
さらに、ダウンロードしたドキュメントを保存するには、コードが配置されているディレクトリに「papers」という名前のフォルダーを作成する必要があります。同時に複数のDOI名を含むtxtファイルを用意する必要があり、各DOI名は1行になります。
2. 導入手順
ダウンロード プロセス全体は、次の手順に大別できます。
- DOI 番号が保存されている txt ファイルを読み取ります。
- Sci-Hub リンクを構築し、HTTP リクエストを送信します。
- HTML ページを分析してドキュメントのダウンロード リンクを取得します。
- ドキュメントをダウンロードしてローカル フォルダーに保存します。
- ダウンロードの成功または失敗をログに記録します。
3. アルゴリズムを実現する
このコードは、txt ファイル内の doi 番号を読み取ることで Sci-Hub のリンクを結合し、解析してドキュメントのダウンロード リンクを取得してダウンロードします。
HTTP リクエストに必要なリクエスト ヘッダーを定義し、ドキュメントをダウンロードしてローカルに保存するために使用される download_paper() 関数を定義します。doi パラメータは、ダウンロードするドキュメントの DOI 番号です。この関数では、最初に DOI を使用します。数値は Sci-Hub リンクを構築し、HTTP リクエストを送信します。次に、HTML ページを解析することによってドキュメントのダウンロード リンクが取得され、ドキュメントはリクエスト ライブラリを使用してローカルにダウンロードされます。ダウンロードの成功と失敗に関する情報はコンソールに出力されるか、ログ ファイルに記録されます。最後に、DOI 番号を保存している txt ファイルを開き、その中の各行をたどって、download_paper() 関数を呼び出します。対応するドキュメントをダウンロードします。
Sci-Hub はドメイン名を頻繁に変更するため、実際のアプリケーションでは、ブラウザを通じて Sci-Hub にアクセスし、現在利用可能なドメイン名を見つけて、それを上記のコード内のリンクに置き換える必要があることに注意してください。
4.ダウンロードを高速化する
上記のコードはすでにドキュメントのダウンロード タスクを完了できますが、シングルスレッドのダウンロード速度は遅いため、マルチスレッドを使用してダウンロード プロセスを高速化できます。具体的には、ダウンロードするドキュメントの 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()