爬虫技术-利用Python和Selenium批量下载动态渲染网页中的标准文本文件
近日工作需要整理信息安全的各项标准文件,这些文件通常发布在在官方网站,供社会各界下载和参考。
这些页面中,标准文本文件常以Word(.doc/.docx)或PDF格式提供下载。由于文件数量庞大,手动逐条点击下载效率极低,且易遗漏,因此决定通过爬虫脚本进行批量自动化下载。
一、流程规划和难点分析
下载流程:
- 列表页:通过下方链接可以获取所有征求意见通知的标题和对应详情页链接。全国信息安全标准化技术委员会Free HTML5 Template by FREEHTML5
https://www.tc260.org.cn/front/bzzqyjList.html?start=0&length=10
- 详情页:点击通知后进入详情页,页面中包含“标准文本”文件的下载链接。
- 文件下载:点击下载链接即可获得Word或PDF格式文件。
要点分析:
- 动态渲染:标准文本文件的下载链接并不直接写在静态HTML里,而是由页面JavaScript动态生成。
- 多格式文件:文件格式多样,包含
.doc
,.docx
,.pdf
,需兼顾。 - 文件命名需求:下载文件需根据通知标题提取核心标准名,生成规范文件名,方便管理。
- 稳定性和礼貌爬取:避免请求过快导致被封,需合理设置间隔。
二、技术选型
- Requests + BeautifulSoup:用于抓取列表页的静态HTML,解析出通知标题和详情页链接。
- Selenium:用于模拟浏览器,完整渲染详情页JavaScript后获取文件下载链接。
- webdriver-manager:自动管理Chrome驱动,简化环境配置。
- Python标准库:文件操作、正则表达式处理文件名等。
三、具体实现
获取列表页信息
用requests
请求列表页,利用BeautifulSoup
解析HTML,定位所有含“征求意见稿征求意见的通知”的链接和标题,形成待爬取列表。
resp = requests.get(LIST_URL, headers=HEADERS)
soup = BeautifulSoup(resp.text, "html.parser")
# 筛选符合条件的a标签,得到title和详情链接
2. Selenium渲染详情页
详情页的文件链接由JS动态生成,直接用requests无法拿到。使用Selenium模拟浏览器打开详情页:
- 启动无头Chrome浏览器
- 加载详情页URL
- 等待若干秒让JS执行完成
- 获取渲染后的完整HTML
driver.get(detail_url)
time.sleep(5) # 等待JS渲染
html = driver.page_source
3. 解析文件下载链接
用BeautifulSoup
解析渲染后的HTML,提取所有.doc
, .docx
, .pdf
文件链接和文件名,筛选出“标准文本”相关的文件。
for a in soup.find_all("a", href=True):if a['href'].endswith(('.doc', '.docx', '.pdf')) and "标准文本" in a.text:# 记录文件名和下载链接
4. 文件命名规范处理
从通知的完整标题中,用正则提取标准名(《》内内容)和“征求意见稿”关键字,生成规范文件名,避免文件名非法字符。
def simplify_title(full_title):match = re.search(r'《([^》]+)》', full_title)if match:name = f"《{match.group(1)}》征求意见稿"else:name = full_titlereturn re.sub(r'[\\/*?:"<>|]', "_", name)
5. 下载文件与日志记录
- 利用requests下载文件,保存到指定目录。
- 统一打印日志并写入日志文件,方便追踪。
- 每下载完一个文件,等待5秒,减小服务器压力。
四、完整代码和效果展示
import os
import time
import re
import requests
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManagerBASE_URL = "这里写地址"
LIST_URL = "这里写地址"HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
}LOG_FILE = os.path.join("downloads", "download_log.txt")def log_print(msg):print(msg)with open(LOG_FILE, "a", encoding="utf-8") as f:f.write(msg + "\n")def sanitize_filename(name):return re.sub(r'[\\/*?:"<>|]', "_", name)def simplify_title(full_title):match = re.search(r'《([^》]+)》', full_title)if not match:return sanitize_filename(full_title)standard_name = f"《{match.group(1)}》"if "征求意见稿" in full_title:return standard_name + "征求意见稿"else:return standard_namedef get_list_page():resp = requests.get(LIST_URL, headers=HEADERS)resp.raise_for_status()return resp.textdef parse_list_page(html):soup = BeautifulSoup(html, "html.parser")notices = []for a in soup.find_all("a", href=True):text = a.get_text(strip=True)href = a['href']if "征求意见稿征求意见的通知" in text and href.startswith("/front/bzzqyjDetail.html"):notices.append({"title": text,"detail_url": BASE_URL + href})return noticesdef fetch_detail_page_selenium(url):options = webdriver.ChromeOptions()options.add_argument('--headless')options.add_argument('--no-sandbox')options.add_argument('--disable-gpu')driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)try:driver.get(url)time.sleep(5)html = driver.page_sourcefinally:driver.quit()return htmldef parse_detail_files(html):soup = BeautifulSoup(html, "html.parser")files = []for a in soup.find_all("a", href=True):href = a['href']if href.endswith((".doc", ".docx", ".pdf")):file_name = a.get_text(strip=True)file_url = href if href.startswith("http") else BASE_URL + hreffiles.append((file_name, file_url))return filesdef download_file(url, filename):log_print(f"下载文件: {filename} 链接: {url}")resp = requests.get(url, headers=HEADERS)resp.raise_for_status()with open(filename, "wb") as f:f.write(resp.content)log_print(f"下载完成: {filename}")def main():os.makedirs("downloads", exist_ok=True)with open(LOG_FILE, "w", encoding="utf-8") as f:f.write("下载日志\n\n")list_html = get_list_page()notices = parse_list_page(list_html)log_print(f"共找到{len(notices)}条通知")for notice in notices:log_print(f"处理通知:{notice['title']}")detail_html = fetch_detail_page_selenium(notice['detail_url'])files = parse_detail_files(detail_html)std_files = [f for f in files if "标准文本" in f[0]]if not std_files:log_print("未找到标准文本文件,跳过")continuefor file_name, file_url in std_files:simple_name = simplify_title(notice['title'])ext = os.path.splitext(file_url)[1]safe_name = sanitize_filename(simple_name) + extsave_path = os.path.join("downloads", safe_name)try:download_file(file_url, save_path)time.sleep(5)except Exception as e:log_print(f"下载失败: {file_name},错误: {e}")if __name__ == "__main__":main()
最终运行即可实现如下效果
相关文章:
爬虫技术-利用Python和Selenium批量下载动态渲染网页中的标准文本文件
近日工作需要整理信息安全的各项标准文件,这些文件通常发布在在官方网站,供社会各界下载和参考。 这些页面中,标准文本文件常以Word(.doc/.docx)或PDF格式提供下载。由于文件数量庞大,手动逐条点击下载效率…...
CUDA编程 - 如何在 GPU 上使用 C++ 函数重载 - cppOverload
这里写目录标题 一、完整代码与例程目的二、代码拆解与复用 2.1、函数重载: 2.2、函数指针声明: 2.3、函数指针赋值与内核启动: 2.4、CUDA API调用:2.4.1、cudaFuncSetCacheConfig:2.4.2、cud…...
AI教你学VUE——Gemini版
前端开发学习路线图 (针对编程新手,主攻 Vue 框架) 总原则:先夯实基础,再深入框架。 想象一下建房子,地基不牢,上面的高楼(框架)是盖不起来的。HTML、CSS、JavaScript 就是前端的地基。 阶段一…...
力扣热题100,力扣49.字母异位词分组力扣128.最长连续序列力扣.盛水最多的容器力扣42.接雨水(单调栈)
目录 力扣49.字母异位词分组 力扣128.最长连续序列 力扣.盛水最多的容器 力扣42.接雨水(单调栈) 1.包的命名规范: java的命名规范 全部采用小写 结尾不能加负数 声明包: 位置必须在首行 类: 字母数字下划线,美元符号 不能数字开头 不能有中文 不能以关键字命名 区…...
react naive 网络框架源码解析
本文取 react native 两个区别很大的版本做分析(0.76.5、0.53.3) 一、0.76.5 版fetch 全流程排查 1、JS 端的实现 随手写一个fetch,点开。 我们这里常用的还是手机端,因此选择 react-native,react-native-windows …...
DID在元宇宙的应用爆发:数字身份资产化与跨平台迁移——解析Decentraland等项目的虚拟身份全链路实现
元宇宙的兴起催生了多维度的数字身份需求,但传统虚拟身份系统受限于中心化架构,面临数据孤岛、身份碎片化、资产归属模糊等核心挑战。本文以Decentraland、The Sandbox、Somnium Space等顶级元宇宙平台为研究对象,探讨去中心化身份࿰…...
MySQL的内置函数与复杂查询
目录 前言 一、聚合函数 1.1日期函数 1.2字符串函数 1.3数学函数 1.4其它函数 二、关键字周边 2.1关键字的生效顺序 2.2数据源 2.3可以使用聚合函数的关键字 前言 在前面几篇文章中,讲解了有关MySQL数据库、数据库表的创建、数据库表的数据操作等等。本文我…...
mysql中select 1 from的作用
在MySQL中,SELECT 1 FROM ... 是一个常见的SQL写法,通常用于以下场景: 1. 作用与原理 SELECT 1 的本质是返回一个常数值(即数字1),且不依赖表中的实际数据。 它的核心作用是快速验证逻辑条件是否成立&…...
Linux中 du (详解)、 df (详解)和 free(详解)以及它们的区别
目录 du命令 df命令 free命令 du/df/free区别 Tree du命令 功能:用于计算文件或目录所占用的磁盘空间大小。它会递归地遍历指定目录下的所有文件和子目录,统计它们占用的磁盘块数,从而得出占用的空间大小。常用选项: -h&…...
ETL交通行业案例丨某大型铁路运输集团ETL数据集成实践
在广袤的祖国边疆,一条条钢铁动脉承载着区域经济发展的重要使命。某大型铁路运输集团作为区域交通枢纽的运营主体,管辖着横跨多个省、区的铁路网络,运营里程超3000公里,每日承载着数以万计的客货运输任务。随着"数字中国&quo…...
【数据挖掘】Apriori算法
Apriori算法是经典的关联规则挖掘算法,用于从事务型数据库中发现频繁项集和强关联规则,特别常用于购物篮分析等场景。 🧠 核心思想(Apriori原则) 一个项集是频繁的,前提是它的所有子集也必须是频繁的。 即&…...
7.9/Q1,Charls最新文章解读
文章题目:Association between urbanization levels and frailty among middle-aged and older adults in China: evidence from the CHARLS DOI:10.1186/s12916-025-03961-y 中文标题:中国中老年人城市化水平与虚弱程度之间的关联࿱…...
从入门到登峰-嵌入式Tracker定位算法全景之旅 Part 7 |TinyML 定位:深度模型在 MCU 上的部署
Part 7 |TinyML 定位:深度模型在 MCU 上的部署 本章聚焦如何在 ESP32-S3 平台上,通过 TinyML 将深度学习模型应用到定位场景,包括特征提取、模型剪枝与量化、TensorFlow Lite for Microcontrollers 部署,以及在线微调与自适应策略。 一、为什么要用 TinyML? 非线性特征挖…...
Codeforces Round 1023 (Div. 2) ABC
链接 Dashboard - Codeforces Round 1023 (Div. 2) - Codeforces A 将数组a分成两组,使得gcd(b) ! gcd(c) 思路 gcd(a,b) < min(a,b) 求数组a的max,min 如果数组a都一样无解 (即max min 否则有解:让是max的一组&…...
56. 合并区间
给定若干个区间的集合,将重叠的区间合并后,放入一个数组中返回。 具体思路就是按左端点排序后合并区间,因为按左端点排序后,可以确保每次合并都是以最小元素为合并后区间的起始,并且按左端点排序可以方便合并ÿ…...
Docker安装使用
1.Docker简介 Docker是一个开源的应用容器引擎;是一个轻量级容器技术; Docker支持将软件编译成一个镜像;然后在镜像中各种软件做好配置,将镜像发布出去,其他使用者可以直接使用这个镜像; 运行中的这个镜…...
Linux/AndroidOS中进程间的通信线程间的同步 - POSIX IPC
1 什么是POSIX? POSIX(Portable Operating System Interface)即可移植操作系统接口,它是IEEE为要在各种UNIX操作系统上运行软件,而定义API的一系列标准的总称。以下为你展开介绍: 产生背景:在…...
5.2创新架构
一、MoE(Mixture of Experts,混合专家模型) 了解混合专家模型架构,与 Dense 架构相比有什么优劣 是一种提升大模型推理效率和参数利用率的关键技术 核心思想:在模型中增加多个“专家模块”(Experts&#x…...
驱动开发系列57 - Linux Graphics QXL显卡驱动代码分析(四)显示区域更新
一:概述 前面在介绍了显示模式设置(分辨率,刷新率)之后,本文继续分析下,显示区域的绘制,详细看看虚拟机的画面是如何由QXL显卡绘制出来的。 二:相关数据结构介绍 struct qxl_moni…...
疗愈服务预约小程序源码介绍
基于ThinkPHP、FastAdmin和UniApp开发的疗愈服务预约小程序源码,这款小程序在功能设计和用户体验上都表现出色,为疗愈行业提供了一种全新的服务模式。 该小程序源码采用了ThinkPHP作为后端框架,保证了系统的稳定性和高效性。同时,…...
力扣118,1920题解
记录 2525.5.6 题目: 思路: 用一个二维数组dp[numRows][numRows]保存每一次动态规划的结果 1.令dp[0][0]1(第一列) 2.找规律 3.得到如下规律(以下情况均为列数大于1) if(col0){ dp[row][col]1 } else { dp[row][col]dp[row-1][col-1]dp[row-1][col] }…...
电池热管理CFD解决方案,为新能源汽车筑安全防线
在全球能源结构加速转型的大背景下,新能源汽车产业异军突起,成为可持续发展的重要驱动力。而作为新能源汽车 “心脏” 的电池系统,其热管理技术的优劣,直接决定了车辆的安全性、续航里程和使用寿命。电池在充放电过程中会产生大量…...
(一)毛子整洁架构(Domain Layer/Repository Pattern/Result Pattern/Error Pattern)
文章目录 项目地址一、整洁架构概念1.1 各个分层的功能1. Domain核心部件2. Application Layer3. Infrastructure layer3. Presenetation layer1.2 项目数据库二、Domain Layer2.1 Apartments 实体1. Current Value Obj2. Money Value Obj3. Apartment 类2.2 User 实体1. User类…...
XSS ..
Web安全中的XSS攻击详细教学,Xss-Labs靶场通关全教程(建议收藏) - 白小雨 - 博客园跨站脚本攻击(XSS)主要是攻击者通过注入恶意脚本到网页中,当用户访问该页面时,恶意脚本会在用户的浏览器中执行…...
Github Action部署node项目
Github Action部署node项目 个人学习的时候,作为前端感觉这个CICD基本流程还是有必要了解的,这里记录一下Github Action部署node项目的流程,也算是一个学习的过程 首先肯定是要有一个可运行的node项目 编写部署文件 部署文件放置在.githu…...
高频面试题:设计秒杀系统,用Redis+Lua解决超卖
高频面试题:设计秒杀系统,用RedisLua解决超卖 **1. 问题背景****2. 解决方案:Redis Lua****为什么选择Redis Lua?****核心代码逻辑****Java调用示例(Spring Boot)** **3. 方案优势****4. 面试回答话术***…...
2、Kafka Replica机制与ISR、HW、LEO、AR、OSR详解
Kafka 作为分布式高可用消息队列,其副本(Replica)机制是实现高可靠性和数据一致性的核心。本文将系统介绍 Kafka 的 Replica 机制,并详细解释 ISR、HW、LEO、AR、OSR 等关键概念。 一、Kafka Replica机制概述 在分布式系统中&am…...
生成式 AI:从工具革命到智能体觉醒,2025 年的质变与突破
在上海胸科医院的手术室里,一束全息投影正精准勾勒出患者肺部的三维血管模型。主刀医生手持机械臂的瞬间,AI 导航系统已同步完成 200 次路径演算,将毫米级误差控制在 0.3 毫米以内 —— 这个真实发生在 2025 年的临床场景,标志着生…...
安卓基础(拖拽)
当用户长按或拖拽某个视图(如按钮、图片)时,需要提供视觉反馈(即阴影)。这行代码通常在拖拽事件的处理逻辑中,例如: view.setOnLongClickListener(v -> {// 创建拖拽阴影DragShadowBuilder …...
IoTDB磁盘I/O性能监控与优化指南
一、磁盘I/O性能观测核心指标 在现代计算机系统中,磁盘I/O性能对整体系统表现至关重要。为有效监控和优化磁盘I/O性能,需关注以下核心指标: I/O读写延迟:衡量从发起I/O请求到接收响应的时间间隔。IOPS(Input/O…...
java每日精进 5.06【框架之功能权限】
0.概述 0.1 整体架构概述 这个RBAC权限系统基于Spring Security和Token认证机制,主要包含以下核心组件: 用户-角色-菜单的多对多关系模型 基于Token的认证流程 细粒度的权限控制(菜单权限、按钮权限) 灵活的权限配置方式 1…...
静态NAT
实验需求 PC1和PC2通过静态NAT去访问服务器 实验拓扑 图13-1 静态NAT 实验步骤 步骤1:IP地址的配置 PC1的配置 PC2的配置 R1的配置 <Huawei>system-view [Huawei]undo info-center enable [Huawei]sysname R1 [R1]interface g0/0/0 [R1-GigabitEt…...
RabbitMQ-api开发
前言 MQ就是接收并转发消息 核心概念 admin是用户 每个虚拟机上都有多个交换机 快速入门 引入依赖 <dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.22.0</version></dependen…...
const MachineTree getMachineTree() ; MachineTree getMachineTree() const; 区别?
这两个函数声明在语法和语义上有明显的区别,它们的用途和行为也不同。让我们逐一分析它们的区别: 1. const MachineTree &getMachineTree(); 这个函数声明表示: 返回类型:const MachineTree &,即返回一个 M…...
使用DevTools工具调试前端页面,便捷脚本,鸿蒙调试webView
参考官方文章 便捷脚本 创建文本,复制修改后缀为bat 建立bat文件 echo off setlocal enabledelayedexpansion:: Initialize port number and PID list set PORT9222 set PID_LIST:: Get the list of all forwarded ports and PIDs for /f "tokens2,5 delims…...
浏览器存储 Cookie,Local Storage和Session Storage
什么是Cookie? 存储容量:一般限制在 4KB 以内。数据有效期:可以设置过期时间,若未设置,则在浏览器关闭时失效。数据共享:在同一域名下,不同页面可以共享cookie数据。并且在每次 HTTP 请求时&am…...
校内周赛题(思维题)
这次周赛的题目没有什么很难的代码实现,基本上都是对思路的把握。 与君共勉🌹 选取x个数,看能不能使得这x个数相加的结果是奇数。 如果x是偶数,他的分布肯定是一个奇数一个偶数若干个两两配对的奇数若干个两两配对的偶数。 如果…...
在 GitLab 中部署Python定时任务
在 GitLab 中部署定时任务(如每天早8点运行Python脚本并存储结果)可以通过 GitLab CI/CD 结合 计划任务(Scheduled Pipelines) 实现。以下是详细步骤和准备工作: 1. 准备工作 (1) 项目结构准备 确保项目包含: Python脚本(如 main.py):执行核心算法逻辑。 结果存储模…...
学习黑客Windows权限体系
已思考 24 秒 借着 Week 2 Day 4 的号角,我们把权限系统这条「双持长枪」摆上擂台:一边是 Windows DACL/icacls,另一边是 Linux sudoers。你将看到二者在授权语法、常见配置漏洞与提权打法上的一一对照——尤其关注 可写服务(Wr…...
DXFViewer进行中2 -> 直线 解析+渲染 ✅已完成
DXFViewer进行中 : ->封装OpenGL -> 解析DXF直线-CSDN博客https://blog.csdn.net/qq_25547755/article/details/147723906 上篇博文 解析dxf直线635条 1. DXFViewer.h #pragma once #include "Application.h" #include <stdio.h> #inc…...
当智能科技遇上医疗行业会帮助疫苗如何方便管理呢?
随着科技的发展,智能科技在医疗行业的应用日益广泛,在疫苗管理方面,温湿度监控设备的安装可以简化管理流程,提高监测效率,降低疫苗损坏的风险。 疫苗管理面临着诸多挑战和需求。疫苗的存储、运输、接种等环节都…...
Excel 数据 可视化 + 自动化!Excel 对比软件
各位Excel小能手们!你们有没有过要对比两个Excel表格数据差异,却看得眼睛都花了的经历?其实啊,现在有专门的Excel文件比较软件能帮咱解决这大难题。这软件就是用来快速找出两个或多个Excel表格数据不同之处,还能把修改…...
Selenium模拟人类行为,操作网页的方法(全)
看到有朋友评论问,用selenium怎么模仿人类行为,去操作网页的页面呢? 我想了想,这确实是一个很大的点,不应该是一段代码能解决的, 就像是,如果让程序模拟人类的行为。例如模拟人类买菜,做饭&am…...
LVS负载均衡群集解析:理解LVS-NAT的工作原理
目录 一、LVS群集应用基础 1.群集技术概述 2.LVS虚拟服务器 3.NFS共享存储服务 二、案例:地址转换模式(LVS-NAT) 1.资源清单 2.修改主机名 3.配置负载调度器(LVS上) 4.配置节点服务器(web1、web2) 5.测试LVS…...
Leetcode Hot 100最长连续序列
题目描述 思路 思路1 我们对数组进行排序,通过遍历数组,如果前一个数组的值1等于当前数组的值,计数count,如果中断了,计算当前最大连续长度的值ans,并且统计值count重新置为1,最后返回count与…...
【东枫科技】代理英伟达产品:交换机系统
文章目录 总体详细:NVIDIA Spectrum SN5000详细:NVIDIA Spectrum SN2100详细:NVIDIA Spectrum SN4700详细:NVIDIA Spectrum SN2010详细:NVIDIA Spectrum SN4600详细:NVIDIA Spectrum SN3700详细:…...
[前端]Javascript获取元素宽度
元素宽度属性对比示意图 ---------------------------------- | 外边距(margin) | -------------------------------- | | 边框(border) | | | -------------------------- | | | …...
MySQL + Qwen3-0.5B + Flask + Dify 工作流部署指南
1. 安装MySQL和PyMySQL 安装MySQL # 在Ubuntu/Debian上安装 sudo apt update sudo apt install mysql-server sudo mysql_secure_installation# 启动MySQL服务 sudo systemctl start mysql sudo systemctl enable mysql 安装PyMySQL pip install pymysql 使用 apt 安装 My…...
项目三 - 任务3:学生多态方式喂养宠物
在本次实战中,我们通过创建动物类及其子类(猫、狗、鸟),并设计学生类的喂养方法,深入学习了Java中的多态和方法重载。学生类通过重载方式为每种动物提供专门的喂养方法,而通过多态方式则仅用一个方法即可喂…...
TypeScript速成
1、类型推断 这里的str已经推断为string类型,不能像JavaScript一样直接给str赋值number类型 2、类型注解 let str:stringabc 或者 let str:string strabc 3、类型断言 因为typescript会判定这个item可能为undefined类型,但是我们人为可以确定item一…...