Metadata-Version: 2.4
Name: jupyter-data-fetch
Version: 0.3.0
Summary: fetch data from jupyter notebook
License-File: LICENSE
Requires-Python: >=3.9
Requires-Dist: jupyter-kernel-client>=1.0.0
Requires-Dist: pandas<3.0
Requires-Dist: pillow
Provides-Extra: playwright
Requires-Dist: loguru; extra == 'playwright'
Requires-Dist: playwright; extra == 'playwright'
Requires-Dist: playwright-stealth; extra == 'playwright'
Requires-Dist: psutil; extra == 'playwright'
Description-Content-Type: text/markdown

# jupyter-data-fetch

从`JupyterLab`、`Jupyter Notebook`、`Kaggle`、`Google Colab`、`VSCode网页版/code-server`中抓取数据的示例

## 优点

1. 通用性强，理论上全平台通用
2. 无需中转服务器，能打开网页就能使用

## 安装

1. `uv pip install jupyter-data-fetch -U -i https://mirrors.aliyun.com/pypi/simple` # Jupyter消息协议版
2. `uv pip install jupyter-data-fetch[playwright] -U -i https://mirrors.aliyun.com/pypi/simple` # playwright网页自动化版

## Jupyter消息协议版(通用)

1. 根据Jupyter消息协议，模拟浏览器直接连接服务器进行代码的执行和获取，效率高
2. 支持`JupyterLab`、`Jupyter Notebook`、`Kaggle`、`Google Colab`等
3. 参考[examples/message](examples/message)

## Jupyter消息协议 + HTTP下载版(速度快)

1. 在数据获取阶段，不通过网页展示提取数据，而是得到下载地址后HTTP下载
2. 直接是二进制，不用`base64/base85`编码，文件小下载快。适合大文件。但每个网站都需要针对性调整
3. 部分平台由于权限问题，服务器上临时文件可能需要手工删除
4. 部分平台`HTTP`下载有流量限制。请换回通用版。如：`SuperMind`
5. 部分平台使用`blob`传输文件。请换回通用版。如：`Kaggle`、`Google Colab`
6. 参考[examples/download](examples/download)

## playwright网页自动化版(全能但低效)

1. 网页自动化控制，通用性更高，额外支持`VSCode网页版/code-server`
2. 暂时不支持的网站也可以定制开发
3. 效率较低，因为多了网页渲染
4. 参考[examples/automation](examples/automation)

## 使用方法

1. `examples`下提供了示例
2. 以`joinquant`为例，打开浏览器，登录研究环境，按`F12`或`Ctrl+Shift+I`打开开发者工具
3. 搜索`kernels`，复制`Cookie`
   ![devtool.png](docs/devtool.png)
4. 替换示例中`COOKIE`即可
   ![ide.png](docs/ide.png)
5. 会自动从`COOKIE`提取`用户ID`，并更新`SERVER_URL`

## 最简示例

```python
from jupyter_kernel_client import KernelClient

from jupyter_data_fetch.codec import TextCodec
from jupyter_data_fetch import extract_from_reply

# ... 省去部分代码。更多参考examples/message/joinquant.py

with KernelClient(server_url="https://www.joinquant.com/user/12345678901", token=None, headers=headers) as kernel:
    # 一定要保证缩进正确
    code = """
df = get_fundamentals(query(
        valuation, income
    ).filter(
        # 这里不能使用 in 操作, 要使用in_()函数
        valuation.code.in_(['000001.XSHE', '600000.XSHG'])
    ), date='2015-10-15')
"""
    reply = kernel.execute(TextCodec.generate_code(code, var_name='df'), store_history=False)
    print(reply)
    obj = TextCodec.decode(extract_from_reply(reply))
    print(obj)

```

## 常用API的封装

实际开发时并不会每次都手工构造`code`,会将函数封装。例如

```python
# jupyter_data_fetch/wraps/jqdatasdk.py
from jupyter_data_fetch import LazyCodec, LazyDownloader


# ======== 使用coder解码数据 ============
# 调用示例 examples/message/jqdatasdk.py
def get_industry(security, date=None):
    code = f"""_ = get_industry({repr(security)}, {repr(date)})"""
    code = LazyCodec.generate_code(code, var_name='_')
    # print(code)
    reply = LazyCodec.execute(code, store_history=False)
    return LazyCodec.decode_from_reply(reply)


# ======== 使用downloader下载数据，遇到流量限制还是换回codec解码 ============
# 调用示例 examples/download/joinquant.py
def get_all_securities(types=[], date=None):
    code = f"""_ = get_all_securities({repr(types)}, {repr(date)})"""
    code = LazyDownloader.generate_code(code, var_name='_')
    # print(code)
    reply = LazyDownloader.execute(code, store_history=False)
    return LazyDownloader.reply_down_replace_load(reply, show_progress=True, dst=None, load=True)

```

参考[jupyter_data_fetch/wraps/jqdatasdk.py](jupyter_data_fetch/wraps/jqdatasdk.py)

也可以封装更复杂的代码为简单函数，例如：[jqresearch_query_client.py](https://github.com/wukan1986/ddump/blob/main/examples/jqresearch2/jqresearch_query_client.py)

## 自动登录并获取数据的完整示例

参考[examples/experimental/cookie_playwright.py](examples/experimental/cookie_playwright.py)

## 核心代码

1. `TextCodec`: 目前使用`base85`编解码器，使用字符串传输数据，压缩率高。如果字符串被截断，必须使用`ImageCodec`
2. `ImageCodec`: 图片编解码器，使用图片传输数据，`base64`编码压缩率低
3. `generate_code`生成可在`Notebook`单元格中运行的代码字符串，一定要指定需要获取的变量名`var_name`
4. `kernel.execute`在服务段执行字符串代码，返回`json`对象
5. `extract_from_reply`从`json`中提取数据
6. `decode`字符串解码成对象

## 注意

1. 由于各平台限制，`generate_code`生成的代码可能无法运行，可以复制到`Notebook`中测试
2. `python3.6`问题太多，可以打开一个`ipynb`文件后，通过菜单更改内核为最新版
3. 可以连接到已经打开的内核，只要提供`kernel_id`参数即可。参考`ricequant.py`示例
4. `Notebook`中可以导入当前目录中`py`，但本项目直接使用当前目录是`/`，导致导入失败，通过指定`kernel_id`可解决