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

版本:

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

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

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

相关文章

在PostgreSQL中如何有效地批量导入大量数据,并确保数据加载过程中的性能和稳定性?

文章目录 解决方案1. 使用COPY命令2. 调整配置参数3. 禁用索引和约束4. 使用事务5. 并发导入 总结 在PostgreSQL中&#xff0c;批量导入大量数据是一个常见的需求&#xff0c;特别是在数据迁移、数据仓库填充或大数据分析等场景中。为了确保数据加载过程中的性能和稳定性&#…

第62天:服务攻防-框架安全CVE 复现SpringStrutsLaravelThinkPHP

目录 思维导图 常见语言开发框架&#xff1a; 案例一&#xff1a;PHP-开发框架安全-Thinkphp&Laravel Thinkphp3.2.x日志泄露 自动化脚本检测 如何getshell 手工注入 ​ThinkPHP5 5.0.23 手工注入 工具检测 laravel-cve_2021_3129 案例二&#xff1a;JAVAWEB-开…

docker (CentOS,ubuntu)安装及常用命令

Docker和虚拟机一样&#xff0c;都拥有环境隔离的能力&#xff0c;但它比虚拟机更加轻量级&#xff0c;可以使资源更大化地得到应用 Client&#xff08;Docker客户端&#xff09;&#xff1a;是Docker的用户界面&#xff0c;可以接受用户命令&#xff08;docker build&#xff…

AD设置覆铜与板子边缘间隔

1、设置板子边缘与覆铜间隔原因 在单个制板或者批量制板时&#xff0c;有时由于机器切割不稳定&#xff0c;造成切到覆铜&#xff0c;板子容易不稳定。为了保证机器切割不切到覆铜&#xff0c;我们可以设置覆铜到板子边缘的间隔。 2、设置方式 打开Design--->Rules&#…

【BUG】前端|GET _MG_0001.JPG 404 (Not Found),hexo博客搭建过程图片路径正确却找不到图片

我的问题 我查了好多资料&#xff0c;结果原因是图片名称开头是_则该文件会被忽略。。。我注意到网上并没有提到这个问题&#xff0c;遂补了一下这篇博客并且汇总了我找到的所有解决办法。 具体检查方式&#xff1a; hexo生成一下静态资源&#xff1a; hexo g会发现这张图片…

JUC面试——⭐⭐Java中的四种引用类型/Threadlocal

四种引用类型 Java 中对象的引用分为四种级别&#xff0c;这四种级别由高到低依次为&#xff1a;强引用、软引用、弱引用和虚引用。 基础知识 强引用&#xff1a;普通使用的引用 强引用是造成 Java 内存泄漏的主要原因之一 软引用&#xff1a; GC内存不够时回收 适用于&…

SpringBoot学习之Kafka下载安装和启动(三十三)

一、Mac环境 1、下载Kafka&#xff1a;Apache Kafka 2、这里我选择的版本是kafka_2.12-3.7.0&#xff0c;下载最新版的Kafka二进制文件&#xff0c;解压到你喜欢的目录&#xff08;建议目录不要带中文&#xff09;。 3、启动ZooKeeper服务&#xff0c;Kafka需要使用ZooKeeper&…

[linux]进程控制——进程等待

一、概念 进程等待&#xff0c;就是通过wait/waitpid的方式&#xff0c;让父进程&#xff08;一般&#xff09;对子进程进行资源回收的等待过程。 二、原因 &#xff08;1&#xff09; 当一个进程在退出的时候&#xff0c;如果不回收&#xff0c;就会变成僵尸状态&#xff0…

【C语言】——内存函数的使用及模拟实现

【C语言】——内存函数的使用及模拟实现 前言一、 m e m c p y memcpy memcpy 函数1.1、函数功能&#xff08;1&#xff09;函数名理解&#xff08;2&#xff09;函数介绍 1.2、函数的使用1.3、函数的模拟实现 二、 m e m m o v e memmove memmove 函数2.1、函数功能2.2、函数的…

Vulnhub靶机 DC-6 打靶实战 详细渗透测试过程

Vulnhub靶机 DC-6 详细渗透流程 打靶实战 目录 Vulnhub靶机 DC-6 详细渗透流程 打靶实战一、将靶机导入到虚拟机当中二、渗透测试主机发现端口扫描信息探测web渗透目录爆破爆破后台密码反弹shell搜集有价值信息SSH远程登录提权反弹jens用户权限的shell 提权利用 一、将靶机导入…

Mac 下安装PostgreSQL经验

使用homebrew终端软件管理器去安装PostgreSQL 如果没有安装brew命令执行以下命令 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 沙果开源物联网系统 SagooIoT | SagooIoT 1.使用命令安装postgreSQL brew i…

制作一个RISC-V的操作系统十二-定时器中断

文章目录 CLINT定时器中断mtimemtimecmp机制总体框架流程时间节拍系统时钟代码 CLINT 产生软件中断和定时器中断 定时器中断 mtime 类似计数器&#xff0c;按照硬件对应的固定频率递增 上电后会自动复位为0&#xff0c;有硬件自动完成 mtimecmp 需要自己设置&#xff0…

【SpringBoot实战篇】获取用户详细信息

1 明确需求 1需要获取用户详细信息 2 接口文档 1基本信息 2请求参数 无 3 响应数据 响应数据类型&#xff1a;application/json 响应参数说明&#xff1a; 响应数据样例 3 思路分析 1用户名在请求头里获取 4 开发 4.1 控制器usercontroller GetMapping("/userInfo")p…

Vue3——组件基础

组件基础 1. 组件定义与使用 1.1 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>组件基础&l…

iZotope RX 10 音频修复和增强工具 mac/win

iZotope RX 10 for Mac是一款出色的音频修复和增强工具&#xff0c;凭借其卓越的音频处理技术&#xff0c;能够轻松应对各种音频问题。 无论是背景噪音、回声还是失真&#xff0c;RX 10都能精准去除&#xff0c;还原清晰纯净的音频。同时&#xff0c;它还提供了丰富的增强工具&…

小红书电商运营实战课,从0打造全程实操(65节视频课)

课程内容&#xff1a; 1.小红书的电商介绍 .mp4 2.小红书的开店流程,mp4 3.小红书店铺基础设置介绍 ,mp4 4.小红书店铺产品上架流程 .mp4 5.客服的聊天过程和子账号建立 .mp4 6.店铺营销工具使用和后台活动参加 .mp4 7.小红书产品上架以及拍单教程,mp4 8.小红书如何选品…

第15届蓝桥杯题解

A题 结果&#xff1a;2429042904288 思路很简单 前20个数分别是 20 24 40 48 60 72 80 96 100 120 140 144 160 168 180 192 200 216 220 240 第2 4 6 8 12 ...n个数分别是24的 1倍 2倍 3倍 4倍 6倍 n/2倍 所以第202420242024 个数就是 24的 101210121012倍 B题 答案&am…

在PostgreSQL中如何实现递归查询,例如使用WITH RECURSIVE构建层次结构数据?

文章目录 解决方案使用WITH RECURSIVE进行递归查询示例代码 总结 在PostgreSQL中&#xff0c;递归查询是一种非常强大的工具&#xff0c;它可以用来查询具有层次结构或树形结构的数据。例如&#xff0c;你可能会在员工-经理关系、目录结构或组织结构图中遇到这样的数据。为了处…

嵌入式物联网实战开发笔记-乐鑫ESP32开发环境ESP-IDF搭建【doc.yotill.com】

乐鑫ESP32入门到精通项目开发参考百例下载&#xff1a; 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;4e33 3.1 ESP-IDF 简介 ESP-IDF&#xff08;Espressif IoT Development Framework&#xff09;是乐鑫&#xff08;Espressif Systems&#xff09;为 ESP 系列…

跨站攻击CSRF实验

1.low等级 先利用Burp抓包 将get响应的url地址复制&#xff0c;发到网页上&#xff08;Low等级到这完成&#xff09; Medium&#xff1a; 再将抓到的包发到Repeater上,对请求中的Referer进行修改&#xff0c;修改成和url一样的地址&#xff0c;修改成功。 在这里修改后发送 然…