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

版本:

  • Chrome 124
  • Python 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。百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

求π的近似值(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h> # include <math.h>int main() {//初始化变量值&#xff1b;int symbol 1;double denominator 1.0, sum 0, term 1.0;//循…

Excel文件解析(Java)

一、概述 在应用程序的开发过程中&#xff0c;经常需要使用 Excel文件来进行数据的导入或导出。所以&#xff0c;在通过Java语言实现此类需求的时候&#xff0c;往往会面临着Excel文件的解析(导入&#xff09;或生成&#xff08;导出)。 在Java技术生态圈中&#xff0c…

JVM运行时内存溢出以及解决办法

JVM有哪些运行时数据区 JVM运行时数据区有程序计数器、本地方法栈虚拟机栈、堆、元数据区、直接内存。 其中只有程序计数器不是内存溢出&#xff0c;其他的都有可能会产生内存溢出。 栈内存溢出 当方法的调用深度过深&#xff0c;可能会导致栈内存溢出。 一般是发生在递归调…

Elasticsearch:如何将 MongoDB 数据引入 Elastic Cloud

作者&#xff1a;Hemendra Singh Lodhi Elastic Cloud 是由 Elastic 提供的基于云的托管服务。Elastic Cloud 允许客户在亚马逊网络服务 (AWS)、谷歌云平台 (GCP) 和微软 Azure 上部署、管理和扩展他们的 Elasticsearch 集群。 MongoDB 是一种流行的 NoSQL 文档导向数据库&am…

IDEA最好用插件推荐

1 背景 俗话说&#xff1a;“工欲善其事必先利其器”&#xff0c;本问介绍几款强大实用的 IDEA 插件&#xff0c;助力大家开发。 希望大家做一个聪明又努力的人&#xff0c;而不只是一个努力的人。 以下插件大都可以通过 IDEA 自带的插件管理中心安装&#xff0c;如果搜不到可以…

算法|最大堆、最小堆和堆排序的实现(JavaScript)

一些概念 堆&#xff1a;特殊的完全二叉树&#xff0c;具有特定性质的完全二叉树。大根堆&#xff1a;父节点 > 子节点小根堆&#xff1a;父节点 < 子节点 二叉堆也属于完全二叉树&#xff0c;所以可以用数组表示。 若下标从1开始&#xff0c;左节点为 2*i &#xff0…

类和对象-封装-设计案例1-立方体类

#include<bits/stdc.h> using namespace std; class Cube{public://设置长void setL(int l){m_Ll;} //获取长int getL(){return m_L;}//设置宽 void setW(int w){m_Ww;}//获取宽 int getW(){return m_W;}//设置高 void setH(int h){m_Hh;}//获取高int getH(){return m_H;…

【机器学习300问】72、神经网络的隐藏层数量和各层神经元节点数如何影响模型的表现?

评估深度学习的模型的性能依旧可以用偏差和方差来衡量。它们反映了模型在预测过程中与理想情况的偏离程度&#xff0c;以及模型对数据扰动的敏感性。我们简单回顾一下什么是模型的偏差和方差&#xff1f; 一、深度学习模型的偏差和方差 偏差&#xff1a;衡量模型预测结果的期望…

JAVAEE—UDP协议TCP协议/三次握手四次挥手

文章目录 UDP协议UDP协议的段格式UDP的传输过程校验和无连接 TCP协议TCP报文的格式段有连接可靠性确认应答超时重传如果ACK丢了呢&#xff1f; 序号和确认序号 连接的构建和断开连接的构建&#xff08;三次握手&#xff09;三次握手的作用为什么握手是三次&#xff0c;而不是四…

微信小程序的常用API ①

前言&#xff1a;什么是微信小程序的API&#xff1f; &#xff08;1&#xff09;微信小程序的API是由宿主环境提供的。通俗来说API是一种接口函数&#xff0c;把函数封装起来给开发者使用&#xff0c;这样好多功能都无需开发者去实现&#xff0c;直接调用即可。 &#xff08;…

工业电脑在ESOP工作站行业应用

ESOP工作站行业应用 项目背景 E-SOP是实现作业指导书电子化&#xff0c;并统一管理和集中控制的一套管理信息平台。信迈科技的ESOP终端是一款体积小巧功能齐全的高性价比工业电脑&#xff0c;上层通过网络与MES系统连接&#xff0c;下层连接显示器展示作业指导书。ESOP控制终…

Covalent Network(CQT)宣布推出面向 Cronos 生态的捐赠计划与 API 积分,为 Web3 创新赋能

为了促进 Web3 领域的创新&#xff0c;Covalent Network&#xff08;CQT&#xff09;宣布将其捐赠计划向 Cronos 生态系统中的开发者拓展。这一战略性举措&#xff0c;旨在通过向 Cronos 网络中基于 Covalent Network&#xff08;CQT&#xff09;API 构建的项目提供支持和资源&…

OpenHarmony实战开发-如何使用Navigation实现多设备适配。

介绍 在应用开发时&#xff0c;一个应用需要适配多终端的设备&#xff0c;使用Navigation的mode属性来实现一套代码&#xff0c;多终端适配。 效果图预览 使用说明 将程序运行在折叠屏手机或者平板上观看适配效果。 实现思路 本例涉及的关键特性和实现方案如下&#xff1a…

高版本Android studio 使用Markdown无法预览(已解决)

目录 概述 解决方法 概述 本人升级Android studio 当前版本为Android Studio Jellyfish | 2023.3.1 RC 2导致Markdown无法预览。 我尝试了很多网上的方法都无法Markdown解决预览问题&#xff0c;包括升级插件、安装各种和Markdown相关的插件及使用“Choose Boot Java Runtim…

Linux 操作系统编译器、静态库、动态库

1、编辑器 1.1、vim的安装 指令&#xff1a;sudo apt-get install vim 1.2 vim的使用 格式&#xff1a;vim 文件名 如果文件存在&#xff0c;只打开&#xff0c;文件不存在&#xff0c;创建并打开 vim的4中模式&#xff1a; 命令模式&#xff0c;插入模式&#xff0c;地行模…

springboot Logback 不同环境,配置不同的日志输出路径

1.背景&#xff1a; mac 笔记本开发&#xff0c;日志文件写到/data/logs/下&#xff0c;控制台报出&#xff1a;Failed to create parent directories for [/data/logs/........... 再去手动在命令窗口创建文件夹data&#xff0c;报Read-only file system 2.修改logback-spri…

Hbase的shell命令(详细)

一、help 1.help 显示命名的分组情况 2.help 命令名称 查看命令的具体使用&#xff0c;包括命令的作用和用法。 举例&#xff1a;help list 二、general 组&#xff08;普通命令组&#xff09; 命令 描述 …

Redux极客园项目初始化搭建

基本结构搭建 实现步骤 在 Login/index.js 中创建登录页面基本结构在 Login 目录中创建 index.scss 文件&#xff0c;指定组件样式将 logo.png 和 login.png 拷贝到 assets 目录中 代码实现 pages/Login/index.js import ./index.scss import { Card, Form, Input, Button }…

【第十二届“泰迪杯”数据挖掘挑战赛】【2024泰迪杯】B题基于多模态特征融合的图像文本检索—更新(正式比赛)

【第十二届“泰迪杯”数据挖掘挑战赛】【2024泰迪杯】B题基于多模态特征融合的图像文本检索—更新&#xff08;正式比赛&#xff09; 往期链接&#xff1a; 【第十二届“泰迪杯”数据挖掘挑战赛】【2024泰迪杯】B题基于多模态特征融合的图像文本检索—解题全流程&#xff08;…

安防视频监控/视频集中存储EasyCVR平台级联时,下级平台未发流是什么原因?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…