
Contents
実行環境
- Windows 7 64
bit + PostgreSQL 9.4.5(zip版からバッチファイルで起動) - Python 3.3.5 + PL/Python3
- PL/v8 1.4.2
- コマンドプロンプトの代わりにConEmu 151208 + psql
- PL/Python
を使うので PostgreSQL はスーパーユーザ権限が必要
関連リンクと過去記事
- PostgreSQL 9.4.5 Documentation : Chapter 43. PL/Python - Python Procedural Language
- PGXN : PL/v8 (Documentation)
- MediaWiki API(日本語ドキュメント)
- Windows
で PostgreSQL 9.5 RC1 + PL/Python のポータブルな環境構築(1),(2) - PL/v8
インストールまとめ(3)Windows 版 PostgreSQL 9.4 - 第
6 回 PostgreSQL アンカンファレンス @ 東京での発表資料(ウィンドウ関数と plv8、PL/R)
過去記事の最初は
PostgreSQL 用の汎用ウェブアクセス関数を、PL/Python で作成
まず今回の作業用データベースを適当な名前で作成し、PL/Python-- on psql create database test_webapi; \c test_webapi create extension plpython3u; create extension plv8;
↓ 現状の確認。psql
select current_database(); +------------------+ | current_database | +------------------+ | test_webapi | +------------------+ (1 row) select extname, extversion from pg_extension; +------------+------------+ | extname | extversion | +------------+------------+ | plpgsql | 1.0 | | plv8 | 1.4.2 | | plpython3u | 1.0 | +------------+------------+ (3 rows)

Python
create or replace function plpy_urlopen(url text) returns bytea language plpython3u immutable as $$ from urllib.request import urlopen from urllib.error import URLError try: response = urlopen(url) except ValueError as e: plpy.notice('ValueError: unknown url type') except URLError as e: plpy.notice('URLError or HTTPError. failed to reach a server') else: return(response.read()); $$;
↓
- Python 3.3.6 Documentation : 21.5. urllib
— URL handling modules - Python v3.1.5 documentation : HOWTO Fetch Internet Resources Using The urllib Package
- StackOverflow : Catching ValueError: unknown url type: urllib2 Python
↓ ストアドの使い方は簡単で、引数に
select plpy_urlopen('アクセス先のURL'); -- bytea型が返る select convert_from(plpy_urlopen('アクセス先のURL'), '文字コード'); -- HTMLやWebAPIの場合、クエリ側で文字コードを指定しテキストにする
テキストの場合はクエリ側の手間が増えますが、一つのストアドでテキスト・バイナリ両方のウェブアクセスに使え、文字コードが不明なテキストデータも「とりあえず」バイナリで保存しておく等の対処が可能。このような汎用性・柔軟性を考えて
作った関数のテスト
↓ 本ブログのトップにアクセスし、結果のselect plpy_urlopen('http://kenpg.bitbucket.org/'); plpy_urlopen \x3c21444f43545950452068746d6c3e3c68746d6c3e0d0a3c686561643e0d0a3c6d 65746120687474702d65717569763d22436f6e74656e742d547970652220636f6e74 656e743d22746578742f68746d6c3b20636861727365743d5554462d38223e0d0a3c 6d65746120687474702d65717569763d22582d55412d436f6d70617469626c652220 636f6e74656e743d2249453d3130222f3e0d0a3c2f686561643e0d0a3c626f64793e 3c736372697074207372633d226b656e70675f766572315f696e6465782e6a732220 747970653d22746578742f6a617661736372697074223e3c2f7363726970743e3c2f 626f64793e0d0a3c2f68746d6c3e0d0a (1 row)

↓ 同じ結果を、クエリ側で文字コード(ここでは
select convert_from( plpy_urlopen('http://kenpg.bitbucket.org/'), 'utf8'); convert_fromcharset=UTF-8"> (1 row)

↓
select convert_from( plpy_urlopen('http://portal.nifty.com/'), 'sjis');

↓ 文字コード
select convert_from( plpy_urlopen('http://sango.edisc.jp/'), 'eucjp');

↓ エラー処理のテスト。サーバが存在しないとかネットワーク非接続の場合は
-- 存在しないアドレス select plpy_urlopen('https://kenpg.org/'); NOTICE: URLError or HTTPError. failed to reach a server CONTEXT: PL/Python function "plpy_urlopen" +--------------+ | plpy_urlopen | +--------------+ | | +--------------+ (1 row) -- ネットワークに非接続の場合も、上と同じ結果になる -- 引数がURL形式でない select plpy_urlopen('httpkenpg.org/'); NOTICE: ValueError: unknown url type CONTEXT: PL/Python function "plpy_urlopen" +--------------+ | plpy_urlopen | +--------------+ | | +--------------+ (1 row)

↓ テストの最後。ウェブ上の
-- bytea型の表示形式を確認 select current_setting('bytea_output'); +-----------------+ | current_setting | +-----------------+ | hex | +-----------------+ (1 row) -- hexならencode()不要でcopy -> xxdでバイナリファイルにできる copy ( select plpy_urlopen('http://kenpg.bitbucket.org/blog/201601/02/2.png') ) to program '"D:/AppsPortable/GitPortable/2.6.2/App/Git/usr/bin/xxd" -r -p > "R:/plpy_test.png"';


今回の主眼は