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("没有成功获取任何巡检详情数据")
关键修复点说明
- URL收集逻辑:先把所有生成的URL存入
url_list,再遍历这个列表,确保是批量处理每个巡检页面。 - 独立的爬取函数:把
get_inspect_detail()放在循环外,接收url参数,每个URL独立调用,同时加入异常处理,避免单个URL出错导致程序崩溃。 - 细节优化:
- 用f-string生成URL,避免手动替换空格的麻烦;
- 给所有文本加上
.strip()去除多余空格; - 增加
len(details)的判断,防止页面结构变化导致索引越界; - 收集所有爬取到的结果到
all_details列表,最后转换成DataFrame方便后续清洗和分析。
- 正确的函数调用:实际调用
get_inspect_detail(url)并接收返回的字典,存入结果列表。
内容的提问来源于stack exchange,提问作者DRay
相关产品推荐
相关产品推荐

