PyscriptとはPythonがhtmlファイルで使えるものです。
HTML、CSS、JavaScriptの基本的な知識は必要です。
まだできたばかりで本番では使用しない方がいいようです。
htmlファイル一つ作ればいいだけなので開発環境はエディターだけで済みます。
実行環境はウェブプラウザ。
パソコンにPythonがインストールされてる必要はありません。
今回アーティスト名を入力したら
楽天APIでCD検索して結果を表示するプログラムを作りました。
Pyscriptの欠点として動き始めるまで時間がかかります。
下の完成品も動くまで下の方にloading runtime…と出てると思います。
それが消えるまで動作しません。
またAPIキー(APP_ID)をユーザーに送っているのでブラウザの標準機能で見えてしまうので注意です。
2025/2/1追記
動かなくなった。原因は以下のpyscriptファイルが読み込めていない(404エラー)。どうやら削除されたみたい。
違うところになったみたい。参考https://docs.pyscript.net/2024.11.1/beginning-pyscript/
さらに仕様も変更されているようです。
面倒なのでコードの修正はChatGptに聞いた。(内容は理解していない)
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
↓↓↓こちらに変更(2024.11.1版)
<link rel="stylesheet" href="https://pyscript.net/releases/2024.11.1/core.css">
<script type="module" src="https://pyscript.net/releases/2024.11.1/core.js"></script>
完成品 1番最後に機能アップ版もあります!
こちら↓↓もChatGptに聞いて直そうと思ったがうまくいかないので、サンプルを参考に調べて修正した。
生成AIに全面的に頼る危険性を改めて感じた!
Pyscriptとは
こちらのYoutubeが分かりやすいです。
【話題のPyScript!】HTMLファイルにPythonが書ける?!Webブラウザで動くPythonを解説!〜プログラム初心者用〜
基本的なHTMLコードに以下があれば動きます。
headタグの中に以下2行追加で使える。
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
↓↓↓こちらに変更
<link rel="stylesheet" href="https://pyscript.net/releases/2024.11.1/core.css">
<script type="module" src="https://pyscript.net/releases/2024.11.1/core.js"></script>
コードを書く場所、bodyタグ内。
<py-script>
pythonコード
</py-script>
↓↓↓こちらに変更?(2024.11.1版)、上のままでも動いた。
<script type="py">
pythonコード
</script>
その他、たいぶ使い方が変わっているので注意!
開発環境
開発環境はhtmlファイル一つだけで動くのでWindowsのメモ帳でも作れます。
メモ帳使うときは、保存するときにテキストファイルで保存しないように注意が必要です。
保存するときにファイルの種類をすべてに選択し
ファイル名は必ず*.htmlというファイル名で保存しましょう。
しかしメモ帳ではさすがにプログラミングには不便です。特にインテンド。
一般的にはパソコンにVSCodeなどのエディターをインストールして
プログラミングします。
Jsfidleというオンラインエディタだとパソコンに何もインストールする必要がありません。
実行は作ったhtmlファイルをウェブプラウザで開くだけです。
Pythonの実行環境を用意する必要がありません。
逆にJupiterNotebookでRunしても動かせません。
コード
requestsに関して
こちらを参考にさせていただきました。PyScriptを試してみました
requestsではrequests.get(request_url,params)のようにして
urlパラメータを連結できました。
open_urlは多分できないようなので
以下のようにurlのあとに?’キー’=’value’&’キー’=’value’という形でurlを作ります。
import urllib.parse
from pyodide.http import open_url
import json
省略
request_url='https://app.rakuten.co.jp/services/api/BooksCD/Search/20170404'
APP_ID='個人別コード'
params={'artistName':keyword,
'sort':'-releaseDate',
'applicationId':APP_ID}
url=request_url+'?'+'artistName='+urllib.parse.quote(keyword)+r'&sort='+'-releaseDate'+r'&applicationId='+APP_ID
res = json.loads(open_url(url).read())
(2025/2/1追記)上のコードは使っていません。詳細は下のhtmlファイル。
日本語になる可能性のある部分はurllib.parse.quoteにより%エンコードします。
%エンコードについては以下の記事を参考にしてください。
ソースコード
楽天APIのコード付きでサーバーにアップロードして運用すると
アクセスした人は誰でも楽天APIのコードが見れてしまうので注意してください。
楽天APIのコード部分はAPP_ID=’個人別コード’としてありますので
このままコピペしても動きません。
楽天APIの使い方は、Pythonで楽天トラベルAPIを使用した宿泊先リスト作成方法をわかりやすく解説!が分かりやすいです。
イチゲをOFUSEで応援する
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="description" content="Pyscriptを使って楽天APIでCD検索して結果を表示するプログラムを作りました。アーティスト名を入力して検索ボタンを押すと楽天ブックスCDの検索結果が新しい順に5件表示します。詳細はhttps://kikuichige.com/11630/"/>
<title>Pyscript+WebApi</title>
<link rel="stylesheet" href="https://pyscript.net/releases/2024.11.1/core.css">
<script type="module" src="https://pyscript.net/releases/2024.11.1/core.js"></script>
<style>
.cgap { display: grid; gap: 20px 20px; }
/* h1 { font-size: 200%; color: #ff0000; } */
h1{
font-size:200%;
color: #ff0000;
background-color: #ffffff;
}
a {color: skyblue; text-decoration: underline;}
.btn--orange,
a.btn--orange {
color: #fff;
background-color: #eb6100;
}
.btn--orange:hover,
a.btn--orange:hover {
color: #fff;
background: #f56500;
}
table { border-collapse: collapse; text-align: center; }
th, td { padding: 5px; border: 1px solid #333; }
th { background-color: #2c88d9; color: #FFF; }
</style>
</head>
<body>
<div style="display:flex; flex-flow: column; justify-content:center; margin: 6px 4px;">
<div class="cgap">
<h1>楽天ブックスCD検索APIを利用したアプリ</h1>
<div>
<input id="input_test" class="border">
<button id="btn" class="btn btn--orange">検索</button>
<p>入力例:babymetal</p>
</div>
<a href="//af.moshimo.com/af/c/click?a_id=3426884&p_id=54&pc_id=54&pl_id=1220&guid=ON" rel="nofollow" referrerpolicy="no-referrer-when-downgrade"><img src="//image.moshimo.com/af-img/0032/000000001220.gif" width="468" height="60" style="border:none;"></a><img src="//i.moshimo.com/af/i/impression?a_id=3426884&p_id=54&pc_id=54&pl_id=1220" width="1" height="1" style="border:none;">
<p>表示はするけど反応するまでに数十秒かかります。反応するようになってからは早いです。</p>
<p>このサイトの詳細は<a href="https://kikuichige.com/11630/">イチゲブログ</a></p>
<label id="mes"></label>
<table>
<tr><th>タイトル</th><th>楽天ブックスCDリンク</th></tr>
<tr><td><label id="0"></label></td><td><label id="10"></label></td></tr>
<tr><td><label id="1"></label></td><td><label id="11"></label></td></tr>
<tr><td><label id="2"></label></td><td><label id="12"></label></td></tr>
<tr><td><label id="3"></label></td><td><label id="13"></label></td></tr>
<tr><td><label id="4"></label></td><td><label id="14"></label></td></tr>
</table>
</div>
<script type="py">
import json
import urllib.parse
from pyodide.http import pyfetch
from js import document
from pyodide.ffi import create_proxy # ✅ 追加:関数の参照を保持するため
async def searchCD(event):
input_element = document.getElementById("input_test")
keyword = input_element.value.strip()
input_element.value = "" # 入力欄をクリア
if not keyword:
document.getElementById("mes").innerText = "アーティスト名を入力してください"
return
request_url = "https://app.rakuten.co.jp/services/api/BooksCD/Search/20170404"
APP_ID='個人別コード'
params = {
"artistName": keyword,
"sort": "-releaseDate",
"applicationId": APP_ID
}
url = request_url + "?" + urllib.parse.urlencode(params)
try:
response = await pyfetch(url)
data = await response.json()
except Exception as e:
document.getElementById("mes").innerText = f"エラー: {str(e)}"
return
if "error" in data:
document.getElementById("mes").innerText = "APIエラー: データ取得に失敗しました"
return
items = data.get("Items", [])
if not items:
document.getElementById("mes").innerText = "該当するアーティストがいません"
return
# 検索結果の上位5件を取得
for i in range(min(5, len(items))):
item = items[i]["Item"]
title = item.get("title", "タイトルなし")
link = item.get("itemUrl", "#")
document.getElementById(str(i)).innerText = title
document.getElementById(str(i + 10)).innerHTML = f'<a href="{link}" target="_blank">リンク</a>'
document.getElementById("mes").innerText = "検索結果を表示しました"
# ✅ create_proxy を使って JavaScript に関数参照を保持
searchCD_proxy = create_proxy(searchCD)
document.getElementById("btn").addEventListener("click", searchCD_proxy)
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="description" content="Pyscriptを使って楽天APIでCD検索して結果を表示するプログラムを作りました。アーティスト名を入力して検索ボタンを押すと楽天ブックスCDの検索結果が新しい順に5件表示します。詳細はhttps://kikuichige.com/11630/"/>
<title>Pyscript+WebApi</title>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
<py-env>
</py-env>
<style type="text/css">
.cgap {
display: grid;
gap: 20px 20px;
}
h1{
font-size:200%;
color: #ff0000;
background-color: #ffffff;
}
a {color: skyblue; text-decoration: underline;}
.btn--orange,
a.btn--orange {
color: #fff;
background-color: #eb6100;
}
.btn--orange:hover,
a.btn--orange:hover {
color: #fff;
background: #f56500;
}
table {
border-collapse: collapse;
text-align: center;
}
th, td {
padding: 5px;
border: 1px solid #333;
}
th {
background-color: #2c88d9;
color: #FFF;
}
</style>
</head>
<body>
<div style="display:flex; flex-flow: column; justify-content:center; margin: 6px 4px;">
<div class="cgap">
<h1>
楽天ブックスCD検索APIを利用したアプリ
</h1>
<div>
<input id="input_test" class="border">
<button id="btn" class="btn btn--orange" pys-onClick="searchCD"> 検索 </button>
<p>入力例:babymetal</p>
</div>
<a href="//af.moshimo.com/af/c/click?a_id=3426884&p_id=54&pc_id=54&pl_id=1220&guid=ON" rel="nofollow" referrerpolicy="no-referrer-when-downgrade"><img src="//image.moshimo.com/af-img/0032/000000001220.gif" width="468" height="60" style="border:none;"></a><img src="//i.moshimo.com/af/i/impression?a_id=3426884&p_id=54&pc_id=54&pl_id=1220" width="1" height="1" style="border:none;">
<p>表示はするけど反応するまでに数十秒かかります。反応するようになってからは早いです。</p>
<p>このサイトの詳細は<a href="https://kikuichige.com/11630/">イチゲブログ</a></p>
<label id='mes'></label>
<table>
<tr><!-- 行1(見出し)-->
<th>タイトル</th> <th>楽天ブックスCDリンク</th>
</tr>
<tr>
<td><label id='0'></label></td> <td><label id='10'></label></td>
</tr>
<tr>
<td><label id='1'></label></td> <td><label id='11'></label></td>
</tr>
<tr>
<td><label id='2'></label></td> <td><label id='12'></label></td>
</tr>
<tr>
<td><label id='3'></label></td> <td><label id='13'></label></td>
</tr>
<tr>
<td><label id='4'></label></td> <td><label id='14'></label></td>
</tr>
</table>
</div></div>
<py-script>
import urllib.parse
from pyodide.http import open_url
import json
def searchCD(*ags, **kws):
input_test_element = Element("input_test")
input_word = input_test_element.element.value
input_test_element.clear() #処理後に入力フォームを空にする
keyword=repr(input_word)
test_text=''
request_url='https://app.rakuten.co.jp/services/api/BooksCD/Search/20170404'
APP_ID='個人別コード'
params={'artistName':keyword,
'sort':'-releaseDate',
'applicationId':APP_ID}
url=request_url+'?'+'artistName='+urllib.parse.quote(keyword)+r'&sort='+'-releaseDate'+r'&applicationId='+APP_ID
res = json.loads(open_url(url).read())
result=res
dic=[]
if 'error' in result:
test_text='失敗です!'
else:
if result['last'] !='':
suu=result['last']
else:
suu=0
for i in range(suu):
if (result['Items'][i]['Item']['smallImageUrl']!='' and result['Items'][i]['Item']['title']!='' and result['Items'][i]['Item']['itemUrl'] !=''):
dic.append(result['Items'][i]['Item']['title'])
dic.append(result['Items'][i]['Item']['itemUrl'])
if dic == []:
test_text='該当するアーティストがいません'
else:
dic1=dic[0::2]
dic2=dic[1::2]
for i in range(5):
pyscript.write(i,dic1[i])
pyscript.write(i+10,dic2[i])
pyscript.write("mes",test_text)
return
</py-script>
</body>
</html>
CORS
参考にさせていただいたPyScriptを試してみましたでCORSに関して触れています。
CORSとはCORSエラーで検索すると出てきます。
これは結構やっかいでパソコンにPyscript demoのサンプルをコピーして実行しようとするときも
このエラーに悩まされます。(pathsを使ってるサンプルの場合)
パソコンの場合、原因は多分ここで紹介されてる内容だと思います。
【Ajax】ローカルファイルを読み込もうとしたらCORSエラーが発生したので解決した
簡単な対策としてはファイルを分けないで
*.pyを<scriput></script>内に全部書いて読み込みに行かないようにするとうまくいきます。
エラーの確認方法はプラウザの検証ツールを使ってコンソールのところをクリックすると見れます。
クロームの場合は以下

今回使用した楽天APIは下のようにレスポンスが返ってきてます。
(ネットワーク→対象の通信を右クリック→コピー→レスポンスヘッダをコピーで見れます。)
どこのオリジンからの通信もOK(Access-Control-Allow-Origin: *)と設定されているようです。
なので何もしなくてもうまくいきます。
HTTP/1.1 200 200
Date: Fri, 13 May 2022 04:53:16 GMT
Server: Apache
Access-Control-Allow-Origin: *
公開
できたものを公開するにはサーバーに***.htmlをアップロードすればできます。
やり方はこちらの記事を参考にしてください。
感想
いいと思う部分
- htmlファイル一つで済む。
使いにくい部分や疑問
- 動き出すまでに時間がかかる。
- タグがPythonで変更できないのか?<a href=や<img src=がPythonで変更できたら便利。
できました。↓↓
aタグやimgを動的に変更した完成品(https)
イチゲをOFUSEで応援する
MENTAやってます(ichige)



コメント