【记录】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 webdriverchrome_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 modewith open('downloaded_pdf.pdf', 'wb') as f:# Write the PDF content to the filef.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 filewith 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.hqwc.cn/news/636400.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3D感知生成对抗网络的高斯溅射解码器

Gaussian Splatting Decoder for 3D-aware Generative Adversarial Networks 3D感知生成对抗网络的高斯溅射解码器 Florian Barthel1, 2  Arian Beckmann1  Wieland Morgenstern1  Anna Hilsmann1  Peter Eisert1,2 Florian Barthel 1, 2 阿里安贝克曼Wieland晨星Anna Hils…

【数据结构练习题】堆——top-k问题

♥♥♥♥♥个人主页♥♥♥♥♥ ♥♥♥♥♥数据结构练习题总结专栏♥♥♥♥♥ ♥♥♥♥♥上一章&#xff1a;【数据结构练习题】二叉树(1)——1.相同的树2.另一颗树的子树3.翻转二叉树4.平衡二叉树5.对称二叉树♥♥♥♥♥ 文章目录 1.top-k问题1.1问题描述1.2思路分析1.3绘图分析…

数据分析_商品维度占比及变化可视化分析(Pandas和Matplotlib)

数据分析_商品维度占比及变化可视化分析(Pandas和Matplotlib) 分析维度包括: 各商品年度销量占比 各商品月度销量变化 构建测试数据 这里你可以了解到: 如何生成时间相关的数据。 如何从列表&#xff08;可迭代对象&#xff09;中生成随机数据。 Pandas 的 DataFrame 自…

LabVIEW仪器信息管理系统

LabVIEW仪器信息管理系统 在计量检测实验室的日常工作中&#xff0c;仪器检定校准是一项基础而重要的任务。随着科技的进步和实验室工作量的增加&#xff0c;传统的人工管理方式已经难以满足现代实验室对效率和准确性的要求。开发一套基于LabVIEW的仪器信息管理系统显得尤为必…

ROS分布式通讯配置

4WD 必读&#xff1a;分布式通讯是相对于用虚拟机来连接小车上主机来说&#xff0c;如果是 4WD 笔记本无主 机用户&#xff0c;不存在分布式通讯一说。 1.4WD 用户单笔记设置一&#xff0c;连接底盘和雷达还有摄像头。 因为虚拟机带宽问题&#xff0c;无法保证摄像头正常运行。…

51单片机入门_江协科技_31~32_OB记录的自学笔记_LCD1602液晶显示屏

31. LCD1602 31.1. LCD1602介绍 •LCD1602&#xff08;Liquid Crystal Display&#xff09;液晶显示屏是一种字符型液晶显示模块&#xff0c;可以显示ASCII码的标准字符和其它的一些内置特殊字符&#xff0c;还可以有8个自定义字符 •显示容量&#xff1a;162个字符&#xff0c…

汽车4S集团数据分析

派可数据分析--汽车4S集团。 派可数据汽车4S集团数据分析概述。派可数据汽车4S集团分析主题全面涵盖行业内各板块业务分析&#xff0c;具体包括&#xff1a;保险业务分析、客户关系分析、汽车保养情况分析、售后维修主题分析、整车销售分析、整车库存分析、装具销售分析、配件…

Zynq 7000 系列中的JTAG和DAP子系统

Zynq 7000系列SoC器件通过标准JTAG调试接口提供调试访问。在内部&#xff0c;SoC设备器件在处理系统&#xff08;PS&#xff09;内部实现了一个Arm调试访问端口&#xff08;DAP&#xff09;&#xff0c;同时在可编程逻辑&#xff08;PL&#xff09;内部实现了一个标准的JTAG测试…

二叉树高频题目下

下 最近公共祖先 包含 分了两树 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/ class Solution { public:TreeNode* lowestCommo…

使用Redis实现全局唯一ID

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 在分布式系统中&am…

「 网络安全常用术语解读 」软件成分分析SCA详解:从发展背景到技术原理再到业界常用检测工具推荐

软件成分分析&#xff08;Software Composition Analysis&#xff0c;SCA&#xff09;是一种用于识别和分析软件内部组件及其关系的技术&#xff0c;旨在帮助开发人员更好地了解和管理其软件的构建过程&#xff0c;同时可帮助安全人员揭秘软件内部结构的神秘面纱。SCA技术的发展…

安装mysql的流程

安装mysql的步骤 安装流程 [rootlocalhost z]# cd /mnt/share/share[rootlocalhost share]# ll[rootlocalhost share]# cp mysql157-community-release-el7-10.noarch.rmp /usr/localcp: cannot stat ‘mysql157-community-release-el7-10.noarch.rmp’: No such file or direc…