惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
S
Security Affairs
阮一峰的网络日志
阮一峰的网络日志
L
LangChain Blog
Microsoft Azure Blog
Microsoft Azure Blog
雷峰网
雷峰网
Recent Announcements
Recent Announcements
WordPress大学
WordPress大学
The GitHub Blog
The GitHub Blog
博客园_首页
The Cloudflare Blog
M
MIT News - Artificial intelligence
博客园 - 【当耐特】
MyScale Blog
MyScale Blog
S
SegmentFault 最新的问题
P
Proofpoint News Feed
Y
Y Combinator Blog
Jina AI
Jina AI
博客园 - 聂微东
A
About on SuperTechFans
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
G
Google Developers Blog
云风的 BLOG
云风的 BLOG
F
Full Disclosure
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Microsoft Security Blog
Microsoft Security Blog
爱范儿
爱范儿
T
Tailwind CSS Blog
J
Java Code Geeks
Vercel News
Vercel News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Stack Overflow Blog
Stack Overflow Blog
罗磊的独立博客
小众软件
小众软件
酷 壳 – CoolShell
酷 壳 – CoolShell
T
The Blog of Author Tim Ferriss
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - 三生石上(FineUI控件)
W
WeLiveSecurity
PCI Perspectives
PCI Perspectives
Attack and Defense Labs
Attack and Defense Labs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
宝玉的分享
宝玉的分享
IT之家
IT之家
Hacker News: Ask HN
Hacker News: Ask HN
The Register - Security
The Register - Security
T
The Exploit Database - CXSecurity.com
T
Threat Research - Cisco Blogs

夜行人

回家路上 第一期的直播演示项目 震动检测器 正能量 在线参观CodeLab Neverland 发布 CodeLab Adapter 3.3.1 DynamicTable 之 纸糊方向盘 CodeLab DynamicTable: 一个可实施的技术方案 CodeLab Insight 发布 Alpha 版 情人节 Home Assistant 周报 && IoT 周报 (02) Joplin: 关注隐私的 Evernote 开源替代软件 浏览器的未来与 Web 传感器 Home Assistant 周报 && IoT 周报 (01) 百宝箱(01) 论自由 介绍 WebThings Home Assistant 周报 && iot 周报 (00) 百宝箱(00) 毛姆读书心得 传世之作 周末徒步 CodeLab Adapter ❤️ Jupyter/Python 航班 躲雨 夏令营途中 [译]思想--作为一种技术 The future of coding 美国之行 三门问题的程序模拟 从Python转向Pharo https://blog.just4fun.site/post/iot/iot-open-source-projects/ Python异步编程笔记 https://blog.just4fun.site/post/iot/iot-open-source-hardware-community/ 万物积木化开发者社区 CodeLab ❤️ Blender Scratch3技术分析之云变量 API(第7篇) [译]对管道(Pipes)的偏爱 [译]提出正确的问题比得到正确答案更重要 蓝牙设备与Scratch3.0 创建你的第一个Scratch3.0 Extension Scratch3技术分析之项目内部数据(第6篇) Scratch3技术分析之社区 API(第5篇) Scratch3技术分析之User API(第4篇) Scratch3技术分析之项目主页API(第3篇) Scratch3技术分析之静态资源API(第2篇) Scratch3.0、micro:bit与Windows7 https://blog.just4fun.site/post/iot/zerynth-vs-micropython/ 核聚变、方所与半宅空间 可视化编程为何是个糟糕的主意 codelab.club周末聚会 关于codelab.club '下一件大事'是一个房间 Hungry Robot - Eat everything 编程作为一种思考方式 今日简史 史蒂夫·乔布斯传 罗素自选文集 https://blog.just4fun.site/post/edx/tianjin-scratch-ai/ https://blog.just4fun.site/post/edx/richie-cms-openedx/ 徒步武功山 WebUSB与micro:bit 积木化编程与3D场景 夜宿武功山顶 scratch3-adapter接入优必选Alpha系列机器人 https://blog.just4fun.site/post/edx/video-migration-note/ scratch3-adapter重构笔记 https://blog.just4fun.site/post/edx/edx-community-members/ 两种硬件编程风格的比较 使用micro:bit自制PPT翻页笔 柏拉图对话集 scratch3.0 + micro:bit 七月电影放映计划 非营利组织的管理 Screenly--用树莓派让任何屏幕变为可编程的数字标牌 以最佳实践开始你的Django项目 micro:bit与事件驱动 为Scratch3.0设计的插件系统(上篇) OCR应用一例 近两年读过的一些好书 blockly开发之使用python驱动浏览器中的turtle(2) 牛顿新传 文学理论入门 逻辑的引擎 人生的意义 blockly开发之生成并运行js代码(1) blockly开发之hello world(0) micro:bit使用笔记 神器之Termux https://blog.just4fun.site/post/iot/micropython-notes/ Cozmo what is this Scratch的前世今生 下段旅程 我行在远方 爆裂 途中杂记 https://blog.just4fun.site/post/edx/open-edx-startup/ cozmo系列之入门 - 有性格且可编程的机器人 PaperWeekly开发笔记 创业二三事
对jupyter notebook的分析、扩展与hack
种瓜 · 2017-03-22 · via 夜行人

文章目录

大纲

本文关心代码在jupyter notebook里从前端传往后端的过程,并试图获取到钩子,因为我最近项目的缘故(可以参考我之前的文章),分析完通信过程,我将演示如何扩展和hack jupyter notebook

在接下来动手实践部分将演示如何将其以iframe嵌入到外部网页网页中(在概念上是嵌入一种资源)

实验环境

  • ubuntu 14.04
  • python 2.7.6
  • jupyter 4.3.0

安装jupyter(notebook)

1
2
3
virtualenv env
. env/bin/activate
pip install jupyter #  安装完后是4.3

运行

jupyter notebook --no-browser --port 5000 --ip=0.0.0.0

我将其跑在5000端口,并接收所有ip的请求

关于启动参数,不熟悉的同学可以参考我之前文章

值得注意的是第一次手动登陆,需要输入token,如果你没加入–no-brower,会自动打开http://127.0.0.1:5000/?token=d311b2834ac7337157c54aaba8d9a524ce48f7597c91xxxx,验证一次之后,浏览器就有cookie了,之后只需要127.0.0.1:5000就可访问

分析

从websocket入手

打开一个新的notebook: http://127.0.0.1:5000/notebooks/Untitled1.ipynb

从chrome调试面板的Network可以看到,有个websocket:ws://127.0.0.1:5000/api/kernels/d13a50b0-6baa-4d5e-8564-95f224daxxxx/channels?session_id=F552491A7C0448A2B5567DE1A71Cxxxx,代码经由它往后端发送,也经由它接收后台返回的信息

当我们运行上头的print(“hello world”)时,往后台发送如下数据

1
{"header":{"msg_id":"29A5EFC0B11848BE97B66D6E947AEB71","username":"username","session":"7C49DDC342FD43AA8F5624B08CD7BDAB","msg_type":"execute_request","version":"5.0"},"metadata":{},"content":{"code":"print(\"hello world\")","silent":false,"store_history":true,"user_expressions":{},"allow_stdin":true,"stop_on_error":true},"buffers":[],"parent_header":{},"channel":"shell"}

接下来有5个frames

其中包含了代码执行的结果

那么我们只要模拟建立这样的websocket,就拿到所要的钩子了,可以自如地运行代码

从页面入手

除了建立websocket,我们也可以找找js中钩子

这个问题在stack overflow里找到解答,方法如下

1
2
3
4
5
6
7
8
var handle_output = function (data) {console.log(data);}

var callbacks = {
            iopub : {output : handle_output,}
}

var kernel = IPython.notebook.kernel;
kernel.execute("print('hello')",callbacks)

如此一来我们找到了第二种钩子

消息是用websocket传输的,你可以试试实时性:kernel.execute("for i in range(5):import time;time.sleep(1);print('hello')",callbacks)

嵌入到外部页面中

接下来的部分,演示如何将jupyter notebook嵌入到外部页面里,如此一来可以利用jupyter强大的特性做很多好玩的东西,诸如各种语言的线上IDE

首先建立一个前端页面(my_test.html),然后以iframe的方式引入jupyter notebook(关于iframe的属性可以参考这里),接下来在外部网页中与其互操作

从建立网页开始

1
2
3
4
5
6
7
8
9
<html>
<title>wwj</title>
<body>
<iframe width="600" height="400" id="notebook" src="http://127.0.0.1:5000/notebooks/Untitled1.ipynb?token=c81b15a38f4fdfebe67cab0400b9feb0e60325f35bafxxxx" ></iframe>
    <script>
    console.log("wwjtest")
    </script>
</body>
</html>

噢报错了,这个问题这里有描述:How do I embed an Ipython Notebook in an iframe,解决方案这个比较靠谱:Can’t use Notebook inside an iframe

解决方案是生成配置文件:jupyter notebook --generate-config,做些配置。往~/.jupyter/jupyter_notebook_config.py加入c.NotebookApp.tornado_settings = { 'headers': { 'Content-Security-Policy': "frame-ancestors 'self' *" } }

现在没有问题啦 (注意不要直接打开my_test.html,使用网络访问它(python -m SimpleHTTPServer))

采用postMessage来传递消息

因为jupyter与外部页面可能存在跨域问题(别怕,最复杂的情况,也就是跨域了),我打算采用HTML5 postMessage来处理这个问题

postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

往iframe里发送消息

1
2
3
var notebook = document.getElementById('notebook');
code="print('hello')";
notebook.contentWindow.postMessage(code,"*") ;

扩展jupyter notebook

为了在jupyter notebook中监听到外部网页发过来的消息,并给予响应,我们需要为其写js扩展,哈哈别紧张,jupyter设计得很漂亮,扩展它很简单(可能需要安装:pip install widgetsnbextension)

进入~/.ipython/nbextensions,

创建我们的扩展(iframe_extension.js):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
define(function(){
      function _on_load(){
            console.info('iframe extension running!')
            window.addEventListener('message', function(event){
            console.log("the iframe get:"+event.data);
            window.parent.postMessage("data from  iframe extension",'*');
      })
      }
    
    return {load_ipython_extension: _on_load };
})

在外部网页等待iframe的消息

1
2
3
4
window.addEventListener('message',function(e){
    var data=e.data;
    console.log("response from notebook:"+data);
},false);

大功告成!

文章作者 种瓜

上次更新 2017-03-22