Web自动化之Selenium实战案例1:论文pdf自动下载

server/2025/2/26 16:25:21/

        在上一篇文章中,我们介绍了Selenium的基础用法和一些常见技巧。今天,我们将通过中国科学:信息科学网站内当前目录论文下载这一实战案例来进一步展示Selenium的web自动化流程。

目录

中国科学:信息科学当期目录论文下载

1.网页内容分析

2.下载流程

检测浏览器内文件下载完毕后退出webdriver        

解压下载的zip文件

完整代码


中国科学:信息科学当期目录论文下载

https://www.sciengine.com/SSI/issuehttps://www.sciengine.com/SSI/issue中国科学:信息科学官网。

1.网页内容分析

        网页内容的分析是web自动化中的关键一步。通过分析网页结构,我们可以确定需要抓取的数据位置以及操作元素的方式。

        与爬虫不同的是,web自动化通常是对浏览器渲染后的html网页直接进行操作,因此,我们不需要像爬虫那样进行抓包分析,只需要在原网页中定位元素并进行相应的操作即可。


 中国科学信息科学网页源代码

      

         观察网页源代码,可以发现,下载时我们主要用到的两个组件是全选下载pdf,且这两个组件均为div元素,具有class_name属性,那么在代码中,我们便可以先定位到全选下载pdf 这两个div,接着按照顺序点击即可。

2.下载流程

        先不着急写代码,我们先手动操作一番,看一下整个流程是什么样子。

        

        按下全选后,所有文章被选中,且会在下方出现已选中13结果的字样,表示待下载的文件数量。

        每个文章的标题都在classname为title的div内的span标签下,我们分别复制第一个文章与最后一个文章的标题的XPATH:

python">'//*[@id="journal-list"]/div[1]/div[1]/div[4]/div/div[1]/div/div[2]/div[2]/a/span'
python">'//*[@id="journal-list"]/div[1]/div[1]/div[4]/div/div[13]/div/div[2]/div[2]/a/span'

      不难发现,对于第i个文章的标题,其XPATH应该为:

python">'//*[@id="journal-list"]/div[1]/div[1]/div[4]/div/div[{i}]/div/div[2]/div[2]/a/span'

     

  那么,为了功能更完善一些,我们还可以在点击全选之后按照出现的数量,遍历查找上述的XPATH下的内容的text属性,这些text便是所有的论文标题,我们还可以将其写入到txt中,与下载的论文一起保存到本地。

python">essay_titles=[]
total_number=browser.find_element(By.XPATH,'//*[@id="selectedArticleNum"]/strong')#定位全选之后弹出的已选中之后的数字total_number=int(total_number.text)#################################查找文章标题for i in range(1,total_number+1):essay_title=browser.find_element(By.XPATH,f'//*[@id="journal-list"]/div[1]/div[1]/div[4]/div/div[{i}]/div/div[2]/div[2]/a/span')essay_titles.append(essay_title.text)#################################将查找到的文章标题写入到与下载文件同路径的位置的txt内full_path=os.path.join(self.download_path,'下载论文列表.txt')with open(full_path,'w',encoding='utf-8') as file:for essay_title in self.essay_titles: file.write(essay_title+'\n')

  在按下下载PDF按钮后,页面会暂时的跳转到一个其他url下的空白页面,过一会儿后,文件开始下载,且下载到本地的格式为zip。

      

  按下下载pdf按钮后页面变化


检测浏览器内文件下载完毕后退出webdriver        

对于上述两个流程,倘若我们在代码中不加任何等待机制:即等待页面跳转完毕,文件开始下载至文件下载完毕的等待机制

即使我们在代码中没有写browser.quit()这样的命令,webdriver也会自动关闭的。

        这是因为我们的代码中涉及到自动化流程的只有点击全选下载pdf这两个按钮以及查找文章标题,一旦这三个任务完成后,webdriver是会自动关闭的。

        对于上述问题,最简单的思路是使用time.sleep()函数,设置足够多的秒数,保证点击下载pdf按钮后,从文件开始下载至文件下载完毕webdriver不会关闭,这里我已经测试过,使用time.sleep(30)足矣。


但是,这样有点太过于勉强,且不够优雅,有没有更好的解决方案呢?

答案是:有的。       

         大家在使用谷歌或者Edge浏览器下载文件时,如果在文件下载过程中,中途退出会发现源文件下载取消且中断,并且在下载文件的位置有一个 文件名.crdownload的文件,这是一个临时文件,表示文件在浏览器下载过程中未完全下载完毕,在下载完毕后文件名后缀中的.crdownload会消失。

        那么,我们便可以按照下边的方式来进行等待,这样等待的好处是只要文件下载完毕,webdriver立即关闭,不会等待多余时长。

python">import os
import time
def is_download_finished(download_path):files=os.listdir(download_path)for file in files:if file.endswith('crdownload'):#判断文件夹内是否存在crdownload结尾文件,如果有说明还webdriver内还有文件在下载中return Falsereturn True
while not is_download_finished(download_path):#while循环轮询time.sleep(1)#这里以1s为单位,若对等待时间要求较高,可以更换为0.1-0.5的小数
webdriver.quit()#关闭先前打开的webdriver

 等待文件下载完毕代码


        到这里就万事大吉了吗?No,No,No。还记得我们前边我们说到的,我们在点击下载pdf后,会有大概5s左右的空闲时间,在这5s内我们会临时跳转到一个新的网页,然后又跳转回到原来的网页,文件开始下载吗?

点击下载pdf后,跳转到空白网页 

大概5s后,返回原网页,文件开始下载

        对于上述现象,倘若我们在点击下载pdf后,直接使用上边的等待文件下载完毕的代码的话,由于文件还没开始下载,文件夹内也根本没有crdownload结尾的文件,此时代码中is_download_finishe函数会直接返回True,while循环一次也不执行,webdriver直接就退出了。

        所以,我们应该等待文件正式下载后再调用上边的代码,这里可以使用time.sleep函数,等待几秒钟页面跳转完毕,当然也可以使用webdriver的current_url属性,先临时保存原先网页url,然后一个while循环判断webdriver.current_url是否等于原来的网页的url来进行判断。为了省事,我们这里就直接使用time.sleep函数进行等待了。


解压下载的zip文件

解压已经下载好的zip文件,我们只需要使用python标准库内置的zipfile模块即可

python">import os
import zipfile
def extract_zip_file(download_path):#解压zip文件filelist=os.listdir(download_path)for file in filelist:if file.endswith('.zip'):zip_file_path=os.path.join(download_path,file)with zipfile.ZipFile(zip_file_path,'r') as zip:zip.extractall(download_path)

运行上述代码后,给定文件夹下的后缀为zip的文件夹内的内容将被解压到原路径下,注意:若你需要解压指定的zip文件夹,只需要将  if file.endswith('.zip'):更换为if file=='指定的zip文件名':即可。

完整代码

python">import os
import time
import zipfile
from selenium import webdriver
from selenium.webdriver.edge.options import Options
from selenium.webdriver.common.by import By
class 中国科学():def __init__(self,download_path:str,headless:bool=False):'''Args:download_path:下载文件保存路径headless:是否开启无头模式'''self.download_path=download_pathself.headless=headlessself.essay_titles=[]def extract_zip_file(self):#解压zip文件filelist=os.listdir(self.download_path)for file in filelist:if file.endswith('.zip'):zip_file_path=os.path.join(self.download_path,file)with zipfile.ZipFile(zip_file_path,'r') as zip:zip.extractall(self.download_path)def is_download_finished(self):#判断是否下载完毕files=os.listdir(self.download_path)for file in files:if file.endswith('crdownload'):return Falsereturn Truedef download(self):#下载文件prefs = {'download.default_directory': self.download_path,  # 设置默认下载路径"profile.default_content_setting_values.automatic_downloads": True  # 允许多文件下载} self.Options=Options()self.Options.add_argument('--disable-blink-features=AutomationControlled')#隐藏自动化控制self.Options.add_argument('--ignore-ssl-errosr')#忽略ssl错误self.Options.add_argument('--ignore-certificate-errors')#忽略证书错误self.Options.add_experimental_option("prefs", prefs)self.Options.add_experimental_option('excludeSwitches', ['enable-logging'])self.Options.add_experimental_option('excludeSwitches',['enable-automation'])#隐藏自动化控制if self.headless:#无头模式运行自动化代码self.Options.add_argument('--headless')self.Options.add_argument('--disable-gpu')else:passself.browser=webdriver.ChromiumEdge(self.Options)self.browser.maximize_window()#webdriver全屏self.browser.get('https://www.sciengine.com/SSI/issue')self.browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {#执行一段js代码,隐藏自动化控制"source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"""})select_all=self.browser.find_element(By.CLASS_NAME,'select.borderC2')download_pdf=self.browser.find_element(By.CLASS_NAME,'download.borderC2')self.browser.execute_script('arguments[0].click()',select_all)total_number=self.browser.find_element(By.XPATH,'//*[@id="selectedArticleNum"]/strong')#定位全选之后弹出的已选中之后的数字total_number=int(total_number.text)#################################查找文章标题for i in range(1,total_number+1):essay_title=self.browser.find_element(By.XPATH,f'//*[@id="journal-list"]/div[1]/div[1]/div[4]/div/div[{i}]/div/div[2]/div[2]/a/span')self.essay_titles.append(essay_title.text)#################################将查找到的文章标题写入到与下载文件同路径的位置的txt内full_path=os.path.join(self.download_path,'下载论文列表.txt')with open(full_path,'w',encoding='utf-8') as file:for essay_title in self.essay_titles: file.write(essay_title+'\n')##################################点击下载按钮,等待下载完毕后退出webdriverself.browser.execute_script('arguments[0].click()',download_pdf)time.sleep(7)#等待7s页面跳转完毕while not self.is_download_finished():time.sleep(1)self.browser.quit()self.extract_zip_file()
中国科学(r"E:\OneDrive\Desktop\中国科学信息科学",headless=False).download()

 运行结果


http://www.ppmy.cn/server/170793.html

相关文章

基于SpringBoot+Vue+uniapp的高校招聘小程序+LW参考示例

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

算法基础篇--模拟

模拟 模拟的含义 模拟, 顾名思义就是题目让你干什么,你就干什么。考察的是将思路转化成代码的代码能⼒。这类题⼀般较为简单,属于竞赛⾥⾯的签到题(但是,万事⽆绝对,也有可能会出现让⼈⾮常难受的模拟题&a…

python~http的请求参数中携带map

背景 调试 http GET请求的 map 参数,链路携带参数一直有问题,最终采用如下方式携带map 解决 user{"demo":"true","info":"王者"}url encode之后的效果如下所示 user%7B%22demo%22:%22true%22,%22info%22:%22…

【Linux Oracle】time命令+oracle exp压缩

Linux && Oracle相关文档,希望互相学习,共同进步 风123456789~-CSDN博客 1.说明 Linux中的time命令:主要用于测量命令的执行时间,并显示该命令在执行过程中所使用的系统资源情况,如CPU时间、内存和…

数学建模之数学模型—2:非线性规划

文章目录 非线性规划基本概念与结论凸集与凸函数极值条件无约束条件的极值判断条件有约束条件的极值判断条件 无约束非线性规划一维搜索算法步骤示例特点代码模板 最速下降法算法详细步骤 代码实现示例最优步长的求解 黄金分割法斐波那契法牛顿法阻尼牛顿法模式搜索法Powell方法…

单目摄像头物体深度计算基础原理

三维空间物体表面点位与其在图像中对应点之间的相互关系,必须建立相机成像的几何模型,这些几何模型参数就是相机参数,而相机参数的求解就是相机标定。 相机的参数矩阵包括内参和外参: 外参:决定现实坐标到摄像机坐标。…

mac下载MAMP6.8.1

因为mac的小皮面板没有php7.4了 链接:c9cc270e6961c17c.dmg官方版下载丨最新版下载丨绿色版下载丨APP下载-123云盘 鹅选一 附上大佬写的教程:MAMP PRO教程 - 牛奔 - 博客园

ubuntu安装配置docker

这里不再进行分步解读了,所有操作见下面命令 sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc…