使用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会按最短的列表长度匹配,但多余的墓园元素会在最后一条数据后生成一个只有墓园信息、姓名为空的记录,也就是你看到的空单元格。
具体解决步骤
按单个逝者容器提取数据,保证字段对应
不要分开抓三个列表,而是先找到每个逝者的容器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)优化CSV写入细节
- 添加
newline='':避免Windows系统下导出的CSV出现多余空行; - 指定
encoding='utf-8':防止特殊字符乱码; - 首次运行时可以先写入表头(放在循环外执行一次):
with open('Fernandiabeach3.csv', 'w', newline='', encoding='utf-8') as csvfile: writer = csv.writer(csvfile) writer.writerow(['姓名', '生卒日期', '安葬墓园'])
- 添加
调试验证(可选)
如果想确认之前的列表长度问题,可以在循环中添加打印语句:print(f"第{page_no}页:姓名数量{len(grave_name)},日期数量{len(dates)},墓园数量{len(grave_yard)}")你会看到墓园数量明显多于其他两个,这就是空单元格的直接来源。
内容的提问来源于stack exchange,提问作者Sanderson10453
相关产品推荐
相关产品推荐

