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

优化BeautifulSoup爬虫 爬取Fleetmon海事新闻导出指定格式CSV

Fleetmon海事新闻爬虫优化方案

原有代码问题

  • 语法缩进错误:分页循环内的请求、解析逻辑未正确缩进,仅会处理循环最后一次的响应
  • 链接格式错误:列表页提取的是相对路径,未拼接域名直接请求会返回404
  • 元素定位错误:原有详情页选择器与站点实际DOM结构不匹配,无法提取到目标字段
  • 反爬策略缺失:列表页请求未携带合法请求头,极易被站点拦截
  • 容错机制缺失:遇到请求超时、页面元素不存在时程序直接崩溃
  • 无效链接未过滤:会抓取到导航、广告、标签页等非新闻详情链接,浪费请求资源
  • 分页范围过小:默认仅爬取1页内容,无法获取全量数据

优化后完整代码

import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
from urllib.parse import urljoin

# 基础配置
BASE_URL = 'https://www.fleetmon.com/maritime-news/'
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',
    'Accept-Language': 'en-US,en;q=0.9',
    'Referer': 'https://www.fleetmon.com/'
}
# 配置爬取页数,全量爬取可修改为列表页实际总页数
MAX_PAGE = 10
REQUEST_DELAY = 1  # 请求间隔,单位秒,避免被封
SAVE_PATH = './fleetmon_news.csv'

def get_news_links():
    """获取所有新闻详情页链接"""
    news_links = set()
    for page in range(1, MAX_PAGE + 1):
        try:
            resp = requests.get(
                BASE_URL,
                params={'page': page},
                headers=HEADERS,
                timeout=10
            )
            resp.raise_for_status()
            soup = BeautifulSoup(resp.text, 'html.parser')
            # 精准定位新闻卡片的标题链接,过滤无效链接
            card_links = soup.select('a.article-card__title[href*="/maritime-news/"]')
            for link in card_links:
                full_url = urljoin(BASE_URL, link['href'])
                news_links.add(full_url)
            print(f'第{page}页链接提取完成,当前累计有效链接{len(news_links)}条')
            time.sleep(REQUEST_DELAY)
        except Exception as e:
            print(f'第{page}页链接提取失败:{str(e)}')
            continue
    return list(news_links)

def parse_news_detail(url):
    """解析单条新闻详情页内容"""
    try:
        resp = requests.get(url, headers=HEADERS, timeout=10)
        resp.raise_for_status()
        soup = BeautifulSoup(resp.text, 'html.parser')
        
        # 提取标题
        title = soup.select_one('h1.article-header__title').text.strip()
        # 提取分类:取面包屑最后一个分类文本
        category = soup.select('nav.breadcrumbs a')[-1].text.strip()
        # 提取发布时间,格式与要求一致
        pub_time = soup.select_one('span.article-meta__date').text.strip()
        # 提取正文:拼接所有段落文本,去掉多余空白
        content_paragraphs = soup.select('div.article__content p')
        content = '\n'.join([p.text.strip() for p in content_paragraphs if p.text.strip()])
        
        return {
            'News_title': title,
            'category': category,
            'publish_date_time': pub_time,
            'news': content
        }
    except Exception as e:
        print(f'详情页解析失败[{url}]:{str(e)}')
        return None

if __name__ == '__main__':
    all_links = get_news_links()
    print(f'共获取到{len(all_links)}条有效新闻链接,开始解析详情')
    news_data = []
    for idx, link in enumerate(all_links):
        item = parse_news_detail(link)
        if item:
            news_data.append(item)
        print(f'进度:{idx+1}/{len(all_links)}')
        time.sleep(REQUEST_DELAY)
    
    # 按指定字段顺序导出CSV,编码适配Excel打开不乱码
    df = pd.DataFrame(news_data, columns=['News_title', 'category', 'publish_date_time', 'news'])
    df.to_csv(SAVE_PATH, index=False, encoding='utf-8-sig')
    print(f'爬取完成,共保存有效新闻{len(news_data)}条,文件保存路径:{SAVE_PATH}')

使用说明

  • 全量爬取时,先访问新闻列表页,拉到最底部分页栏查看总页数,将代码中MAX_PAGE变量修改为对应数值即可
  • 若爬取过程中出现连接被拒绝的情况,可适当调大REQUEST_DELAY的数值,降低请求频率
  • 导出的CSV默认保存在代码运行的同级目录,可修改SAVE_PATH自定义保存位置
  • 代码自动过滤解析失败的条目,不会因单条新闻异常中断整体爬取流程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 16:01:06