用 Python 爬取网页 PDF 和文档

该博客主要介绍使用Python进行网页爬取。以特定网站为例,阐述爬取网页PDF的步骤,包括在日历控件输入时间、下载文件,还提及解决selenium被反爬限制的方法;同时介绍爬取网页文档时遇到的问题及解决办法,最后推荐了一些相关资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 爬取网页 PDF

https://reader.jojokanbao.cn/rmrb 上 PDF 的下载为例

1.1 在日历控件中输入时间

参考博客:selenium+Python(Js处理日历控件)
网页的日期框中可以直接输入日期
在这里插入图片描述
找到输入框对应的标签,根据 class name 进行内容清楚和输入(如果标签有 id 属性可以根据 id 进行输入框确定),代码如下

browser.find_element_by_class_name('el-input__inner').clear()
browser.find_element_by_class_name('el-input__inner').send_keys('1976-10-09')

在这里插入图片描述
输入日期后需要回车才能刷新页面,使用 selenium 模拟键盘事件参考博客:selenium-模拟键盘事件(回车、删除、刷新等)
实现代码如下

from selenium.webdriver.common.keys import Keys

browser.find_element_by_class_name('el-input__inner').send_keys(Keys.ENTER)

1.2 下载 PDF 文件

使用 selenium 下载 PDF 文件参考博客:python selenium 下载pdf文件
需要将简单的 browser = webdriver.Chrome() 替换为如下代码

# PDF 文件保存路径
down_load_dir = os.path.abspath(".")
options = webdriver.ChromeOptions()
options.add_experimental_option("excludeSwitches", ['enable-automation'])
prefs = {
    "download.default_directory": down_load_dir,
    "download.prompt_for_download": False,
    "download.directory_upgrade": True,
    "plugins.always_open_pdf_externally": True
}
options.add_experimental_option('prefs', prefs)
options.add_argument("--disable-blink-features=AutomationControlled")
browser = webdriver.Chrome(options=options)

1.3 selenium 访问网站被反爬限制封锁

参考博客:python之selenium访问网站被反爬限制封锁解决方法
添加如下代码

browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": """
    Object.defineProperty(navigator, 'webdriver', {
      get: () => undefined
    })
  """
})

1.4 完整代码

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
from bs4 import BeautifulSoup
import os


url = 'https://reader.jojokanbao.cn/rmrb'

down_load_dir = os.path.abspath(".")
options = webdriver.ChromeOptions()
options.add_experimental_option("excludeSwitches", ['enable-automation'])
prefs = {
    "download.default_directory": down_load_dir,
    "download.prompt_for_download": False,
    "download.directory_upgrade": True,
    "plugins.always_open_pdf_externally": True
}
options.add_experimental_option('prefs', prefs)
options.add_argument("--disable-blink-features=AutomationControlled")
browser = webdriver.Chrome(options=options)

browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": """
    Object.defineProperty(navigator, 'webdriver', {
      get: () => undefined
    })
  """
})

browser.get(url)

browser.find_element_by_class_name('el-input__inner').clear()
browser.find_element_by_class_name('el-input__inner').send_keys('1976-10-09')
# 输入完成后,敲击键盘上的回车键
browser.find_element_by_class_name('el-input__inner').send_keys(Keys.ENTER)
time.sleep(5)

data = browser.page_source
# print(data)
# 获取文档的下载链接
soup = BeautifulSoup(data)
body = soup.find('div', attrs={'class': 'el-col el-col-24 el-col-xs-24 el-col-sm-12 el-col-md-12 el-col-lg-12 el-col-xl-12'})
link = body.find_all("a")[0].get("href")
print(link)

# 有了开始对 options 的设置,这一步可以直接下载 PDF 文档
browser.get(link)
time.sleep(5)
browser.close()

2 爬取网页文档

https://www.laoziliao.net/rmrb/ 上的文档下载为例

2.1 遇到的问题

整体实现思路和爬取小说(https://blog.csdn.net/mycsdn5698/article/details/133465660)的一样,实现过程中遇到了一些问题:
(1)BeautifulSoup 怎样获取标签间文本内容
获取标签的某个属性,例如 a 标签的 href 属性,代码如下

data = requests.get(url = url, headers = headers)
data.encoding = 'UTF-8'
soup = BeautifulSoup(data.text, 'html.parser')
body = soup.find('div', attrs={'id': 'month_box'})

for item in body.find_all('a'):
    link = item.get("href")
    print(link)

获取标签间的文本内容
如果标签属性较少,则可以使用正则提取,例子及其代码如下
在这里插入图片描述

findTitle = re.compile(r'<h3 class="card-title text-center text-danger">(.*?)</h3>',re.S)

for card in soup.find_all('div', class_="card mt-2"):
    # 提取标题
    card_title = re.findall(findTitle, str(card))[0]
    print(card_title)

如果标签属性较多,则可以参考博客:beautifulsoup怎样获取标签间文本内容,例子及其代码如下
在这里插入图片描述

data = requests.get(url = news_link, headers = headers)
data.encoding = 'UTF-8'
soup = BeautifulSoup(data.text, 'html.parser')
for context in soup.find_all('div', class_="card mt-2"):
    # 提取标题
    news_title = context.find('h2').string
    print(news_title)

(2)将 br 标签替换为换行符
例子如下
在这里插入图片描述
方法一:使用 get_text()
缺点:br 标签会变成一些空格,而不是换行

for news_context in context.find_all('div', class_="card-body lh-lg"):
    tmp_context = news_context.get_text()
    print(tmp_context)

方法二:参考博客 https://blog.csdn.net/u012587107/article/details/80543977
缺点:str(news_context) 的使用导致 div 标签出现,且 <br> 变成了 <br/>

for news_context in context.find_all('div', class_="card-body lh-lg"):
    tmp_context = (str(news_context).replace('<br>','\n')).replace('<br/>','\n')
    # str(news_context) 的使用导致 <div class="card-body lh-lg"> 和 </div> 也出现了
    tmp_context = (tmp_context.replace('<div class="card-body lh-lg">','')).replace('</div>','')
    # 新闻标题的第一行前是俩Tab,将其替换为四个空格
    tmp_context = tmp_context.replace('  ','    ')
    print(tmp_context)

2.2 完整代码

注意:ANSI 编码的文本在 kindle 打开会有部分乱码,UTF-8 编码的不会

import requests
import re
import time
from bs4 import BeautifulSoup

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

findTitle = re.compile(r'<h3 class="card-title text-center text-danger">(.*?)</h3>',re.S)


url = "https://www.laoziliao.net/rmrb/1946-06"

# 获取该月内所有日报的链接
data = requests.get(url = url, headers = headers)
data.encoding = 'UTF-8'
soup = BeautifulSoup(data.text, 'html.parser')
body = soup.find('div', attrs={'id': 'month_box'})

for item in body.find_all('a'):
    link = item.get("href")
    # print(link)
    
    # 根据 link 创建每天报纸的 TXT
    # 提取最后一个斜杠后面的字符
    last_slash_index = link.rfind("/")
    if last_slash_index != -1:
        TXT_name = link[last_slash_index + 1:]
        TXT_name = TXT_name.replace("-", "")
    print(TXT_name)
    # ansi 编码用 kindle 打开有乱码
    with open("./TXTs/"+TXT_name+".txt", "w", encoding='utf-8') as f:
        # 访问每天的报纸
        data = requests.get(url = link, headers = headers)
        data.encoding = 'UTF-8'
        soup = BeautifulSoup(data.text, 'html.parser')
    
        # 每一版的内容都放在 class="card mt-2" 的 div 中
        for card in soup.find_all('div', class_="card mt-2"):
            # 提取标题
            card_title = re.findall(findTitle, str(card))[0]
            f.write(card_title + '\n')
            # print(card_title)
        
            # 提取新闻链接
            news = card.find_all('a')
            news_link = news[0].get('href')
            if "#" in news_link:
                index = news_link.index("#")
            news_link = news_link[:index]
            print(news_link)
            time.sleep(1)

            # 访问当天的每一版新闻,每一条新闻都放在 class="card mt-2" 的 div 中
            data = requests.get(url = news_link, headers = headers)
            data.encoding = 'UTF-8'
            soup = BeautifulSoup(data.text, 'html.parser')
            for context in soup.find_all('div', class_="card mt-2"):
                # # 提取标题
                # news_title = context.find('h2').string
                # print(news_title)
                # 提取新闻内容,存放在 class="card-body lh-lg" 的 div 中
                for news_context in context.find_all('div', class_="card-body lh-lg"):
                    # 把<br>换成换行符
                    tmp_context = (str(news_context).replace('<br>','\n')).replace('<br/>','\n')
                    # str(news_context) 的使用导致 <div class="card-body lh-lg"> 和 </div> 也出现了
                    tmp_context = (tmp_context.replace('<div class="card-body lh-lg">','')).replace('</div>','')
                    # 新闻标题的第一行前是俩Tab,将其替换为四个空格
                    tmp_context = tmp_context.replace('  ','    ')
                    f.write(tmp_context + '\n')
                    # print(tmp_context)
            f.write('\n\n')

3 一些资源推荐

除了上述两个作为例子的网站,还有 时光印记经典珍藏系列,可以免费查看部分资料,全部资料的话是收费的。

python爬虫与项目实战,网络爬虫是一个自动提取网页的程序,它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成。 随着网络的迅速发展,万维网成为大量信息的载体,如何有效地提取并利用这些信息成为一个巨大的挑战。搜索引擎(Search Engine),例如传统的通用搜索引擎AltaVista,Yahoo!Google等,作为一个辅助人们检索信息的工具成为用户访问万维网的入口指南。但是,这些通用性搜索引擎也存在着一定的局限性,如: (1)不同领域、不同背景的用户往往具有不同的检索目的需求,通用搜索引擎所返回的结果包含大量用户不关心的网页。 (2)通用搜索引擎的目标是尽可能大的网络覆盖率,有限的搜索引擎服务器资源与无限的网络数据资源之间的矛盾将进一步加深。 (3)万维网数据形式的丰富网络技术的不断发展,图片、数据库、音频、视频多媒体等不同数据大量出现,通用搜索引擎往往对这些信息含量密集且具有一定结构的数据无能为力,不能很好地发现获取。 (4)通用搜索引擎大多提供基于关键字的检索,难以支持根据语义信息提出的查询。 网络爬虫 为了解决上述问题,定向抓取相关网页资源的聚焦爬虫应运而生。聚焦爬虫是一个自动下载网页的程序,它根据既定的抓取目标,有选择的访问万维网上的网页与相关的链接,获取所需要的信息。与通用爬虫(general purpose web crawler)不同,聚焦爬虫并不追求大的覆盖,而将目标定为抓取与某一特定主题内容相关的网页,为面向主题的用户查询准备数据资源。 传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。聚焦爬虫的工作流程较为复杂,需要根据一定的网页分析算法过滤与主题无关的链接,保留有用的链接并将其放入等待抓取的URL队列。然后,它将根据一定的搜索策略从队列中选择下一步要抓取的网页URL,并重复上述过程,直到达到系统的某一条件时停止。另外,所有被爬虫抓取的网页将会被系统存贮,进行一定的分析、过滤,并建立索引,以便之后的查询检索;对于聚焦爬虫来说,这一过程所得到的分析结果还可能对以后的抓取过程给出反馈指导。
Python中,爬取付费PDF文档并下载到本地通常涉及到网络请求、自动化登录(如果网站有登录验证)、解析网页内容寻找下载链接等步骤。这里以Selenium库配合requests库为例,因为很多付费资源可能需要JavaScript的支持才能显示下载链接。 1. **安装必要的库**: 首先,你需要安装`selenium`, `webdriver_manager`, `requests`。可以使用pip进行安装: ``` pip install selenium webdriver_manager requests ``` 2. **设置WebDriver**: Selenium需要浏览器驱动(WebDriver),比如ChromeDriver。你可以从ChromeDriver官网下载对应版本的驱动,并将其放置到系统的PATH中,或者通过`webdriver_manager`管理。 3. **模拟浏览器操作**: 使用`webdriver_manager`创建浏览器实例,然后打开目标页面: ```python from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager driver = webdriver.Chrome(ChromeDriverManager().install()) driver.get('付费PDF文档URL') ``` 4. **登录处理(如果有)**: 如果网站需要登录,找到登录表单的元素,填写用户名密码,然后点击登录按钮: ```python login_form = driver.find_element_by_id('login-form') # 假设id为login-form username_input = login_form.find_element_by_name('username') password_input = login_form.find_element_by_name('password') username_input.send_keys('your_username') password_input.send_keys('your_password') login_button = login_form.find_element_by_css_selector('.login-button') login_button.click() ``` 5. **查找下载链接**: 寻找页面上隐藏的下载链接,这可能需要根据HTML结构或特定CSS类来定位。找到后,使用`requests`库下载文件: ```python download_link = driver.find_element_by_xpath('//a[contains(@href, "download")]') # 假设XPath为... response = requests.get(download_link.get_attribute('href'), stream=True) with open('target_filename.pdf', 'wb') as f: for chunk in response.iter_content(chunk_size=1024): if chunk: f.write(chunk) ``` 6. **关闭浏览器**: 爬虫任务完成后记得关闭浏览器实例: ```python driver.quit() ``` 注意:这只是一个基础示例,实际操作可能会因网站结构防爬策略的不同而有所变化。在进行此类操作时,请遵守网站的使用条款,尊重版权,并确保你的行为合法合规。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值