爬取CECS网站征求意见栏目的最新信息

#!/usr/bin/env python3

-- coding: utf-8 --

"""

CECS标准征求意见栏目数据提取工具

功能:从CECS标准征求意见栏目获取数据并保存为CSV格式

"""

导入所需库

try:

import requests

import pandas as pd

from bs4 import BeautifulSoup

import re

import time

import os

from datetime import datetime

复制代码
# 标记库是否可用
libraries_available = {
    'requests': True,
    'pandas': True,
    'BeautifulSoup': True
}

except ImportError as e:

print(f"警告: 缺少必要的库。请安装以下库:\n{'-' * 50}\npip install requests pandas beautifulsoup4\n{'-' * 50}")

复制代码
# 根据导入错误标记缺失的库
libraries_available = {
    'requests': 'requests' not in str(e),
    'pandas': 'pandas' not in str(e),
    'BeautifulSoup': 'bs4' not in str(e)
}

def get_cecs_zqyj_content(url="http://www.cecs.org.cn/xhbz/zqyj/index.html", max_retries=3, timeout=30):

"""

使用requests获取CECS标准征求意见栏目的页面内容,支持重试机制

复制代码
Args:
    url: CECS标准征求意见栏目的URL
    max_retries: 最大重试次数
    timeout: 每次请求的超时时间(秒)

Returns:
    str: 页面的HTML内容,如果获取失败则返回None
"""
if not libraries_available['requests']:
    print("错误: requests库未安装,无法获取网页内容。")
    return None

# 设置请求头模拟浏览器访问
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Connection': 'keep-alive',
    'Upgrade-Insecure-Requests': '1'
}

# 重试机制
for attempt in range(1, max_retries + 1):
    try:
        # 发送请求
        print(f"正在获取CECS标准征求意见栏目的内容 (尝试 {attempt}/{max_retries})...")
        response = requests.get(url, headers=headers, timeout=timeout)

        # 检查响应状态
        if response.status_code == 200:
            # 网页编码设置为UTF-8
            response.encoding = 'utf-8'
            print(f"成功获取页面内容,状态码: {response.status_code}")
            return response.text
        else:
            print(f"获取页面失败,状态码: {response.status_code}")
            if attempt < max_retries:
                print(f"{attempt}秒后重试...")
                time.sleep(attempt)  # 指数退避策略
                continue
            else:
                return None

    except requests.RequestException as e:
        print(f"请求出错: {str(e)}")
        if attempt < max_retries:
            print(f"{attempt}秒后重试...")
            time.sleep(attempt)  # 指数退避策略
            continue
        else:
            return None

def save_to_csv(data, output_dir="."):

"""

使用pandas将提取的标准征求意见信息保存为CSV格式文件

复制代码
Args:
    data: 包含标准征求意见信息的字典列表
    output_dir: 输出文件的目录,默认为当前目录

Returns:
    str: 保存的CSV文件路径,如果保存失败则返回None
"""
if not libraries_available['pandas']:
    print("错误: pandas库未安装,无法保存为CSV文件。")
    return None

if not data:
    print("警告: 没有数据可保存")
    return None

try:
    # 创建pandas DataFrame
    df = pd.DataFrame(data)

    # 确保输出目录存在
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # 生成带有时间戳的文件名
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = f"cecs_zqyj_standards_{timestamp}.csv"
    filepath = os.path.join(output_dir, filename)

    # 保存为CSV文件,使用UTF-8-SIG编码以支持中文
    df.to_csv(filepath, index=False, encoding='utf-8-sig')

    print(f"成功将 {len(data)} 条标准征求意见信息保存到CSV文件:")
    print(f"文件路径: {filepath}")
    return filepath

except Exception as e:
    print(f"保存CSV文件时出错: {str(e)}")
    return None

def extract_zqyj_info(html_content):

"""

使用BeautifulSoup解析HTML,提取CECS标准征求意见信息

复制代码
Args:
    html_content: 页面的HTML内容

Returns:
    list: 包含标准征求意见信息的字典列表
"""
if not libraries_available['BeautifulSoup']:
    print("错误: BeautifulSoup库未安装,无法解析HTML。")
    return []

try:
    # 创建BeautifulSoup对象
    soup = BeautifulSoup(html_content, 'html.parser')

    # 存储提取的标准征求意见信息
    standards_info = []

    # 增强的日期提取正则表达式,专门针对2025-12-07这样的格式
    date_pattern = re.compile(r'\d{4}[-/]\d{1,2}[-/]\d{1,2}', re.IGNORECASE)

    # 1. 首先从整个页面中提取所有的日期信息,保存它们的位置
    all_dates = date_pattern.finditer(html_content)
    date_positions = [(match.start(), match.group(0)) for match in all_dates]
    print(f"找到 {len(date_positions)} 个日期格式的文本")

    # 2. 尝试通过不同的方式查找标准征求意见信息
    # 查找所有可能包含标准信息的列表项或div
    items = []

    # 查找常见的内容列表容器
    content_containers = soup.find_all(['ul', 'ol', 'div'],
                                       class_=re.compile(r'list|content|article|news|items', re.I))

    for container in content_containers:
        # 在每个容器中查找可能的条目
        potential_items = container.find_all(['li', 'div', 'tr'],
                                             class_=re.compile(r'item|content|article|news|entry', re.I))
        items.extend(potential_items)

    # 如果没有找到特定的条目容器,尝试获取页面中所有的链接
    if not items:
        links = soup.find_all('a')
        items = links

    print(f"找到 {len(items)} 个可能包含标准信息的元素")

    # 遍历所有找到的项目,提取标准信息
    for i, item in enumerate(items):
        # 尝试获取文本内容
        text = item.get_text(strip=True)

        # 尝试获取链接
        link = None
        if item.name == 'a':
            link = item.get('href', '')
        else:
            a_tag = item.find('a')
            if a_tag:
                link = a_tag.get('href', '')

        # 处理链接,确保是完整的URL
        base_url = "http://www.cecs.org.cn"
        if link:
            # 如果链接是相对路径,添加基础URL
            if not link.startswith('http'):
                # 确保路径正确拼接
                if link.startswith('/'):
                    full_link = base_url + link
                else:
                    # 假设这是相对于xhbz/zqyj目录的链接
                    full_link = base_url + "/xhbz/zqyj/" + link
            else:
                full_link = link
        else:
            full_link = ''

        # 查找此元素在HTML中的位置
        item_position = -1
        if link:
            # 如果有链接,尝试通过链接定位元素位置
            item_position = html_content.find(f'href="{link}"')
            if item_position == -1:
                item_position = html_content.find(f"href='{link}'")

        if item_position == -1 and text:
            # 如果没有链接或无法通过链接定位,尝试通过文本定位
            # 只使用文本的前30个字符进行匹配
            search_text = text[:30]
            item_position = html_content.find(search_text)

        # 尝试从文本中直接提取日期信息
        date_match = date_pattern.search(text)
        date = date_match.group(0) if date_match else ''

        # 如果文本中没有日期,但我们有元素位置,尝试查找附近的日期
        if not date and item_position != -1 and date_positions:
            # 找到离元素最近的日期
            nearest_date = None
            min_distance = float('inf')

            for pos, date_str in date_positions:
                distance = abs(pos - item_position)
                if distance < min_distance:
                    min_distance = distance
                    nearest_date = date_str

            # 如果找到的日期足够近(500个字符内),就使用它
            if nearest_date and min_distance < 500:
                date = nearest_date

        # 如果文本内容不为空,则添加到结果列表
        if text and len(text) > 5:
            # 构建标准信息字典
            standard_info = {
                '序号': i + 1,
                '标题': text,
                '链接': full_link,
                '日期': date
            }
            standards_info.append(standard_info)

    # 3. 专门查找页面中所有包含日期的文本元素
    date_elements = soup.find_all(string=date_pattern)
    for date_text in date_elements:
        # 提取日期
        date_match = date_pattern.search(date_text)
        date = date_match.group(0) if date_match else ''

        # 获取包含这个日期的元素
        parent_element = date_text.parent

        # 检查这个日期是否已经在我们的结果中
        date_exists = False
        for std in standards_info:
            if std['日期'] == date:
                # 检查这个条目是否包含这个元素的文本
                if parent_element.get_text(strip=True) in std['标题']:
                    date_exists = True
                    break

        # 如果日期不在结果中,为它创建一个条目
        if not date_exists and date:
            # 获取链接并确保完整性
            element_link = parent_element.get('href', '') if parent_element.name == 'a' else ''

            # 处理链接,确保是完整的URL
            base_url = "http://www.cecs.org.cn"
            if element_link:
                if not element_link.startswith('http'):
                    if element_link.startswith('/'):
                        full_element_link = base_url + element_link
                    else:
                        full_element_link = base_url + "/xhbz/zqyj/" + element_link
                else:
                    full_element_link = element_link
            else:
                full_element_link = ''

            standards_info.append({
                '序号': len(standards_info) + 1,
                '标题': parent_element.get_text(strip=True) or f'日期条目: {date}',
                '链接': full_element_link,
                '日期': date
            })

    # 4. 如果没有找到任何信息,尝试直接提取页面中的文本段落
    if not standards_info:
        paragraphs = soup.find_all('p')
        for i, p in enumerate(paragraphs):
            text = p.get_text(strip=True)

            # 尝试从文本中提取日期信息
            date_match = date_pattern.search(text)
            date = date_match.group(0) if date_match else ''

            if text and len(text) > 5:
                standard_info = {
                    '序号': i + 1,
                    '标题': text,
                    '链接': '',
                    '日期': date
                }
                standards_info.append(standard_info)

    # 去重
    seen_titles = set()
    unique_standards = []

    for std in standards_info:
        title = std['标题']
        if title not in seen_titles:
            seen_titles.add(title)
            unique_standards.append(std)

    # 重新排序,让有日期的条目优先显示
    unique_standards.sort(key=lambda x: 0 if x['日期'] else 1)

    # 重新编号
    for i, std in enumerate(unique_standards):
        std['序号'] = i + 1

    standards_info = unique_standards

    # 统计有日期的条目
    dated_entries = sum(1 for std in standards_info if std['日期'])
    print(f"成功提取 {len(standards_info)} 条唯一的标准征求意见信息,其中 {dated_entries} 条包含日期")
    return standards_info

except Exception as e:
    print(f"解析HTML出错: {str(e)}")
    return []

def main():

"""

主函数

"""

检查必要的库是否可用

if not all(libraries_available.values()):

missing_libraries = [lib for lib, available in libraries_available.items() if not available]

print(f"错误: 缺少以下必要的库: {', '.join(missing_libraries)}")

print("请先安装必要的库后再运行程序。")

return

复制代码
# 获取CECS标准征求意见栏目的内容
html_content = get_cecs_zqyj_content()

if html_content:
    print(f"成功获取CECS标准征求意见栏目的内容,长度: {len(html_content)} 字符")

    # 提取标准征求意见信息
    standards_info = extract_zqyj_info(html_content)

    if standards_info:
        print(f"成功提取 {len(standards_info)} 条标准征求意见信息")

        # 保存为CSV文件
        csv_file = save_to_csv(standards_info)

        if csv_file:
            print(f"数据已成功保存到CSV文件: {csv_file}")
            # 显示保存的数据预览
            print("\n数据预览:")
            df_preview = pd.DataFrame(standards_info)
            print(df_preview.head(10).to_string(index=False))
        else:
            print("保存CSV文件失败")
    else:
        print("未能提取到标准征求意见信息")
else:
    print("无法获取CECS标准征求意见栏目的内容")

if name == "main ":

main()

相关推荐
占疏3 小时前
dify API访问工作流/聊天
开发语言·数据库·python
aningxiaoxixi4 小时前
TTS 之 PYTHON库 pyttsx3
开发语言·python·语音识别
深蓝海拓4 小时前
PySide6从0开始学习的笔记(三) 布局管理器与尺寸策略
笔记·python·qt·学习·pyqt
数据科学项目实践4 小时前
建模步骤 3 :数据探索(EDA) — 1、初步了解数据:常用函数
人工智能·python·机器学习·数据挖掘·数据分析·pandas·数据可视化
Chen--Xing4 小时前
2025鹏城杯 -- Crypto -- RandomAudit详解
python·密码学·ctf·鹏城杯
一瞬祈望5 小时前
PyTorch 图像分类完整项目模板实战
人工智能·pytorch·python·深度学习·分类
坐吃山猪5 小时前
BrowserUse12-源码-MCP模块
python·llm·playwright·browser-use
昔时扬尘处5 小时前
【Files Content Replace】文件夹文件内容批量替换自动化测试脚本
c语言·python·pytest·adi
咖啡の猫5 小时前
Python字典的查询操作
数据库·python·c#