写paper时随心记录一些对自己有用的skills与tips。
文章目录
一、待解决问题
1.1 问题描述
查询文献时,有众多文献想阅读,但一篇篇基于doi号去下载,费时费力。
因此,这篇文章基于IEEE Xplore搜索,撰写一段自动批量下载文献的程序。
1.2 解决方法
(1)安装Firefox浏览器驱动:geckodriver
(2)基于webdriver实现文献自动下载
(3)使用注意事项及待优化之处
二、方法详述
2.1 必要说明
(1)操作系统:ubuntu 22.04 LTS
(2)浏览器:Firefox 139.0.1 (64 位)
(3)python版本:3.11.11
(4)geckodriver版本:geckodriver 0.36.0
(5)selenium版本:4.24.0
2.2 应用步骤
2.2.1 安装Firefox浏览器驱动:geckodriver
geckodriver
是 Selenium 用于控制 Firefox 浏览器的驱动程序。它充当 Selenium 和 Firefox 浏览器之间的桥梁,允许 Selenium 发送命令到 Firefox 浏览器并接收响应。简单来说,geckodriver
是一个可执行文件,用于使 Selenium 能够自动化 Firefox 浏览器。
下载链接:https://github.com/mozilla/geckodriver/releases
然后解压并将可执行文件发送至对应目录:
tar -xvzf geckodriver-v0.36.0-linux64.tar.gz
sudo mv geckodriver /usr/local/bin/
geckodriver --version
geckodriver 0.36.0 (a3d508507022 2025-02-24 15:57 +0000)
The source code of this program is available from
testing/geckodriver in https://hg.mozilla.org/mozilla-central.
This program is subject to the terms of the Mozilla Public License 2.0.
You can obtain a copy of the license at https://mozilla.org/MPL/2.0/.
实际运行过程中,存在报错:
解决方式:使用selenium调用firefox提示Profile Missing的问题解决
2.2.2 基于webdriver实现文献自动下载
以下是基于selenium
、geckodriver
实现的在IEEE Xore上自动搜索doi批量下载文献的代码,功能概述如下:
(1)设置文献doi保存的txt,设置文献下载路径
(2)修改浏览器默认设置,访问IEEE Xplore官网,等待用户自行登录
(3)自动输入doi号开始搜索,有结果即寻找下载按钮进行pdf保存
(4)统计下载文献数量和未下载数量
import os
import time
from selenium import webdriver
from selenium.webdriver.firefox.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.firefox.options import Options
import shutil
def configure_firefox_driver(download_dir):
firefox_options = Options()
firefox_options.add_argument('-profile')
firefox_options.add_argument(
'/home/XXX/snap/firefox/common/.mozilla/firefox')
firefox_options.set_preference("browser.download.folderList", 2)
firefox_options.set_preference("browser.download.dir", download_dir)
firefox_options.set_preference(
"browser.helperApps.neverAsk.saveToDisk", "application/pdf")
firefox_options.set_preference("pdfjs.disabled", True)
geckodriver_path = "/usr/local/bin/geckodriver"
service = Service(geckodriver_path)
driver = webdriver.Firefox(service=service, options=firefox_options)
return driver
def search_and_download_doi(driver, doi, download_dir, title, notFound_path):
print(">>======<<")
print(f"开始搜索文献,标题:{title},DOI号:{doi}")
print(">>======<<")
try:
search_input = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "Typeahead-input"))
)
search_input.click()
search_input.clear()
print(f"输入DOI号: {doi}")
search_input.send_keys(doi)
search_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CLASS_NAME, "fa-search"))
)
search_button.click()
time.sleep(1)
try:
result_span = driver.find_element(
By.XPATH, "//span[contains(., 'Showing') and contains(., 'result')]")
result_text = result_span.text
if ("Showing" in result_text) & ("result" in result_text):
print("找到搜索结果,开始寻找PDF下载按钮...")
try:
pdf_link = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable(
(By.XPATH, "//a[@aria-label='PDF']/i[@class='icon-size-md xpl-pdf-icon fas fa-file-pdf']"))
)
pdf_relative_url = pdf_link.find_element(
By.XPATH, "./..").get_attribute("href")
pdf_url = pdf_relative_url
print("找到PDF链接:", pdf_url)
# 下载前读取文件夹中文件数量
prev_files = set(os.listdir(download_dir))
# 访问PDF页面,并自动下载pdf
driver.get(pdf_url)
# 等待下载完成,这里是手动设置60s延时等待下载,如果网速较慢的情况下需增大延时
print("等待PDF下载完成...")
time.sleep(60)
# 下载后读取文件夹中文件数量
current_files = set(os.listdir(download_dir))
# 比较文件数量变化
if len(current_files) == len(prev_files) + 1:
print(f"{title} PDF下载成功")
return True
else:
print(f"{title} PDF下载失败,文件数量没有增加")
with open(notFound_path, "a") as f:
f.write(f"标题:{title},DOI号:{doi}\n")
return False
return True
except:
print("未找到对应pdf下载按钮!")
with open(notFound_path, "a") as f:
f.write(f"标题:{title},DOI号:{doi}\n")
return False
else:
print("对应DOI无搜索结果!")
with open(notFound_path, "a") as f:
f.write(f"标题:{title},DOI号:{doi}\n")
return False
except:
print("未找到搜索结果!")
with open(notFound_path, "a") as f:
f.write(f"标题:{title},DOI号:{doi}\n")
return False
except Exception as e:
print(f"处理DOI号{doi}时发生错误: {str(e)}")
with open(notFound_path, "a") as f:
f.write(f"标题:{title},DOI号:{doi}\n")
return False
def read_papers(file_path):
papers = []
with open(file_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
title = None
doi = None
for line in lines:
line = line.strip()
if line.startswith('Title:'):
# 如果已经提取到标题和DOI,先将之前的信息添加到列表中
if title and doi:
papers.append({'title': title, 'doi': doi})
# 开始提取新的文献信息
title = line.replace('Title:', '').strip()
doi = None
elif line.startswith('DOI:'):
doi = line.replace('DOI:', '').strip()
# 添加最后一组文献信息
if title and doi:
papers.append({'title': title, 'doi': doi})
return papers
def count_lines_in_txt(file_path):
try:
with open(file_path, 'r', encoding='utf-8') as file:
line_count = 0
for line in file:
line_count += 1
return line_count
except FileNotFoundError:
print(f"文件 {file_path} 未找到。")
return -1
except Exception as e:
print(f"读取文件时发生错误:{e}")
return -1
def main():
file_path = "./selected_Paper_WOS.txt" # 保存文献title、doi号的文档
# 存放下载文献的路径,必须是绝对路径
download_dir = "/home/XXX/code/1env_paper/02_get_FullPaper/paper(Selected)"
notFound_path = "./not_found_Paper.txt" # 保存没有搜索到的文献doi
# 创建或清空名为 "not_found_Paper.txt" 的文件
with open(notFound_path, "w", encoding="utf-8") as file:
pass # 使用 pass 语句创建空文件
# 每次运行前删除旧的下载目录并创建新的
if os.path.exists(download_dir):
shutil.rmtree(download_dir)
print(f"已删除旧的下载目录 {download_dir}")
if not os.path.exists(download_dir):
os.makedirs(download_dir)
print(f"目录 {download_dir} 已创建")
driver = configure_firefox_driver(download_dir)
driver.get("https://ieeexplore.ieee.org/Xplore/home.jsp")
input("用户请自行登录IEEE Xplore,已登录后输入 'y' 并按回车继续: ")
num_selectedPapers = 0
try:
papers = read_papers(file_path)
num_selectedPapers = len(papers)
for paper in papers:
title = paper['title']
doi = paper['doi']
search_and_download_doi(
driver, doi, download_dir, title, notFound_path)
# 下载完成后返回主页,准备下载下一篇文章
driver.get("https://ieeexplore.ieee.org/Xplore/home.jsp")
print("返回IEEE Xplore主页...")
time.sleep(1)
finally:
driver.quit()
print("浏览器已关闭")
num_downloadPapers = len(set(os.listdir(download_dir)))
num_noFoundPapers = count_lines_in_txt(notFound_path)
print(f"+++总计预下载的文献有{num_selectedPapers}篇。+++")
print(f">>>从IEEE成功下载文献总计{num_downloadPapers}篇!<<<")
print(f"~~~未在IEEE找到文献总计{num_noFoundPapers}篇!~~~")
if __name__ == "__main__":
main()
2.2.3 使用注意事项及待优化之处
(1)注意事项-1 :修改浏览默认设置
def configure_firefox_driver(download_dir):
firefox_options = Options()
firefox_options.add_argument('-profile')
firefox_options.add_argument(
'/home/XXX/snap/firefox/common/.mozilla/firefox')
firefox_options.set_preference("browser.download.folderList", 2)
firefox_options.set_preference("browser.download.dir", download_dir)
firefox_options.set_preference(
"browser.helperApps.neverAsk.saveToDisk", "application/pdf")
firefox_options.set_preference("pdfjs.disabled", True)
geckodriver_path = "/usr/local/bin/geckodriver"
service = Service(geckodriver_path)
driver = webdriver.Firefox(service=service, options=firefox_options)
return driver
这个函数中1路径得自己确认:
firefox
路径:‘/home/XXX/snap/firefox/common/.mozilla/firefox’
geckodriver
路径:“/usr/local/bin/geckodriver”
-
firefox_options.set_preference("browser.download.folderList", 2)
:- 这行代码设置下载文件夹的列表。值为2表示使用自定义的下载路径。
-
firefox_options.set_preference("browser.download.dir", download_dir)
:- 这行代码设置下载文件的保存目录。
download_dir
是下载文件的保存路径。
- 这行代码设置下载文件的保存目录。
-
firefox_options.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/pdf")
:- 这行代码指定对于特定的MIME类型(这里是PDF文件,MIME类型为
application/pdf
),浏览器不会询问用户是否要下载,而是直接保存到磁盘。
- 这行代码指定对于特定的MIME类型(这里是PDF文件,MIME类型为
-
firefox_options.set_preference("pdfjs.disabled", True)
:- 这行代码禁用Firefox的内置PDF查看器。这样,当访问PDF文件时,Firefox会直接下载PDF文件而不是在浏览器中显示。
(2)注意事项-2 :下载成功判断不准确
# 等待下载完成,这里是手动设置60s延时等待下载,如果网速较慢的情况下需增大延时
print("等待PDF下载完成...")
time.sleep(60)
由于是手动设置60s延时等待下载,如果网速较慢的情况下,会存在未下载完就开始搜索下一篇文献的情况,但不影响下载进程。加上代码中判断是否下载成功,是在延时后判断文件夹内是否有文件数量+1,这就导致了可能下载进程未完成,但已经判断下载失败,是一个可以优化的地方。
三、疑问
暂无。
四、总结
- 上述代码只适用于firefox浏览器,若在其它浏览器使用,可下载对应驱动。
- 对于其它出版社的文献刊登网站,可以采用同样的方法,不过需要重新去适配对应网页的html元素设置逻辑,例如定位搜索框的html元素、搜索结果文本的html元素、pdf下载按钮的html元素等。