【记录】Python3|Selenium 下载 PDF 不预览不弹窗(2024年)

news2024/12/23 23:25:47

版本:

  • Chrome 124
  • Python 3.12
  • Selenium 4.19.0

版本与我有差异不要紧,只要别差异太大比如 Chrome 用 57 之前的版本了,就可以看本文。

如果你从前完全没使用过、没安装过Selenium,可以参考这篇博客《【记录】Python3|Selenium4 极速上手入门(Windows)》快速安装Edge版本的webdriver,再继续看下文。

前言

这个问题我本来以为就是抓个包解决的,不过后来才发现因为现在浏览器的设计原因,返回Content-Type:application/pdf;的时候就会自动在浏览器中预览文件,报文的响应会解析成以下东西:

<!doctype html><html>
<body style='height: 100%; width: 100%; overflow: hidden; margin:0px; background-color: rgb(51, 51, 51);'>
<embed name='2F7A72AC9A127791D290DA205760BBE4' style='position:absolute; left: 0; top: 0;'width='100%' height='100%' src='about:blank' type='application/pdf' internalid='2F7A72AC9A127791D290DA205760BBE4'>
</body></html>

这会导致网页在遇到这种响应的时候会预览PDF,而不是下载PDF。

网上方法一大堆我看五花八门的其实解决起来就那么回事,有人问我我就汇总一下ok废话不多说。

文章目录

    • 前言
    • 方式一:浏览器设置,PDF打开方式默认为下载
      • 1.1 具体做法
      • 1.2 做法评估
    • 方式二:Selenium设置,禁用PDF Viewer插件
      • 2.1 具体做法
      • 2.2 做法评估
    • 方式三:requests库,直接请求url
      • 3.1 具体做法
      • 3.2 方法评估
      • 彩蛋:不下载PDF直接读取内容

方式一:浏览器设置,PDF打开方式默认为下载

1.1 具体做法

参考:如何使 pdf 文件在浏览器里面直接下载而不是打开-Jacob’s Blog

如果关掉浏览器的PDF阅读模式就不会预览而是会直接下载,例如谷歌浏览器中的设置项,步骤如下:

  1. 打开设置,搜索pdf,前往网站设置。在这里插入图片描述
  2. 展开更多内容设置,并点击PDF文档。
    在这里插入图片描述
  3. 修改默认行为为下载PDF文件。
    在这里插入图片描述

如果设置了下载路径为“另存为”的话,仍然需要手动选择PDF的下载路径。如下所示。

在这里插入图片描述

但是,这个问题是可以解决的。
如果根据下面的步骤设置了默认下载路径,则会自动下载如下。

在这里插入图片描述

如下所示:

在这里插入图片描述

1.2 做法评估

  • 优点:能让我们的读者朋友们弄清楚不预览不弹窗的可视化逻辑。
  • 缺点:
    1. 这种做法放到selenium里面就没用了,因为这个设置不会继承到 chromedriver 中去
    2. 不会继承的问题是有可能解决的,即设置user-data-dir。不过我按照这个思路去解决发现并不起效
      options.add_argument("user-data-dir=C:/Users/User/AppData/Local/Google/Chrome/User Data/Default")
      
      具体路径可以通过chrome://version查看(路径查找参考:chromedriver官方文档),如下所示。
      在这里插入图片描述

方式二:Selenium设置,禁用PDF Viewer插件

2.1 具体做法

参考:selenium disable chrome pdf viewer python-稀土掘金

根据这篇博客,说其实谷歌浏览器是靠一个自带的叫PDF-Viewer的插件来打开网页的pdf,selenium有个语句能禁用这个插件。

相关代码如下:

from time import sleep
from selenium import webdriver

chrome_options = webdriver.ChromeOptions()
driver = webdriver.Chrome(chrome_options=chrome_options)

chrome_options.add_experimental_option('prefs', {
    "download.prompt_for_download": False,
    'plugins.always_open_pdf_externally': True
    })

driver = webdriver.Chrome(chrome_options=chrome_options)
sleep(1000) # 有时候会有人还没等到它下载就退出了,然后觉得这个方法没有作用,所以特地加一行sleep

注意一点,网上还流传着另一种代码:'plugins.plugins_disabled': ["Chrome PDF Viewer"],这个早就已经没用了(自从 Chrome 57)。具体的讨论帖子可以看 Disabling PDF Viewer plugin in chromedriver-StackOverflow。

2.2 做法评估

  • 优点:和Selenium结合得非常好;
  • 缺点:有人说这个方法不起效,因为他们没有sleep,在还没开始下载的时候这个程序就退出了。这个并不是编程人员的毛病,而是这个方法本身确实有缺点。① 它具体下载到哪里了不太好获取(因为是Default),还得另外写代码;② 你没办法确定这个 PDF 是否下载好了。(和第一个缺点一样,都是因为这个下载位置都不太好获取,下载状态更难获取)③ 需要等待一定的时间去下载它,但又难以知道要等多久。(这就是 Selenium 的缺点了,它在模拟方面登峰造极,也在线程控制方面和浏览器的线程控制一样随意而混乱……)

这个做法的缺点如此之多,以至于第三个方式存在极大的生存土壤。

方式三:requests库,直接请求url

3.1 具体做法

参考:没参考,这就是我自己平常的写法。

都已经有url了就别那么麻烦了,赶紧直接请求得到结果吧。。

可用的示例代码如下:

import requests

# URL of the PDF file
pdf_url = 'https://xx.pdf'

# Send an HTTP GET request to the URL
response = requests.get(pdf_url)

# Check if the request was successful (status code 200)
if response.status_code == 200:
    # Open a file in binary write mode
    with open('downloaded_pdf.pdf', 'wb') as f:
        # Write the PDF content to the file
        f.write(response.content)
    print("PDF downloaded successfully.")
else:
    print("Failed to download PDF. Status code:", response.status_code)

3.2 方法评估

  • 优点:简单直接高效。
  • 缺点:requests库有个坏处,就是总是要自己定义header的参数。而这一点Selenium弥补得很好。为了继承Selenium的自动填充的参数,避免反爬虫的问题,GPT添加headers如下所示
    from selenium import webdriver
    import requests
    
    # Set up Selenium WebDriver (make sure to have appropriate driver installed)
    driver = webdriver.Chrome()
    
    # Navigate to the website containing the PDF
    driver.get("https://example.com/your_pdf_link")
    
    # Extract the URL of the PDF file
    pdf_url = driver.current_url
    
    # Retrieve the headers from the WebDriver
    headers = driver.execute_script("return Object.fromEntries(new Map(Object.entries(arguments[0].headers)))", driver.execute_script("return window.navigator"))
    
    # Use requests to download the PDF file with headers
    response = requests.get(pdf_url, headers=headers)
    
    # Check if the request was successful
    if response.status_code == 200:
        # Save the PDF file
        with open("output.pdf", "wb") as f:
            f.write(response.content)
        print("PDF file downloaded successfully.")
    else:
        print("Failed to download the PDF file.")
    
    # Close the Selenium WebDriver
    driver.quit()
    

说实在的啊,这个script是不能用的,但是思路就是继承Selenium的参数
根据我的精心查找,我发现写出一个继承 Selenium 参数的 script 的方式已经值得再写一篇博客了,这篇博客的链接是【代码】Python3|Requests 库怎么继承 Selenium 的 Headers (2024,Chrome)。

一般情况(指对 headers 要求不高时)加上这一个参数就行,反爬虫厉害的网站得再加点别的:

 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36'}

彩蛋:不下载PDF直接读取内容

通过 requests 已经获取了 response 之后,可以通过如下步骤直接使用 pdf 的内容,这样做和下载之后再open是一样的:

import io
import PyPDF2

# 使用 io 模块创建一个 BytesIO 对象,以便将 response.content 传递给 PyPDF2
pdf_file = io.BytesIO(response.content)

# 创建一个 PdfFileReader 对象来读取 PDF 文件内容
pdf_reader = PyPDF2.PdfFileReader(pdf_file)

# 获取 PDF 文件中的页数
num_pages = pdf_reader.numPages
print("Number of pages:", num_pages)

# 逐页提取文本并打印
for page_num in range(num_pages):
    # 获取页面对象
    page = pdf_reader.getPage(page_num)
    # 提取文本
    text = page.extractText()
    # 打印文本
    print("Page", page_num + 1, ":", text.strip())

# 关闭 BytesIO 对象
pdf_file.close()

注意一定要用BytesIO,不需要再with open什么东西了。

好的就分享到这里。

本账号所有文章均为原创,欢迎转载,请注明文章出处:https://blog.csdn.net/qq_46106285/article/details/137883196。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1611867.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

EFK安装与使用!!!

一、将你的项目进行打包。 二、上传到docker&#xff0c; 启动项目 三、修改前端的代理路径 四、EFK相关配置 1、docker-compose.yml&#xff1a; version: 3 services:kibana:image: kibana:7.14.0ports:- "5601:5601"environment:- ELASTICSEARCH_HOSTShttp://19…

redhatcsa学习笔记--题目+答案

一、semanage命令 semanage命令 – 查询与修改安全上下文 semanage命令来自英文词组“SELinux manage”的缩写&#xff0c;其功能是用于查询与修改安全上下文。semanage的功能类似于chcon命令&#xff0c;它们都可以用于设置文件的SELinux安全上下文策略&#xff0c;而semana…

【火猫TV】NBA:汤普森不肯低头,库汤追组合几乎解体,他想留下只有一个办法

随着西部附加赛结束&#xff0c;拥有辉煌历史的勇士队彻底结束了自己本赛季的征程&#xff0c;面对国王队勇士被对手死死压制&#xff0c;除了库里之外其他球员都没有发挥出应有的水平。尤其是曾经的关键先生克莱汤普森&#xff0c;在比赛中竟然贡献了10投0中的尴尬数据&#x…

【nvm最新解决方案】Node.js v16.20.2 is not yet released or available

【nvm最新解决方案】Node.js v16.20.2 is not yet released or available 解决办法&#xff1a;下载想安装的node压缩包&#xff0c;放入nvm对应目录。 2024年最新node压缩包地址&#xff1a;https://nodejs.org/dist/ 1、选择对应的node版本&#xff1a;例如&#xff0c;我选的…

Spring AOP(面向切面编程)

1.Spring AOP 简介 1.1 AOP概述 AOP 为 Aspect Oriented Programming 的缩写&#xff0c;意思为面向切面编程, 是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续&#xff0c;是Spring框架中的一个重要内容&#xff0c;是函数式编程的一…

亚信安全数据安全运营平台DSOP新版本发布 注入AI研判升维

在当今快速发展的数字经济时代&#xff0c;企业对于数据的依赖日益加深&#xff0c;数据安全已成为企业的生命线。亚信安全推出数据安全运营平台DSOP全新版本&#xff0c;正是为满足企业对数据安全的高度需求而设计。这款平台以其卓越的能力和技术优势&#xff0c;为企业的数据…

链表基础4——带头双向循环链表

什么是带头双向循环链表 我们直接看图片 定义结点类型 typedef int LTDataType;//存储的数据类型typedef struct ListNode {LTDataType data;//数据域struct ListNode* prev;//前驱指针struct ListNode* next;//后继指针 }ListNode;链表的初始化 //创建一个新结点 ListNod…

Java 非对称加密RSA应用实现

1.RSA介绍 RSA算法是一种非对称加密算法&#xff0c;与对称加密算法不同的是,RSA算法有两个不同的密钥&#xff0c;一个是公钥&#xff0c;一个是私钥。 RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥&#xff0c;“由已知加密密钥推导出解密密钥在计算上是不可行的…

王者荣耀快速提升等级

1、为什么要提升等级 等级越高&#xff0c;解锁的玩法越多 等级越高&#xff0c;解锁的铭文数量越多&#xff0c;铭文能提升英雄的技能属性 2、如何快速提升等级 通过快速赛、排位赛、人机赛等均可以获取经验值 通过经验翻倍卡&#xff0c;可以快速获取经验值 3、经验卡翻倍…

YOLOv8水稻病害检测系统(python代码,可以通过图片、视频或者摄像头三种路径进行检测)

1.效果视频&#xff1a;最新最全面的水稻病害检测创作&#xff08;yolov8模型&#xff0c;稻瘟病、纹枯病、褐斑病、枯心病、霜霉病、水稻细菌性条纹斑病、稻苞虫等病害。&#xff09;_哔哩哔哩_bilibili 2.数据集介绍 水稻叶病害数据集&#xff08;目标检测&#xff0c;yolo…

信道的题目

调制信道分为恒参信道和随参信道。恒参信道举例&#xff1a;各种有线信道&#xff1b;中长波地波传播、卫星中继。随参信道举例&#xff1a;短波电离层反射信道、各种散射信道、移动通信信道。狭义信道分为有线信道和无线信道。广义信道包含调制信道和编码信道。调制信道中不包…

RK3568 android11 修改关机弹窗界面

需要修改关机弹窗界面&#xff0c;当前界面我已经按照客户需求去掉emergency 但是客户需要按其他区域可以实现返回&#xff0c;也就是点击黑色背景取消dialog 嗑代码发现黑色布局为&#xff1a; <node index"0" text"" resource-id"com.android.…

【R语言】混合图:小提琴图+箱线图

{ggstatsplot} 是 {ggplot2} 包的扩展&#xff0c;用于创建图形&#xff0c;其中包含信息丰富的绘图本身中包含的统计测试的详细信息。在典型的探索性数据分析工作流程中&#xff0c;数据可视化和统计建模是两个不同的阶段&#xff1a;可视化通知建模&#xff0c;而建模又可以建…

janus架构学习

基础介绍 Janus 是由Meetecho设计和开发的开源、通用的基于SFU架构的WebRTC流媒体服务器&#xff0c;它支持在Linux的服务器或MacOS上的机器进行编译和安装。Janus 是使用C语言进行编写的&#xff0c;它的性能十分优秀。 架构 janus为sfu架构 模块结构图 模块说明 core模…

C# Solidworks二次开发:获取模型、组件、主体的表面积相关API详解

大家好&#xff0c;今天要介绍模型、组件、主体的表面积相关API。 下面是今天要介绍的API: &#xff08;1&#xff09;第一个为SurfaceArea Property (IMassProperty)&#xff0c;这个API的含义为获取此模型的表面积&#xff0c;下面是官方的具体解释&#xff1a; 其没有输入…

如何解决DDoS攻击?群联科技做出回答。

DDoS攻击&#xff08;分布式拒绝服务攻击&#xff09;是一种恶意利用多台傀儡机协同发起大规模网络流量&#xff0c;旨在压垮目标系统或网络资源&#xff0c;使其无法正常服务的网络攻击手段。由于现代计算机和网络性能的提升&#xff0c;单点发起的DoS攻击已难以奏效&#xff…

UML 介绍

前言 UML 简介。 文章目录 前言一、简介1、事务2、关系1&#xff09;依赖2&#xff09;关联聚合组合 3&#xff09;泛化4&#xff09;实现 二、类图三、对象图四、用例图五、交互图1、序列图&#xff08;顺序图&#xff09;2、通信图 六、状态图七、活动图八、构件图&#xff0…

探索设计模式的魅力:开启智慧之旅,AI与机器学习驱动的微服务设计模式探索

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索AI与机器学习驱动的微服务设计模式之旅✨ 亲爱的科技爱好者们&#xff0c;有没…

C#语法知识之运算符

3、运算符 目录 3、运算符1、算数运算符思考 秒转化时间 2、字符串拼接3、条件运算符4、逻辑运算符5、位运算符6、三目运算符思考 闰年 1、算数运算符 1、赋值符号 //把右侧的值赋给左侧的变量2、算数运算符 _ * / float f 1 / 2f; %3、算数运算符的优先级 //乘除余优先级高…

Python可视化数据分析-饼状图

一、前言 饼状图&#xff08;Pie Chart&#xff09;是一种常用的数据可视化图表&#xff0c;用于展示数据中各部分的占比关系。Python 中有多种库可以用于绘制饼状图&#xff0c;比较常用的包括 matplotlib、pyecharts和 plotly 等。 二、使用 matplotlib 绘制饼状图 import…