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

使用BeautifulSoup导出CSV时姓名列出现空单元格问题求助

问题:Findagrave爬虫导出CSV后每页末尾姓名列出现空单元格

我正在用爬虫抓取Findagrave网站的逝者姓名、生卒日期及安葬墓园信息,功能整体正常,但导出CSV后发现每一页数据之后的姓名列都会出现一个空单元格。我猜测问题可能出在循环逻辑而非HTML标签,目前还在学习阶段,希望得到解决建议。

我的实现代码

from dataclasses import replace
import requests
from bs4 import BeautifulSoup
import csv 

api = 'https://www.findagrave.com/memorial/search?'
name = 'firstname=&middlename=&lastname='
years = 'birthyear=&birthyearfilter=&deathyear=&deathyearfilter='
place = 'location=Yulee%2C+Nassau+County%2C+Florida%2C+United+States+of+America&locationId=city_28711'
memorialid = 'memorialid=&mcid='
linkname = 'linkedToName='
daterange = 'datefilter='
plotnum = 'orderby=r&plot='
page = 'page='
url = api + name + "&" + years + "&" + place + "&" + memorialid + "&" + linkname + "&" + daterange + "&" + plotnum + '&' + page
for page_no in range(1,93): 
   url_final = url + str(page_no)
   page = requests.get(url_final, headers = headers)

   soup = BeautifulSoup(page.content, "html.parser")
   graves = soup.find_all('div', {'class':'memorial-item py-1'})

   # 获取姓名
   grave_name = soup.find_all('h2', {'class':'name-grave'}) 

   # 获取生卒日期
   dates = soup.find_all('b', {'class':'birthDeathDates'})

   # 获取安葬墓园
   grave_yard = soup.find_all('button', {'role': 'link'})

   dataset = [(x.text, y.text, z.text) for x,y,z in zip(grave_name, dates, grave_yard)]
   with open('Fernandiabeach3.csv', 'a',) as csvfile:
    writer = csv.writer(csvfile)
    writer.writerows(dataset)

我已经尝试检查每页开头的HTML标签,但未发现异常。


问题分析与解决建议

核心原因

你目前是分别抓取姓名、日期、墓园三个独立列表,再用zip打包数据,但这三个列表的长度大概率不匹配:

  • 用soup.find_all('button', {'role': 'link'})抓取墓园时,会意外抓到页面上其他符合条件的按钮(比如导航、页脚区域的按钮),导致grave_yard列表长度比实际逝者数据多1;
  • zip会按最短的列表长度匹配,但多余的墓园元素会在最后一条数据后生成一个只有墓园信息、姓名为空的记录,也就是你看到的空单元格。

具体解决步骤

  1. 按单个逝者容器提取数据,保证字段对应
    不要分开抓三个列表,而是先找到每个逝者的容器memorial-item py-1,再在每个容器内单独提取姓名、日期、墓园,从根源避免字段错位:

    for page_no in range(1,93): 
        url_final = url + str(page_no)
        page = requests.get(url_final, headers=headers)
        soup = BeautifulSoup(page.content, "html.parser")
        graves = soup.find_all('div', {'class':'memorial-item py-1'})
        
        dataset = []
        for grave in graves:
            # 从单个逝者容器内提取姓名
            name_tag = grave.find('h2', {'class':'name-grave'})
            name = name_tag.text.strip() if name_tag else ''
            
            # 提取生卒日期
            date_tag = grave.find('b', {'class':'birthDeathDates'})
            dates = date_tag.text.strip() if date_tag else ''
            
            # 提取当前逝者对应的安葬墓园
            yard_tag = grave.find('button', {'role': 'link'})
            grave_yard = yard_tag.text.strip() if yard_tag else ''
            
            dataset.append((name, dates, grave_yard))
        
        # 优化CSV写入参数,避免空行和乱码
        with open('Fernandiabeach3.csv', 'a', newline='', encoding='utf-8') as csvfile:
            writer = csv.writer(csvfile)
            writer.writerows(dataset)
    
  2. 优化CSV写入细节

    • 添加newline='':避免Windows系统下导出的CSV出现多余空行;
    • 指定encoding='utf-8':防止特殊字符乱码;
    • 首次运行时可以先写入表头(放在循环外执行一次):
      with open('Fernandiabeach3.csv', 'w', newline='', encoding='utf-8') as csvfile:
          writer = csv.writer(csvfile)
          writer.writerow(['姓名', '生卒日期', '安葬墓园'])
      
  3. 调试验证(可选)
    如果想确认之前的列表长度问题,可以在循环中添加打印语句:

    print(f"第{page_no}页:姓名数量{len(grave_name)},日期数量{len(dates)},墓园数量{len(grave_yard)}")
    

    你会看到墓园数量明显多于其他两个,这就是空单元格的直接来源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 22:35:10