Python中如何处理天天基金API返回的JS格式数据?

http://fundgz.1234567.com.cn/js/003095.js

例如这个基金,怎么使用不同键下边的键值?
Python中如何处理天天基金API返回的JS格式数据?

6 回复

这个应该是 JSONP 用的,你搜索一下看看爬虫怎么应对 JSONP 就好了,网上肯定有的


遇到天天基金API返回JS格式数据的情况,通常是因为数据被包装在JavaScript回调函数中(比如jsonpCallback(...))。处理这种数据的关键是提取出其中的JSON部分。

这里提供一个完整的解决方案:

import re
import json
import requests

def parse_js_callback_data(js_text):
    """
    从JS回调函数中提取JSON数据
    
    参数:
        js_text: 包含JS回调函数的字符串,如 'jsonpCallback({...})'
    
    返回:
        解析后的Python字典
    """
    # 方法1:使用正则表达式提取JSON部分
    # 匹配花括号 {} 之间的内容,包括嵌套结构
    pattern = r'\{.*\}'
    match = re.search(pattern, js_text, re.DOTALL)
    
    if match:
        json_str = match.group()
        try:
            return json.loads(json_str)
        except json.JSONDecodeError:
            # 如果直接解析失败,尝试清理数据
            return parse_js_callback_advanced(js_text)
    
    return None

def parse_js_callback_advanced(js_text):
    """
    更健壮的解析方法,处理各种JS格式
    """
    # 移除函数调用包装
    if '(' in js_text and ')' in js_text:
        # 找到第一个 '(' 和最后一个 ')' 之间的内容
        start = js_text.find('(') + 1
        end = js_text.rfind(')')
        json_str = js_text[start:end].strip()
        
        # 清理可能的JavaScript注释和尾随分号
        json_str = re.sub(r'//.*', '', json_str)  # 移除单行注释
        json_str = re.sub(r'/\*.*?\*/', '', json_str, flags=re.DOTALL)  # 移除多行注释
        json_str = json_str.rstrip(';')  # 移除尾部分号
        
        try:
            return json.loads(json_str)
        except json.JSONDecodeError as e:
            print(f"JSON解析错误: {e}")
            print(f"原始数据: {json_str[:200]}...")  # 打印前200字符用于调试
            return None

# 使用示例
def fetch_fund_data(fund_code):
    """
    获取基金数据示例
    """
    # 示例URL(实际URL需要替换)
    url = f"https://fundgz.1234567.com.cn/js/{fund_code}.js"
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    }
    
    try:
        response = requests.get(url, headers=headers, timeout=10)
        response.encoding = 'utf-8'
        
        if response.status_code == 200:
            # 解析JS格式数据
            data = parse_js_callback_data(response.text)
            return data
        else:
            print(f"请求失败,状态码: {response.status_code}")
            return None
            
    except requests.RequestException as e:
        print(f"网络请求错误: {e}")
        return None

# 测试代码
if __name__ == "__main__":
    # 示例基金代码
    fund_code = "110022"  # 易方达消费行业
    
    data = fetch_fund_data(fund_code)
    
    if data:
        print("解析成功!")
        print(f"基金名称: {data.get('name', 'N/A')}")
        print(f"当前净值: {data.get('dwjz', 'N/A')}")
        print(f"估算涨幅: {data.get('gszzl', 'N/A')}%")
    else:
        print("数据获取或解析失败")

代码说明:

  1. 核心解析函数 parse_js_callback_data

    • 使用正则表达式 r'\{.*\}' 匹配花括号内的所有内容(包括嵌套)
    • re.DOTALL 标志让 . 匹配换行符,处理多行JSON
  2. 备用解析方法 parse_js_callback_advanced

    • 通过查找 () 来定位JSON数据
    • 清理JavaScript注释和尾随分号
    • 提供更健壮的解析
  3. 实际应用 fetch_fund_data

    • 模拟真实请求场景
    • 添加合适的请求头(User-Agent)
    • 处理网络异常

常见JS格式示例:

// 格式1:标准JSONP
jsonpCallback({"fundcode":"110022","name":"易方达消费行业"})

// 格式2:带分号
callback({"data": {...}});

// 格式3:带注释
/* 基金数据 */
getData({ "fund": {...} })

如果遇到特殊格式:

  • 如果数据是 var data = {...} 格式,可以搜索 '=' 后的内容
  • 如果包含特殊字符,可能需要先进行转义处理
  • 某些API可能使用不同的回调函数名,需要相应调整

一句话总结:用正则或字符串切割提取JS回调中的JSON,再用json.loads解析。

其实就简单的去头去尾就可以了,然后当 json 来处理。因为在网页当中 JSONP 也是这么使用的,回调函数必须与约定的一致。最多也就最后有没有分号的差别。

jsonp 啊兄弟

JSONP 只是把 json 包装了一层 你把包装层去掉就行了

可以,明白了,已经完美解决。可惜的是为什么美人把它做成个库,直接调用就行。

回到顶部