You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python爬取Rotowire MLB球员新闻并构建可增量更新的DataFrame表格

解决方案:MLB新闻爬取、DataFrame整理与定时增量更新

1. 核心问题解决:数据解析与DataFrame字段映射

Rotowire的新闻条目有固定结构,通过BeautifulSoup精准定位元素,拆分日期、球员、标题和内容字段,直接映射到DataFrame的行中。

2. 完整代码实现

import requests
from bs4 import BeautifulSoup
import pandas as pd
import schedule
import time
import hashlib

# 初始化全局DataFrame,优先读取本地已保存数据
try:
    global_df = pd.read_csv("mlb_news.csv")
except FileNotFoundError:
    global_df = pd.DataFrame(columns=["日期", "球员", "标题", "新闻内容", "唯一标识"])

def parse_mlb_news():
    url = "https://www.rotowire.com/baseball/news.php"
    # 模拟浏览器请求,避免反爬拦截
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
    }
    response = requests.get(url, headers=headers)
    response.raise_for_status()  # 捕获请求错误
    soup = BeautifulSoup(response.text, "html.parser")
    
    news_items = soup.find_all("div", class_="news-item")
    batch_data = []
    
    for item in news_items:
        # 提取日期
        date_tag = item.find("span", class_="news-item__date")
        news_date = date_tag.get_text(strip=True) if date_tag else "未知日期"
        
        # 提取标题与球员:标题格式多为「球员名: 新闻标题」
        title_tag = item.find("a", class_="news-item__title")
        raw_title = title_tag.get_text(strip=True) if title_tag else "无标题"
        
        if ": " in raw_title:
            player_name, clean_title = raw_title.split(": ", 1)
            player_name = player_name.strip()
            clean_title = clean_title.strip()
        else:
            player_name = "未知球员"
            clean_title = raw_title
        
        # 提取新闻内容
        content_tag = item.find("div", class_="news-item__content")
        news_content = content_tag.get_text(strip=True) if content_tag else "无内容"
        
        # 生成唯一标识,用于去重
        unique_key = hashlib.md5(f"{news_date}{player_name}{clean_title}".encode()).hexdigest()
        
        batch_data.append({
            "日期": news_date,
            "球员": player_name,
            "标题": clean_title,
            "新闻内容": news_content,
            "唯一标识": unique_key
        })
    
    return pd.DataFrame(batch_data)

def update_news_database():
    global global_df
    # 爬取最新新闻
    new_news_df = parse_mlb_news()
    # 合并数据并去重,保留首次出现的条目(避免重复爬取)
    combined_df = pd.concat([global_df, new_news_df]).drop_duplicates(subset="唯一标识", keep="first")
    global_df = combined_df.reset_index(drop=True)
    # 保存到本地文件,防止程序重启数据丢失
    global_df.to_csv("mlb_news.csv", index=False, encoding="utf-8-sig")
    print(f"数据更新完成,当前累计新闻条数:{len(global_df)}")

def start_scheduled_crawl():
    # 立即执行一次初始爬取
    update_news_database()
    # 设置每5分钟爬取一次
    schedule.every(5).minutes.do(update_news_database)
    
    # 持续运行调度器
    while True:
        schedule.run_pending()
        time.sleep(1)

if __name__ == "__main__":
    start_scheduled_crawl()

3. 关键细节说明

  • 字段拆分逻辑:利用标题中「球员名: 标题」的固定格式拆分球员与标题,无明确球员的条目标记为「未知球员」,兼容所有新闻类型。
  • 去重机制:通过日期+球员+标题的哈希值生成唯一标识,确保重复爬取的新闻不会重复添加到DataFrame中。
  • 数据持久化:每次更新后将DataFrame保存为CSV文件,程序重启时自动加载历史数据,实现增量积累。
  • 反爬处理:设置浏览器UA头,避免被网站直接拦截;添加response.raise_for_status()捕获请求异常,方便排查问题。

4. 注意事项

  • 若网站更新页面结构(如class名称变化),需重新检查并修改BeautifulSoup的定位标签。
  • 频繁爬取可能触发网站反爬机制,可根据实际情况调整爬取间隔,或添加随机延迟(如time.sleep(random.randint(1,3)))。
  • 若需要处理更多异常情况(如网络波动),可在parse_mlb_news函数中添加try-except块捕获请求或解析错误。

内容的提问来源于stack exchange,提问作者buttermilk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 18:25:24