:斗南花卉鲜花价格采集)
一、前言本篇将引入一个新的解析利器——PyQuery深入讲解如何使用PyQuery进行jQuery风格的DOM操作与表格解析处理HTML表格数据的精准提取避免字段错位实现多品类批量爬取8个分类统一采集使用pandas进行数据整合与Excel导出掌握面向对象的爬虫架构设计目标站点特点昆明斗南花卉市场是中国乃至亚洲最大的鲜切花交易市场被誉为中国花卉市场的风向标。其官网提供8大品类的实时批发价格数据以传统HTML表格形式展示包含品名、种类、颜色、单位、A/B/C三级价格、涨跌等字段。这种多品类表格结构的组合是练习PyQuery和面向对象设计的绝佳场景。二、网站分析与表格结构解析2.1 斗南花卉市场概况昆明斗南花卉市场位于云南省昆明市呈贡区是全国鲜花市场的心脏市场地位亚洲第一、世界第二的专业鲜切花拍卖市场每天有10000余人次进场交易日上市鲜花66个大类、300多个品种全国80多个大中城市中占据70%的市场份额每天有280余吨鲜切花通过航空、铁路、公路运往全国各地2.2 网站页面与URL规律打开 斗南花卉官网可以看到8大品类分类分类IDURL品类1http://www.duood.com/GoodsList.aspx?id1玫瑰类2http://www.duood.com/GoodsList.aspx?id2百合类3http://www.duood.com/GoodsList.aspx?id3康乃馨类4http://www.duood.com/GoodsList.aspx?id4菊花类5http://www.duood.com/GoodsList.aspx?id5配花配草6http://www.duood.com/GoodsList.aspx?id6绣球类7http://www.duood.com/GoodsList.aspx?id7洋桔梗类8http://www.duood.com/GoodsList.aspx?id8其他鲜花URL规律通过id参数切换品类非常适合批量爬取。2.3 表格HTML结构分析通过开发者工具分析价格数据的HTML结构如下tabletrth品名/thth图片/thth种类/thth颜色/thth单位/ththC级价格/ththB级价格/ththA级价格/thth涨跌/th/trtrtd卡罗拉/tdtdimgsrc.../tdtd单头玫瑰/tdtd红色/tdtd20支/扎/tdtd15.00/tdtd18.00/tdtd22.00/tdtd↑2.00/td/tr!-- 更多tr... --/table关键特征第一行是表头th需要跳过数据行使用td每行9个单元格字段位置固定可通过索引精准提取三、代码实现与深度解析3.1 完整源码importrequestsfrompyqueryimportPyQueryaspqimportdatetimeimportpandasaspdimportwarnings# 忽略SSL证书警告目标站点使用自签名证书warnings.filterwarnings(ignore)classCurrentSpider: 斗南花卉鲜花价格爬虫类 设计思路 1. 面向对象封装将请求、解析、存储逻辑封装为类方法 2. 多品类支持通过url列表实现8大品类批量爬取 3. 实时采集自动记录采集日期便于时序分析 4. 精准解析按行遍历表格通过索引提取字段彻底避免错位 # 市场名称常量market_name昆明市斗南花卉鲜花批发交易市场# 8大品类URL列表url[http://www.duood.com/GoodsList.aspx?id1,# 玫瑰类http://www.duood.com/GoodsList.aspx?id2,# 百合类http://www.duood.com/GoodsList.aspx?id3,# 康乃馨类http://www.duood.com/GoodsList.aspx?id4,# 菊花类http://www.duood.com/GoodsList.aspx?id5,# 配花配草http://www.duood.com/GoodsList.aspx?id6,# 绣球类http://www.duood.com/GoodsList.aspx?id7,# 洋桔梗类http://www.duood.com/GoodsList.aspx?id8,# 其他鲜花]def__init__(self): 初始化方法 实例变量 all_data: 存储所有爬取的数据二维列表 reporting: 当前日期字符串YYYY-MM-DD格式 self.all_data[]# 数据容器self.reportingdatetime.datetime.now().strftime(%Y-%m-%d)# 采集日期defget_page(self,url): 发起HTTP GET请求获取网页源码 参数: url: 目标网页地址 返回: 解码后的HTML字符串 请求头设计 1. User-Agent模拟Chrome浏览器绕过基础UA检测 2. Referer设置为网站首页模拟从首页跳转 3. verifyFalse跳过SSL证书验证学习用途 4. timeout10防止网络波动导致程序卡死 5. encodingutf-8显式指定编码防止中文乱码 headers{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36,Referer:http://www.duood.com/# 来源页}# 发送GET请求rrequests.get(url,headersheaders,verifyFalse,timeout10)# 显式设置编码防止requests自动猜测编码错误r.encodingutf-8returnr.textdefparse(self,text): 精准解析表格提取所有字段彻底避免错位 参数: text: 网页HTML字符串 解析策略 1. 使用PyQuery初始化HTML文档 2. 查找所有表格行doc(table tr) 3. 跳过表头行索引0 4. 遍历每行的td单元格提取文本内容 5. 通过索引0-8精准映射到对应字段 6. 过滤无效空行 为什么用PyQuery而不是BeautifulSoup - PyQuery语法与jQuery一致对前端开发者更友好 - 链式操作更流畅doc(table tr).items() - 性能优异底层基于lxml docpq(text)# 查找所有表格行.items()返回生成器支持迭代tr_listdoc(table tr).items()foridx,trinenumerate(tr_list):# 跳过表头行第一行是th表头直接跳过ifidx0:continue# 查找当前行的所有td单元格tdstr(td).items()# 提取每个单元格的文本内容并去除首尾空白# 列表推导式[td.text().strip() for td in tds]td_list[td.text().strip()fortdintds]# 确保行数据完整至少包含8个核心字段# 部分行可能为广告或空行通过长度过滤iflen(td_list)8:# 严格对应表头顺序通过索引提取数据# 这种索引映射方式比按class名查找更可靠# 因为表格结构固定字段位置不会变化nametd_list[0]# 品名如卡罗拉kindtd_list[2]# 种类如单头玫瑰colortd_list[3]# 颜色如红色unittd_list[4]# 单位如20支/扎c_leveltd_list[5]# C级价格最低品质b_leveltd_list[6]# B级价格中等品质a_leveltd_list[7]# A级价格最高品质changetd_list[8]# 涨跌如↑2.00# 过滤无效空行品名为空或为品名表头重复ifnotnameorname品名:continue# 实时输出爬一条输出一行便于监控进度# 使用格式化字符串对齐输出美观易读print(f✅{self.reporting}| f名称{name:8}| # 8 左对齐占8字符宽度f种类{kind:6}| f颜色{color:6}| f单位{unit:8}| fC级{c_level:4}| fB级{b_level:4}| fA级{a_level:4}| f涨跌{change:4}| f{self.market_name})# 存入数据列表用于后续写入Excel# 使用列表而非字典因为pandas.DataFrame可直接接收二维列表self.all_data.append([self.reporting,# 采集日期name,# 名称kind,# 种类color,# 颜色unit,# 单位c_level,# C级价格b_level,# B级价格a_level,# A级价格change,# 涨跌self.market_name# 市场名称])defwrite_to_excel(self): 将完整数据写入Excel文件 设计要点 1. 使用pandas.DataFrame构造数据表格 2. 指定columns作为表头 3. 生成带日期的文件名避免覆盖 4. 使用openpyxl引擎支持.xlsx格式 5. indexFalse不保存行索引 # 边界判断无数据时给出提示ifnotself.all_data:print(\n❌ 未爬取到任何有效数据)return# 构造DataFrame# columns参数指定列名与self.all_data的子列表顺序一一对应dfpd.DataFrame(self.all_data,columns[采集日期,名称,种类,颜色,单位,C级价格,B级价格,A级价格,涨跌,市场名称])# 生成带日期的文件名斗南鲜花完整价格_20240115.xlsx# replace(-, )去掉日期中的横杠使文件名更简洁filenamef斗南鲜花完整价格_{self.reporting.replace(-,)}.xlsx# 写入Excel# engineopenpyxl指定Excel引擎需提前安装pip install openpyxldf.to_excel(filename,indexFalse,engineopenpyxl)print(f\n✅ 数据保存成功共{len(self.all_data)}条记录文件{filename})defenterMethod(self): 爬虫入口方法主控制流程 流程设计 1. 打印欢迎信息 2. 遍历所有品类URL 3. 对每个URL请求 → 解析 4. 全部完成后写入Excel # 打印分隔线和标题print(*120)print(斗南花卉完整价格爬虫精准提取所有字段·无错位·爬一条输出一条)print(*120)# 遍历所有品类URLforurlinself.url:print(f\n 正在爬取分类页{url})# 步骤1获取网页HTMLhtmlself.get_page(url)# 步骤2解析提取数据self.parse(html)# 步骤3全部完成后统一写入Excelself.write_to_excel()# # 程序入口# if__name____main__:# 创建爬虫实例cCurrentSpider()# 启动爬虫c.enterMethod()3.2 核心设计思想解析1PyQuery vs BeautifulSoup vs XPath本案例引入了第三种解析库——PyQuery三种库的对比如下维度PyQueryBeautifulSoupXPath语法风格jQuery风格链式操作Pythonic方法调用XML路径表达式学习曲线有jQuery基础极易上手简单直观较陡峭性能快基于lxml中等快基于lxml适用场景熟悉前端开发者通用场景复杂条件查询表格解析doc(table tr).items()soup.find_all(tr)//table//trPyQuery核心语法frompyqueryimportPyQueryaspq# 初始化支持字符串、URL、文件docpq(html.../html)# 从字符串docpq(urlhttp://example.com)# 从URLdocpq(filenameindex.html)# 从文件# CSS选择器查找itemsdoc(table tr).items()# 查找所有表格行titledoc(#title).text()# ID选择器linksdoc(a.link).attr(href)# class选择器属性提取# 链式操作doc(div.item).find(span).text()# 查找子元素doc(div).filter(.active)# 过滤本案例PyQuery使用docpq(text)# 从HTML字符串初始化tr_listdoc(table tr).items()# 查找所有表格行生成器fortrintr_list:tdstr(td).items()# 在当前行内查找所有单元格td_list[td.text().strip()fortdintds]# 提取文本这种jQuery风格的链式操作对前端开发者极其友好代码可读性极高。2表格解析的索引映射策略这是本案例最核心的设计——通过索引而非class名提取字段# ✅ 索引映射推荐位置固定不受class变化影响nametd_list[0]# 第1列品名kindtd_list[2]# 第3列种类跳过第2列图片colortd_list[3]# 第4列颜色# ❌ class查找不推荐表格通常无class或class重复nametr.find(.name).text()# 可能找不到或找错为什么索引映射更可靠场景索引映射class查找表格无class✅ 正常工作❌ 无法定位class重复✅ 不受影响❌ 可能错位网站改版⚠️ 只需调整索引❌ 需重新分析class代码可读性⚠️ 需注释说明✅ 语义清晰最佳实践表格解析优先使用索引映射配合详细注释说明每个索引对应的字段。3面向对象架构设计本案例采用面向对象设计相比函数式编程的优势┌─────────────────────────────────────┐ │ CurrentSpider 类 │ ├─────────────────────────────────────┤ │ 类属性 │ │ market_name 昆明市斗南花卉... │ │ url [8个品类URL] │ ├─────────────────────────────────────┤ │ 实例属性 │ │ self.all_data [] │ │ self.reporting 2024-01-15 │ ├─────────────────────────────────────┤ │ 方法 │ │ __init__() → 初始化 │ │ get_page() → 请求网页 │ │ parse() → 解析数据 │ │ write_to_excel() → 持久化存储 │ │ enterMethod() → 主控制流程 │ └─────────────────────────────────────┘设计优势封装性数据all_data与方法parse绑定避免全局变量污染可扩展性新增品类只需修改url列表无需改动解析逻辑可复用性类可直接实例化多次爬取不同日期数据可维护性结构清晰便于后续添加多线程、数据库等功能四、运行效果展示4.1 控制台输出程序运行时的控制台输出如下可以看到清晰的进度与数据输出特征每行数据对齐输出美观易读实时显示采集日期、品类信息、价格数据使用✅标识成功提取的记录4.2 生成的Excel文件爬取完成后生成的Excel文件结构如下文件特点包含8大品类所有数据统一整合带日期文件名便于时序追踪字段完整可直接用于数据分析五、总结通过本次实战我们完整掌握了PyQuery表格解析与面向对象爬虫设计的核心技术PyQuery解析库掌握jQuery风格的链式操作理解items()生成器、text()文本提取等核心方法表格索引映射通过固定位置索引提取表格字段避免class变化导致的解析失败面向对象架构使用类封装请求、解析、存储逻辑提升代码的可维护性和可扩展性多品类批量爬取通过URL列表实现8大品类统一采集理解参数化设计思想pandas数据整合使用DataFrame构造结构化数据实现Excel专业格式导出