Python爬虫实战:高效采集农业病虫害图谱数据
1. 项目背景与需求分析农作物病虫害图谱是农业从业者和研究人员的重要参考资料但大多数专业网站都采用分类页详情页的二段式结构展示数据。传统手动收集方式效率极低一个完整的图谱库往往包含数百个分类和上万张图片。这正是我们需要自动化采集解决方案的原因。去年我在帮某农业研究所构建病虫害识别系统时发现他们需要收集12个大类、86个小类共计约1.2万张图谱。如果人工操作按每张图30秒计算需要100小时而用Python爬虫只需2小时就能完成全部采集。这就是技术带来的效率革命。2. 技术方案设计2.1 整体架构设计采用经典的两阶段采集模式分类页采集获取所有病虫害分类链接详情页采集根据分类链接逐级获取图谱数据这种架构的优势在于逻辑清晰易于维护可以分阶段执行和调试天然支持增量采集2.2 核心工具选型import requests from bs4 import BeautifulSoup import pandas as pd import time import random from urllib.parse import urljoin选择这些库的原因是requests比urllib更人性化的HTTP库BeautifulSoupHTML解析神器pandas数据存储和导出更方便timerandom实现请求间隔随机化urljoin处理相对路径转绝对路径3. 分类页采集实现3.1 页面结构分析以某农业网站为例分类页通常有这样的结构div classcategory-list a href/disease/rice/1稻瘟病/a a href/disease/wheat/2小麦锈病/a ... /div3.2 采集代码实现def get_categories(main_url): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) } try: response requests.get(main_url, headersheaders) response.raise_for_status() soup BeautifulSoup(response.text, html.parser) categories [] for link in soup.select(.category-list a): category_name link.text.strip() category_url urljoin(main_url, link[href]) categories.append((category_name, category_url)) return categories except Exception as e: print(f获取分类失败: {e}) return []3.3 反爬应对策略User-Agent轮换准备多个常见浏览器的UA请求间隔使用time.sleep(random.uniform(1, 3))代理IP池对于严格反爬的网站需要准备异常处理捕获所有可能的网络异常4. 详情页采集实现4.1 详情页结构分析典型详情页包含病虫害名称症状描述防治方法图片可能有多张4.2 核心采集代码def get_details(category_url): details [] page 1 while True: url f{category_url}?page{page} try: response requests.get(url) soup BeautifulSoup(response.text, html.parser) items soup.select(.disease-item) if not items: break for item in items: name item.select_one(.disease-name).text.strip() desc item.select_one(.description).text.strip() imgs [img[src] for img in item.select(.disease-img img)] details.append({ name: name, description: desc, images: imgs }) page 1 time.sleep(random.uniform(1, 2)) except Exception as e: print(f获取详情页失败: {e}) break return details4.3 图片下载处理def download_images(img_urls, save_dir): if not os.path.exists(save_dir): os.makedirs(save_dir) for i, url in enumerate(img_urls): try: response requests.get(url, streamTrue) with open(f{save_dir}/img_{i}.jpg, wb) as f: for chunk in response.iter_content(1024): f.write(chunk) time.sleep(0.5) except Exception as e: print(f下载图片失败: {url} - {e})5. 数据存储方案5.1 结构化存储使用pandas DataFrame存储文本数据df pd.DataFrame({ category: category_name, disease_name: item[name], description: item[description], image_paths: , .join([fimages/{category_name}/{i}.jpg for i in range(len(item[images]))]) }) df.to_csv(disease_data.csv, indexFalse)5.2 文件目录组织建议按以下结构组织dataset/ ├── rice/ │ ├── img_0.jpg │ ├── img_1.jpg ├── wheat/ │ ├── img_0.jpg ├── disease_data.csv6. 高级技巧与优化6.1 并发采集优化使用多线程提高效率from concurrent.futures import ThreadPoolExecutor def crawl_category(category): name, url category details get_details(url) save_data(name, details) with ThreadPoolExecutor(max_workers4) as executor: executor.map(crawl_category, categories)6.2 断点续采实现记录已采集的页码if os.path.exists(progress.json): with open(progress.json) as f: progress json.load(f) else: progress {} # 采集时更新进度 progress[category_name] current_page6.3 反反爬进阶策略模拟鼠标移动轨迹使用selenium应对动态加载随机浏览路径分布式采集7. 法律与道德注意事项严格遵守robots.txt规则控制请求频率建议1请求/秒仅采集公开数据不绕过付费墙注明数据来源重要提示商业用途前务必咨询法律意见个人学习研究也应注意数据使用范围。8. 完整项目示例import os import json from concurrent.futures import ThreadPoolExecutor def main(): # 1. 获取所有分类 base_url https://example.com/diseases categories get_categories(base_url) # 2. 创建数据目录 if not os.path.exists(dataset): os.makedirs(dataset) # 3. 加载进度 progress_file progress.json if os.path.exists(progress_file): with open(progress_file) as f: progress json.load(f) else: progress {} # 4. 并发采集 with ThreadPoolExecutor(max_workers4) as executor: for category in categories: name, url category if name in progress: print(f跳过已采集分类: {name}) continue executor.submit(crawl_category, name, url) print(采集完成) if __name__ __main__: main()9. 常见问题解决9.1 请求被拒绝(403)可能原因User-Agent被识别IP被限制解决方案更换User-Agent增加请求头headers { Accept: text/html,application/xhtmlxml, Accept-Language: zh-CN,zh;q0.9, Referer: https://www.google.com/ }9.2 数据加载不全可能原因动态加载内容需要触发JS事件解决方案 使用selenium模拟浏览器from selenium import webdriver driver webdriver.Chrome() driver.get(url) html driver.page_source soup BeautifulSoup(html, html.parser)9.3 图片下载失败处理方案重试机制URL修正def fix_url(url): if url.startswith(//): return https: url return url10. 项目扩展方向自动分类标注用文件名包含分类信息数据清洗脚本去除重复和低质量图片构建检索系统使用Elasticsearch开发识别模型训练CNN分类器这个项目最让我有成就感的是采集到的数据后来被用于训练一个准确率达到92%的水稻病害识别模型。技术真正的价值在于解决实际问题而Python爬虫就是我们获取数据的有力工具。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →