Python爬虫技术:招标信息抓取与关键词过滤 (1)

一、技术架构概述

招标信息抓取系统主要包含三个核心模块:

  1. 网络请求模块:负责向目标网站发送HTTP请求并获取网页内容
  2. 数据解析模块:从网页HTML中提取结构化招标信息
  3. 关键词过滤模块:根据预设关键词对招标信息进行筛选

二、实现步骤详解

1. 环境准备

首先安装必要的Python库:

  • requests:用于发送HTTP请求
  • beautifulsoup4:用于解析HTML文档
  • pandas:用于数据处理和存储
2. 网页内容获取

使用requests库向目标招标网站发送GET请求,获取网页HTML内容:

plain 复制代码
import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import re

class BidInfoSpider:
    def __init__(self):
        self.session = requests.Session()
        # 设置请求头,模拟浏览器行为
        self.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'
        }
        self.session.headers.update(self.headers)
    
    def get_page_content(self, url, params=None):
        """
        获取网页内容
        :param url: 目标URL
        :param params: 请求参数
        :return: 网页HTML内容
        """
        try:
            response = self.session.get(url, params=params, timeout=10)
            response.encoding = 'utf-8'
            if response.status_code == 200:
                return response.text
            else:
                print(f"请求失败,状态码:{response.status_code}")
                return None
        except Exception as e:
            print(f"请求异常:{str(e)}")
            return None
3. 数据解析与提取

使用BeautifulSoup解析HTML,提取招标信息的关键字段:

plain 复制代码
def parse_bid_info(self, html):
        """
        解析招标信息
        :param html: 网页HTML内容
        :return: 招标信息列表
        """
        if not html:
            return []
        
        soup = BeautifulSoup(html, 'lxml')
        bid_list = []
        
        # 根据实际网站结构调整选择器
        # 这里以常见的招标信息列表结构为例
        items = soup.select('.bid-item, .tender-item, .zbxx-item')
        
        for item in items:
            try:
                bid_info = {}
                
                # 提取标题
                title_elem = item.select_one('.title, .tit, a')
                bid_info['title'] = title_elem.get_text().strip() if title_elem else ''
                
                # 提取链接
                if title_elem and title_elem.get('href'):
                    link = title_elem['href']
                    if not link.startswith('http'):
                        # 处理相对链接
                        base_url = 'http://www.example.com'  # 替换为实际基础URL
                        link = base_url + link
                    bid_info['link'] = link
                else:
                    bid_info['link'] = ''
                
                # 提取发布时间
                time_elem = item.select_one('.time, .date, .publish-time')
                bid_info['publish_time'] = time_elem.get_text().strip() if time_elem else ''
                
                # 提取招标方
                owner_elem = item.select_one('.owner, .tenderer, .zbunit')
                bid_info['owner'] = owner_elem.get_text().strip() if owner_elem else ''
                
                # 提取项目预算(如果有)
                budget_elem = item.select_one('.budget, .amount, .money')
                bid_info['budget'] = budget_elem.get_text().strip() if budget_elem else ''
                
                if bid_info['title']:  # 只有包含标题的信息才保存
                    bid_list.append(bid_info)
                    
            except Exception as e:
                print(f"解析招标信息异常:{str(e)}")
                continue
        
        return bid_list
4. 关键词过滤系统

实现基于关键词的智能过滤机制:

plain 复制代码
class KeywordFilter:
    def __init__(self):
        # 定义关键词分类
        self.keyword_categories = {
            'industry': ['IT', '软件', '系统集成', '信息化', '智能化', '网络', '数据中心'],
            'technology': ['Python', 'Java', '云计算', '大数据', '人工智能', '物联网', '区块链'],
            'project_type': ['开发', '实施', '运维', '咨询', '设计', '培训'],
            'exclude': ['废标', '终止', '流标', '更正']  # 排除关键词
        }
        
        # 构建正则表达式模式
        self.patterns = {}
        for category, keywords in self.keyword_categories.items():
            # 将关键词用|连接,创建正则表达式
            pattern = '|'.join(keywords)
            self.patterns[category] = re.compile(pattern)
    
    def filter_by_keywords(self, bid_info, min_matches=2):
        """
        根据关键词过滤招标信息
        :param bid_info: 招标信息字典
        :param min_matches: 最小匹配关键词数量
        :return: 是否通过过滤
        """
        title = bid_info.get('title', '')
        content = bid_info.get('content', '')  # 如果有详细内容
        
        # 排除包含排除关键词的信息
        exclude_pattern = self.patterns['exclude']
        if exclude_pattern.search(title) or exclude_pattern.search(content):
            return False
        
        # 计算匹配的关键词数量
        match_count = 0
        for category in ['industry', 'technology', 'project_type']:
            pattern = self.patterns[category]
            if pattern.search(title) or pattern.search(content):
                match_count += 1
        
        return match_count >= min_matches
    
    def get_matched_keywords(self, text):
        """
        获取文本中匹配的关键词
        :param text: 待匹配文本
        :return: 匹配的关键词列表
        """
        matched_keywords = []
        for category in ['industry', 'technology', 'project_type']:
            pattern = self.patterns[category]
            matches = pattern.findall(text)
            matched_keywords.extend(matches)
        
        return list(set(matched_keywords))  # 去重
5. 完整爬虫实现

整合各模块,实现完整的招标信息抓取流程:

plain 复制代码
class BidInformationCrawler:
    def __init__(self):
        self.spider = BidInfoSpider()
        self.filter = KeywordFilter()
        self.all_bid_info = []
    
    def crawl_multiple_pages(self, base_url, pages=5):
        """
        爬取多页招标信息
        :param base_url: 基础URL
        :param pages: 爬取页数
        """
        print("开始爬取招标信息...")
        
        for page in range(1, pages + 1):
            print(f"正在爬取第 {page} 页...")
            
            # 构造每页的URL参数(根据实际网站调整)
            params = {
                'page': page,
                'size': 20  # 每页显示数量
            }
            
            html = self.spider.get_page_content(base_url, params)
            if html:
                bid_list = self.spider.parse_bid_info(html)
                filtered_bids = self.filter_bid_info(bid_list)
                self.all_bid_info.extend(filtered_bids)
            
            # 添加延迟,避免请求过于频繁
            time.sleep(2)
        
        print(f"爬取完成,共获取 {len(self.all_bid_info)} 条符合条件的招标信息")
    
    def filter_bid_info(self, bid_list):
        """
        过滤招标信息
        :param bid_list: 原始招标信息列表
        :return: 过滤后的招标信息列表
        """
        filtered_bids = []
        for bid_info in bid_list:
            # 获取详细内容(如果需要)
            if bid_info.get('link'):
                detail_html = self.spider.get_page_content(bid_info['link'])
                if detail_html:
                    # 解析详细内容(根据实际网站结构实现)
                    bid_info['content'] = self.extract_detail_content(detail_html)
            
            # 关键词过滤
            if self.filter.filter_by_keywords(bid_info):
                # 添加匹配的关键词
                title = bid_info.get('title', '')
                content = bid_info.get('content', '')
                all_text = title + ' ' + content
                bid_info['matched_keywords'] = self.filter.get_matched_keywords(all_text)
                filtered_bids.append(bid_info)
        
        return filtered_bids
    
    def extract_detail_content(self, html):
        """
        提取招标详细信息内容
        :param html: 详情页HTML
        :return: 纯文本内容
        """
        soup = BeautifulSoup(html, 'lxml')
        
        # 根据实际网站结构调整选择器
        content_elem = soup.select_one('.content, .detail, .article-content')
        if content_elem:
            # 移除脚本和样式标签
            for script in content_elem(["script", "style"]):
                script.decompose()
            return content_elem.get_text().strip()
        
        return ''
    
    def save_to_excel(self, filename='bid_information.xlsx'):
        """
        保存招标信息到Excel文件
        :param filename: 文件名
        """
        if not self.all_bid_info:
            print("没有数据可保存")
            return
        
        df = pd.DataFrame(self.all_bid_info)
        
        # 选择要保存的列
        columns_to_save = ['title', 'owner', 'publish_time', 'budget', 'link', 'matched_keywords']
        existing_columns = [col for col in columns_to_save if col in df.columns]
        
        df = df[existing_columns]
        df.to_excel(filename, index=False, engine='openpyxl')
        print(f"数据已保存到 {filename}")
    
    def display_results(self):
        """显示筛选结果"""
        print("\n=== 符合条件的招标信息 ===")
        for i, bid_info in enumerate(self.all_bid_info, 1):
            print(f"\n{i}. 标题: {bid_info.get('title', '')}")
            print(f"   招标方: {bid_info.get('owner', '')}")
            print(f"   发布时间: {bid_info.get('publish_time', '')}")
            print(f"   预算: {bid_info.get('budget', '')}")
            print(f"   匹配关键词: {', '.join(bid_info.get('matched_keywords', []))}")
            print(f"   链接: {bid_info.get('link', '')}")

# 使用示例
if __name__ == "__main__":
    # 替换为实际的招标网站URL
    base_url = "http://www.example-bid-website.com/bid-list"
    
    crawler = BidInformationCrawler()
    crawler.crawl_multiple_pages(base_url, pages=3)
    crawler.display_results()
    crawler.save_to_excel()

三、注意事项与优化建议

  1. 遵守法律法规:在抓取数据前,务必检查网站的robots.txt文件,尊重网站的使用条款
  2. 请求频率控制:合理设置请求间隔,避免对目标网站造成过大压力
  3. 异常处理:完善网络异常、解析异常等情况的处理机制
  4. 数据去重:实现基于标题或内容哈希的去重机制
  5. 代理支持 :对于反爬严格的网站,可以考虑使用代理IP。例如:https://www.16yun.cn/
  6. 验证码处理:准备应对验证码的解决方案,如人工识别或第三方服务

结语

本文详细介绍了使用Python爬虫技术实现招标信息抓取与关键词过滤的完整方案。通过合理的技术选型和模块设计,我们构建了一个高效、可扩展的招标信息监控系统。在实际应用中,企业可以根据自身业务特点调整关键词策略,优化过滤算法,从而更精准地获取商机,提升市场竞争力。

相关推荐
Irene19913 小时前
URLSearchParams :处理 URL 查询参数的接口
开发语言·前端·javascript
Dontla3 小时前
Web典型路由结构之Next.js (App Router, v13+) )(文件系统驱动的路由:File-based Routing)声明式路由:文件即路由
开发语言·前端·javascript
~无忧花开~3 小时前
JavaScript学习笔记(十七):ES6生成器函数详解
开发语言·前端·javascript·笔记·学习·es6·js
电商API_180079052473 小时前
获取淘宝商品视频API接口解析:通过商品链接url获取商品视频item_video
开发语言·爬虫·python·数据挖掘·数据分析
精灵vector3 小时前
构建自定义AI客户支持助手——LangGraph 中断机制
人工智能·python
用户8356290780514 小时前
使用Python自动化移除Excel公式,保留纯净数值
后端·python
Pocker_Spades_A4 小时前
Python快速入门专业版(五十):Python异常处理:try-except语句(捕获单一与多个异常)
开发语言·python
hsjkdhs4 小时前
C++之友元函数与前向引用
开发语言·c++
ajassi20004 小时前
开源 C# 快速开发(十二)进程监控
开发语言·开源·c#