如何将在线TXT文件转换为pandas DataFrame并定义列名追加数据
问题原因
原代码存在4个核心错误,导致无法正常读取txt并合并DataFrame:
pd.read_csv()不支持直接传入纯文本字符串输入,该方法仅接受本地文件路径或带read方法的类文件对象,直接传入requests返回的text字符串会被识别为无效本地路径,触发文件不存在报错。- pandas的
DataFrame.append()不会原地修改原对象,每次调用会返回全新的拼接后DataFrame,原写法未接收返回值,所有拼接操作都不会生效。 - 初始化DataFrame时漏写pandas前缀,直接调用
DataFrame()会触发名称错误。 - 人口普查局该目录下的txt文件前4行是调查说明、统计口径等元数据,不是正式结构化数据,直接读取会把说明文字识别为数据行,导致格式完全错乱。
修正方案
- 用标准库
io.StringIO把requests返回的文本内容包装为类文件对象,再传给pandas读取。 - 放弃循环逐次append的写法,用列表暂存每个txt生成的临时DataFrame,最后用
pd.concat()一次性合并,性能更高。 - 读取时通过
skiprows参数跳过开头的非数据行,可提前自定义列名传入,也可指定文件自带表头的位置直接使用。 - 这批早期普查文件默认用latin-1编码,解码时指定编码避免乱码。
修正后的可运行代码:
from bs4 import BeautifulSoup import pandas as pd import requests import io from bs4.dammit import EncodingDetector target_url = 'https://www2.census.gov/econ/bps/Place/West%20Region/' parser = 'html.parser' page_resp = requests.get(target_url) http_encoding = page_resp.encoding if 'charset' in page_resp.headers.get('content-type', '').lower() else None html_encoding = EncodingDetector.find_declared_encoding(page_resp.content, is_html=True) page_encoding = html_encoding or http_encoding region_soup = BeautifulSoup(page_resp.content, parser, from_encoding=page_encoding) # 按文件字段顺序自定义列名,不需要自定义可删除相关配置,直接使用文件自带表头 custom_cols = [ "fips_code", "place_name", "total_permit_units", "single_family_units", "two_unit_units", "three_four_unit_units", "five_plus_unit_units" ] df_container = [] for link in region_soup.find_all('a', href=True): file_name = link['href'] if not file_name.endswith(".txt"): continue print(f"处理文件: {file_name}") file_resp = requests.get(target_url + file_name) # 用latin-1解码老普查文件避免乱码 file_text = file_resp.content.decode('latin-1') file_buffer = io.StringIO(file_text) # 读取配置可根据实际文件格式调整 temp_df = pd.read_csv( file_buffer, sep=",", # 如果是空白分隔文件替换为r'\s+',固定宽度文件换用pd.read_fwf skiprows=4, # 跳过前4行元数据说明,根据实际文件格式调整行数 skip_blank_lines=True, names=custom_cols, # 用自定义列名,使用文件自带表头请删除本行 header=None # 配合自定义列名跳过文件自带表头行,使用文件自带表头请删除本行并设置header=表头行索引 ) # 新增来源字段方便后续数据溯源 temp_df["source_file"] = file_name df_container.append(temp_df) # 一次性合并所有数据 final_df = pd.concat(df_container, ignore_index=True)
配置说明
- 列名定义:如果不需要自定义列,删除
names=custom_cols和header=None两个参数,将header设置为文件中表头所在的行索引即可(行索引从0开始计数,比如表头在第5行就设置header=4)。 - 格式适配:如果读取时出现列错位,手动打开1-2个目标txt文件,确认分隔符类型、开头非数据行数量,对应调整
sep和skiprows参数即可。部分年份的早期文件是固定宽度格式,把pd.read_csv替换为pd.read_fwf即可,其余参数逻辑一致。 - 数据清洗:合并完成后可按需做数据类型转换、空值过滤、字段拆分等后续处理。
内容的提问来源于stack exchange,提问作者matt stoebe
相关产品推荐
相关产品推荐

