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

AGMARKNET网站多页面表格数据爬取求助

爬取AGMARKNET多页表格数据的问题

我尝试从AGMARKNET网站爬取苹果在查谟和克什米尔地区的历史价格数据,目标表格分为11页,但所有页面使用同一URL。作为网页爬取和Python新手,因为网站没有公开API,只能通过爬取页面获取数据。目前用BeautifulSoup只能爬取第一页的500条数据,无法获取全部11页的完整数据,求解决方向。

目标链接:
https://agmarknet.gov.in/SearchCmmMkt.aspx?Tx_Commodity=17&Tx_State=JK&Tx_District=0&Tx_Market=0&DateFrom=01-Oct-2004&DateTo=18-Oct-2022&Fr_Date=01-Oct-2004&To_Date=18-Oct-2022&Tx_Trend=2&Tx_CommodityHead=Apple&Tx_StateHead=Jammu+and+Kashmir&Tx_DistrictHead=--Select--&Tx_MarketHead=--Select--

当前代码:

import requests
import pandas as pd
from bs4 import BeautifulSoup  # 补充原代码缺失的导入

url = 'https://agmarknet.gov.in/SearchCmmMkt.aspx?Tx_Commodity=17&Tx_State=JK&Tx_District=0&Tx_Market=0&DateFrom=01-Oct-2004&DateTo=18-Oct-2022&Fr_Date=01-Oct-2004&To_Date=18-Oct-2022&Tx_Trend=2&Tx_CommodityHead=Apple&Tx_StateHead=Jammu+and+Kashmir&Tx_DistrictHead=--Select--&Tx_MarketHead=--Select--'

response = requests.get(url)

# 解析HTML
soup = BeautifulSoup(response.content, 'html.parser')

# 定位目标表格并转为Tag对象
stat_table = soup.find_all('table', {'class': 'tableagmark_new'})
stat_table = stat_table[0]

# 提取表格数据到列表
rows = []
for tr in stat_table.find_all('tr')[1:]:
    cells = []
    tds = tr.find_all('td')
    if len(tds) == 0:
        ths = tr.find_all('th')
        for th in ths:
            cells.append(th.text.strip())
    else:
        for td in tds:
            cells.append(td.text.strip())
    rows.append(cells)

# 转为DataFrame
table = pd.DataFrame(rows)

解决方向

这类ASP.NET网站的分页不依赖URL参数跳转,而是通过POST请求提交ViewState等隐藏验证字段加载新页面,具体实现步骤如下:

  1. 提取页面核心隐藏字段
    第一次GET请求后,从页面中提取ASP.NET验证必需的三个字段:__VIEWSTATE、__VIEWSTATEGENERATOR、__EVENTVALIDATION,这些值每次页面刷新都会变化,必须动态获取:

    viewstate = soup.find('input', {'id': '__VIEWSTATE'})['value']
    viewstategenerator = soup.find('input', {'id': '__VIEWSTATEGENERATOR'})['value']
    eventvalidation = soup.find('input', {'id': '__EVENTVALIDATION'})['value']
    
  2. 构造分页POST请求参数
    通过浏览器开发者工具(F12)查看分页按钮的网络请求,复制Form Data中的所有参数,其中关键的分页参数是:

    • __EVENTTARGET:分页控件的ID(比如ctl00$ContentPlaceHolder1$gvResults)
    • __EVENTARGUMENT:分页指令(比如Page$2表示第2页)
      同时需要保留原查询的商品、地区、日期等固定参数。
  3. 循环爬取所有页面

    • 使用requests.Session()保持会话,避免重复建立连接
    • 初始化空DataFrame存储全量数据
    • 循环遍历1到11页,每次提交POST请求后,更新隐藏字段值,解析当前页表格数据并追加到全量DataFrame中
    • 添加请求延迟(如time.sleep(1)),防止请求频率过高被封禁
  4. 完整示例代码

import time
import requests
import pandas as pd
from bs4 import BeautifulSoup

base_url = 'https://agmarknet.gov.in/SearchCmmMkt.aspx?Tx_Commodity=17&Tx_State=JK&Tx_District=0&Tx_Market=0&DateFrom=01-Oct-2004&DateTo=18-Oct-2022&Fr_Date=01-Oct-2004&To_Date=18-Oct-2022&Tx_Trend=2&Tx_CommodityHead=Apple&Tx_StateHead=Jammu+and+Kashmir&Tx_DistrictHead=--Select--&Tx_MarketHead=--Select--'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36'
}

# 初始化全量数据容器
all_data = pd.DataFrame()

# 建立会话并获取初始页面参数
session = requests.Session()
response = session.get(base_url, headers=headers)
soup = BeautifulSoup(response.content, 'html.parser')

# 提取初始验证字段
viewstate = soup.find('input', {'id': '__VIEWSTATE'})['value']
viewstategenerator = soup.find('input', {'id': '__VIEWSTATEGENERATOR'})['value']
eventvalidation = soup.find('input', {'id': '__EVENTVALIDATION'})['value']

# 解析第一页数据
stat_table = soup.find_all('table', {'class': 'tableagmark_new'})[0]
rows = []
for tr in stat_table.find_all('tr')[1:]:
    cells = []
    tds = tr.find_all('td')
    if len(tds) == 0:
        ths = tr.find_all('th')
        for th in ths:
            cells.append(th.text.strip())
    else:
        for td in tds:
            cells.append(td.text.strip())
    rows.append(cells)
df_page = pd.DataFrame(rows[1:], columns=rows[0])
all_data = pd.concat([all_data, df_page], ignore_index=True)

# 循环爬取第2到11页
for page_num in range(2, 12):
    time.sleep(1)
    # 构造POST请求参数
    form_data = {
        '__VIEWSTATE': viewstate,
        '__VIEWSTATEGENERATOR': viewstategenerator,
        '__EVENTVALIDATION': eventvalidation,
        '__EVENTTARGET': 'ctl00$ContentPlaceHolder1$gvResults',
        '__EVENTARGUMENT': f'Page${page_num}',
        'ctl00$ContentPlaceHolder1$ddlCommodity': '17',
        'ctl00$ContentPlaceHolder1$ddlState': 'JK',
        'ctl00$ContentPlaceHolder1$ddlDistrict': '0',
        'ctl00$ContentPlaceHolder1$ddlMarket': '0',
        'ctl00$ContentPlaceHolder1$txtDateFrom': '01-Oct-2004',
        'ctl00$ContentPlaceHolder1$txtDateTo': '18-Oct-2022',
        'ctl00$ContentPlaceHolder1$ddlTrend': '2'
    }
    
    # 发送POST请求并解析页面
    response = session.post(base_url, data=form_data, headers=headers)
    soup = BeautifulSoup(response.content, 'html.parser')
    
    # 更新验证字段
    viewstate = soup.find('input', {'id': '__VIEWSTATE'})['value']
    viewstategenerator = soup.find('input', {'id': '__VIEWSTATEGENERATOR'})['value']
    eventvalidation = soup.find('input', {'id': '__EVENTVALIDATION'})['value']
    
    # 解析当前页数据
    stat_table = soup.find_all('table', {'class': 'tableagmark_new'})[0]
    rows = []
    for tr in stat_table.find_all('tr')[1:]:
        cells = []
        tds = tr.find_all('td')
        if len(tds) == 0:
            ths = tr.find_all('th')
            for th in ths:
                cells.append(th.text.strip())
        else:
            for td in tds:
                cells.append(td.text.strip())
        rows.append(cells)
    df_page = pd.DataFrame(rows[1:], columns=rows[0])
    all_data = pd.concat([all_data, df_page], ignore_index=True)

# 保存数据到CSV
all_data.to_csv('agmarknet_apple_data.csv', index=False)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 09:55:20