实战教程:Python爬取北京新发地农产品价格数据并存储到MySQL

实战教程:Python爬取北京新发地农产品价格数据并存储到MySQL

在农产品价格数据分析、市场行情监控等场景中,获取新发地的价格数据是很有价值的需求。本文将详细讲解如何使用Python实现北京新发地农产品价格数据的爬取,并将爬取到的数据存储到MySQL数据库中,帮助大家掌握网络爬虫与数据库操作的核心技能。

技术栈选型

  • 网络请求 :使用requests库发送HTTP请求,获取目标网站的接口数据。requests库简洁易用,能高效处理POST/GET等请求方式,满足接口调用需求。
  • 数据解析 :目标接口返回JSON格式数据,使用Python内置的json库解析数据,提取关键信息。
  • 数据库操作 :使用pymysql库连接MySQL数据库,实现数据表创建和数据插入操作,pymysql是Python操作MySQL的主流库,兼容性好、操作便捷。
  • 其他time库用于异常处理时的短暂休眠,避免频繁请求触发网站限制。

实现步骤详解

步骤1:环境准备

首先需要安装所需的Python库,执行以下命令:

bash 复制代码
pip install requests pymysql

同时确保本地已安装MySQL数据库,并创建好对应的数据库(本文中数据库名为vegetables),后续代码会基于该数据库创建数据表。

步骤2:数据库连接与数据表创建

首先实现MySQL数据库的连接,并创建用于存储价格数据的数据表。数据表需要包含农产品分类、名称、价格区间、规格、产地、发布日期等字段。

python 复制代码
import pymysql

# 连接MySQL数据库
conn = pymysql.connect(
    host='localhost',  # 数据库主机地址,本地为localhost
    user='root',       # 数据库用户名
    password='123456', # 数据库密码
    database='vegetables' # 提前创建的数据库名
)
cursor = conn.cursor()

# 创建数据表SQL语句
sql_create_table = """
CREATE TABLE IF NOT EXISTS xinfadi (
    id INT(11) NOT NULL AUTO_INCREMENT,
    category1 VARCHAR(255),  # 一级分类
    category2 VARCHAR(255),  # 二级分类
    name VARCHAR(255),       # 农产品名称
    low_price FLOAT,         # 最低价
    high_price FLOAT,        # 最高价
    avg_price FLOAT,         # 平均价
    spec_info VARCHAR(255),  # 规格信息
    place VARCHAR(255),      # 产地
    unit_info VARCHAR(255),  # 单位
    pub_date DATE,           # 发布日期
    PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
"""
# 执行创建表操作
cursor.execute(sql_create_table)

步骤3:编写爬虫核心函数

核心逻辑是调用新发地的价格数据接口,循环获取多页数据,解析后插入数据库。需要注意设置请求头模拟浏览器访问,避免被网站拦截。

python 复制代码
import requests
import json
import time

def crawl_and_store_data(db_conn, db_cur, page_start, page_end):
    # 请求头,模拟浏览器访问
    head = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
        'Referer': 'http://www.xinfadi.com.cn/priceDetail.html'
    }

    # 循环爬取指定页码范围的内容
    for page in range(page_start, page_end + 1):
        url = 'http://www.xinfadi.com.cn/getPriceData.html'
        # 构造请求参数
        params = {
            'limit': 20,
            'current': page,
            'pubDateStartTime': "",
            'pubDateEndTime': "",
            'prodPcatid': "",
            'prodCatid': "",
            'prodName': "",
        }
        # 发送POST请求获取数据
        resp = requests.post(url, headers=head, data=params).text
        # 解析JSON数据
        resp_json = json.loads(resp)
        list_json = resp_json['list']
        
        # 遍历解析后的每条数据
        for i in list_json:
            try:
                # 提取字段,为空时赋值空字符串
                category1 = i['prodCat'] or ''
                category2 = i['prodPcat'] or ''
                name = i['prodName']
                low_price = i['lowPrice']
                high_price = i['highPrice']
                avg_price = i['avgPrice']
                spec_info = i['specInfo'] or ''
                place = i['place'] or ''
                unit_info = i['unitInfo'] or ''
                pub_date = i['pubDate']
                
                # 打印数据,方便调试
                print(category1, category2, name, low_price, high_price, avg_price, spec_info, place, unit_info, pub_date)

                # 插入数据到MySQL的SQL语句
                sql_insert_data = """
                INSERT INTO xinfadi (category1, category2, name, low_price, high_price, avg_price, spec_info, place, unit_info, pub_date)
                VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                """
                # 执行插入操作
                db_cur.execute(sql_insert_data, (
                    category1, category2, name, low_price, high_price, avg_price, spec_info, place, unit_info, pub_date
                ))
                # 提交事务
                db_conn.commit()

            except Exception as e:
                # 捕获异常并打印,休眠0.5秒避免频繁请求
                print(f"数据处理异常:{e}")
                time.sleep(0.5)

    return True

步骤4:执行爬虫并释放资源

调用核心爬虫函数,指定爬取的页码范围(本文爬取1-20页),爬取完成后关闭数据库游标和连接,释放资源。

python 复制代码
try:
    # 调用爬虫函数,爬取1-20页数据
    status = crawl_and_store_data(conn, cursor, 1, 20)
    if status:
        print("数据爬取完成!")
except Exception as e:
    print(f"爬取过程异常:{e}")

# 关闭游标和连接
cursor.close()
conn.close()

完整代码整合

将上述代码整合,补充编码声明等细节,完整代码如下(编码设置为gbk适配中文,避免乱码):

python 复制代码
# coding=gbk
import pymysql
import requests
import json
import time

def crawl_and_store_data(db_conn, db_cur, page_start, page_end):
    head = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
        'Referer': 'http://www.xinfadi.com.cn/priceDetail.html'
    }

    for page in range(page_start, page_end + 1):
        url = f'http://www.xinfadi.com.cn/getPriceData.html'
        params = {
            'limit': 20,
            'current': page,
            'pubDateStartTime': "",
            'pubDateEndTime': "",
            'prodPcatid': "",
            'prodCatid': "",
            'prodName': "",
        }
        resp = requests.post(url, headers=head, data=params).text
        resp_json = json.loads(resp)
        list_json = resp_json['list']
        for i in list_json:
            try:
                category1 = i['prodCat'] or ''
                category2 = i['prodPcat'] or ''
                name = i['prodName']
                low_price = i['lowPrice']
                high_price = i['highPrice']
                avg_price = i['avgPrice']
                spec_info = i['specInfo'] or ''
                place = i['place'] or ''
                unit_info = i['unitInfo'] or ''
                pub_date = i['pubDate']
                print(category1, category2, name, low_price, high_price, avg_price, spec_info, place, unit_info,
                      pub_date)

                sql_insert_data = """
                INSERT INTO xinfadi (category1, category2, name, low_price, high_price, avg_price, spec_info, place, unit_info, pub_date)
                VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                """
                db_cur.execute(sql_insert_data, (
                category1, category2, name, low_price, high_price, avg_price, spec_info, place, unit_info, pub_date))
                db_conn.commit()

            except Exception as e:
                print(e)
                time.sleep(0.5)

    return True

# 连接MySQL数据库
conn = pymysql.connect(host='localhost', user='root', password='123456', database='vegetables')
cursor = conn.cursor()

# 创建数据表
sql_create_table = """
CREATE TABLE IF NOT EXISTS xinfadi (
    id INT(11) NOT NULL AUTO_INCREMENT,
    category1 VARCHAR(255),
    category2 VARCHAR(255),
    name VARCHAR(255),
    low_price FLOAT,
    high_price FLOAT,
    avg_price FLOAT,
    spec_info VARCHAR(255),
    place VARCHAR(255),
    unit_info VARCHAR(255),
    pub_date DATE,
    PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
"""
cursor.execute(sql_create_table)

# 爬取并存储数据
try:
    status = crawl_and_store_data(conn, cursor, 1, 20)
    if status:
        print("数据爬取完成!")
except Exception as e:
    print(e)

# 关闭数据库连接
cursor.close()
conn.close()

注意事项与优化方向

注意事项

  1. 请求频率控制 :本文在异常处理中加入了time.sleep(0.5),实际使用中可根据网站反爬规则调整请求间隔,避免过于频繁的请求导致IP被封禁。
  2. 编码问题 :代码开头设置# coding=gbk,数据库表设置CHARSET=utf8,确保中文数据正常存储,避免乱码。
  3. 异常处理:代码中对数据解析和插入过程做了异常捕获,但可进一步细化异常类型(如数据库连接异常、请求超时异常等),提升程序鲁棒性。
  4. 数据库权限:确保连接MySQL的用户有足够的权限(如创建表、插入数据),避免权限不足导致操作失败。

优化方向

  1. 增量爬取 :当前代码爬取指定页码的全部数据,可增加按日期筛选的逻辑(利用pubDateStartTimepubDateEndTime参数),实现增量爬取,避免重复数据。
  2. 多线程/异步爬取 :对于大量数据爬取,可使用threading多线程或aiohttp异步请求,提升爬取效率。
  3. 数据去重:在插入数据前增加去重逻辑(如根据农产品名称、规格、日期等字段判断),避免数据库中出现重复数据。
  4. 日志记录 :替换print语句为logging模块,将爬取日志、异常信息记录到文件,方便后续排查问题。
  5. 配置文件化 :将数据库连接信息、爬取页码范围、请求头信息等写入配置文件(如config.ini),提升代码的可维护性。

总结

本文通过Python实现了北京新发地农产品价格数据的爬取与MySQL存储,涵盖了网络请求、JSON解析、数据库操作等核心知识点。该方案不仅能满足基础的爬取需求,还可根据实际场景进行扩展优化,适用于农产品价格分析、市场监控等业务场景。希望本文能帮助大家掌握爬虫与数据库结合的实战技巧,也欢迎大家基于此代码进行更深入的二次开发。

相关推荐
m0_743297422 小时前
将Python Web应用部署到服务器(Docker + Nginx)
jvm·数据库·python
一直都在5722 小时前
JSoup:Java 处理 HTML 的实用利器,从基础到实战爬取教程
java·python·html
EnCi Zheng2 小时前
P1B-Python环境配置基础完全指南-Windows系统安装与验证
开发语言·windows·python
小陈phd2 小时前
多模态大模型学习笔记(十九)——基于 LangChain+Faiss的本地知识库问答系统实战
开发语言·c#
重庆兔巴哥2 小时前
如何检查Java环境变量是否配置成功?
java·开发语言
moxiaoran57532 小时前
MySQL分库分表的实现(二)--水平分表
数据库·mysql
yue0082 小时前
C#读取App.Config配置文件
开发语言·c#
亚林瓜子2 小时前
AWS RDS创建ReadLatency,WriteLatency,DBLoad,AuroraVolumeBytesLeftTotal四种指标告警
mysql·aws·aurora·alarm·cloudwatch·rds·cw
小小怪7502 小时前
实战:用Python开发一个简单的区块链
jvm·数据库·python