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

Python餐饮巡检数据爬取问题:遍历URL列表获取详情失败

批量爬取餐厅巡检数据的问题排查与解决

嘿,我看到你在批量获取佛罗里达餐厅巡检详情时遇到了阻碍,咱们一步步拆解问题、修复代码:

你的代码核心问题

我整理了几个关键的逻辑和语法错误:

  • 循环遍历逻辑错误:你在遍历DataFrame时每次生成单个URL字符串urls,紧接着写for url in urls——这会把这个URL拆成单个字符逐个遍历,完全不是你想要的批量处理多个URL的逻辑!你需要先把所有生成的URL收集到一个列表中,再统一遍历这个列表。
  • 函数定义与调用错误:你把get_inspect_detail()定义在循环内部,而且函数没有接收url参数;最后调用时用repr(get_inspect_detail()),这只是输出函数的描述信息,根本没有执行函数去爬取数据。
  • 细节语法错误:比如observed1 = details[34].get_text少了调用括号,应该是.get_text();另外批量请求时没有异常处理,单个URL请求失败会直接中断整个程序。

修正后的完整代码

import pandas as pd
import bs4
import datetime
import re
import lxml
from urllib.request import urlopen
from urllib.error import HTTPError, URLError

# 定义爬取单条巡检详情的函数(放在循环外面,复用性更强)
def get_inspect_detail(url):
    try:
        html = urlopen(url)
        soup = bs4.BeautifulSoup(html.read(), 'lxml')
        details = soup.find_all('font', {'face':'verdana'})[10:]
        
        # 注意:这里要确保details的索引是正确的,避免索引越界
        if len(details) < 53:
            print(f"URL {url} 返回的详情数据不完整,跳过")
            return None
            
        siteName = details[0].text.strip()
        licNum = details[2].text.strip()
        siteRank = details[4].text.strip()
        expDate = details[6].text.strip()
        primeStatus = details[8].text.strip()
        secStatus = details[10].text.strip()
        siteAddress = details[12].text.strip()
        inspectResult = details[20].text.strip()
        observed1 = details[34].get_text(strip=True)
        observed2 = details[36].text.strip()
        observed3 = details[38].text.strip()
        observed4 = details[40].text.strip()
        observed5 = details[42].text.strip()
        observed6 = details[44].text.strip()
        observed7 = details[46].text.strip()
        observed8 = details[48].text.strip()
        observed9 = details[50].text.strip()
        observed10 = details[52].text.strip()
        
        detailsLib = {
            'Restaurant': siteName,
            'License': licNum,
            'Rank': siteRank,
            'Expires': expDate,
            'Primary': primeStatus,
            'Secondary': secStatus,
            'Address': siteAddress,
            'Result': inspectResult,
            'Observed1': observed1,
            'Observed2': observed2,
            'Observed3': observed3,
            'Observed4': observed4,
            'Observed5': observed5,
            'Observed6': observed6,
            'Observed7': observed7,
            'Observed8': observed8,
            'Observed9': observed9,
            'Observed10': observed10
        }
        return detailsLib
    except (HTTPError, URLError, IndexError) as e:
        print(f"处理URL {url} 时出错:{str(e)}")
        return None

# 主逻辑:获取并过滤巡检汇总数据
try:
    insp = pd.read_csv(
        "ftp://dbprftp.state.fl.us/pub/llweb/5fdinspi.csv",
        usecols=[2,14,18,80,81]
    )
except IOError:
    print("无法访问FTP文件。")
    exit()

insp.columns = ["CountyName", "InspectDate", "NumHighVio", "LicenseID", "VisitID"]
# 过滤Alachua县且有严重违规的餐厅
alachua = insp[(insp.CountyName == 'Alachua') & (insp.NumHighVio > 0)]
# 转换日期格式并排序
alachua['InspectDate'] = pd.to_datetime(alachua['InspectDate'])
alachua = alachua.sort_values('InspectDate', ascending=False)
# 过滤最近30天的数据
today = pd.to_datetime('today')
startDay = datetime.date.today() - datetime.timedelta(days=30)
alachua = alachua[(alachua['InspectDate'] > startDay) & (alachua['InspectDate'] < today)]

# 第一步:先收集所有需要爬取的URL到列表中
url_list = []
for _, row in alachua.iterrows():
    visitID = row['VisitID']
    licID = row['LicenseID']
    # 直接用f-string生成URL,避免空格问题
    url = f"https://www.myfloridalicense.com/inspectionDetail.asp?InspVisitID={visitID}&licid={licID}"
    url_list.append(url)
    print(f"已添加URL:{url}")

# 第二步:遍历URL列表,批量爬取数据
all_details = []
for url in url_list:
    detail = get_inspect_detail(url)
    if detail:
        all_details.append(detail)
        print(f"成功获取 {detail['Restaurant']} 的巡检数据")

# 把结果转换成DataFrame,方便后续处理
if all_details:
    result_df = pd.DataFrame(all_details)
    print("批量爬取完成!结果预览:")
    print(result_df.head())
    # 可以保存到CSV
    # result_df.to_csv("alachua_restaurant_inspections.csv", index=False)
else:
    print("没有成功获取任何巡检详情数据")

关键修复点说明

  1. URL收集逻辑:先把所有生成的URL存入url_list,再遍历这个列表,确保是批量处理每个巡检页面。
  2. 独立的爬取函数:把get_inspect_detail()放在循环外,接收url参数,每个URL独立调用,同时加入异常处理,避免单个URL出错导致程序崩溃。
  3. 细节优化:
    • 用f-string生成URL,避免手动替换空格的麻烦;
    • 给所有文本加上.strip()去除多余空格;
    • 增加len(details)的判断,防止页面结构变化导致索引越界;
    • 收集所有爬取到的结果到all_details列表,最后转换成DataFrame方便后续清洗和分析。
  4. 正确的函数调用:实际调用get_inspect_detail(url)并接收返回的字典,存入结果列表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:55:32