質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

1301閲覧

tkinter 画像

ads3hcgff

総合スコア16

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2018/09/16 16:06

tkinterでwebから画像をスクレイピングする部分を関数化してキャンパスに描写できない

tkinterでボタンをクリックしたらwebから画像を習得したいのですが、毎回webからスクレイピングを
するのは負担がかかると思い↓のように関数化したのですがなぜか関数化すると画像がキャンパスに描写されませんでした。普通に書くと問題なく描写されるのですが、それだと毎回通信をして画像をwebからスクレイピングしているのかと思いボタンの中で関数化しました。
そもそもtkinterのループの仕組みがわかっていないからなのか、とりあえずリファレンスを読みましたが手抜きのあまりにもひどいリファレンスだったので全く理解できず・・・

##関数化の部分 def imageprint(url): headers = { "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0", } request = urllib.request.Request(url=url, headers=headers) f = io.BytesIO(urllib.request.urlopen(request).read()) img = Image.open(f) img.thumbnail((200, 200), Image.ANTIALIAS) img = ImageTk.PhotoImage(img) # 表示するイメージを用意 return img
##こちらが全ソース import tkinter as tk from PIL import Image, ImageTk import urllib.request import io from PIL import Image ''' web上にある画像を保存します ''' img ="" url = "http://imgcc.naver.jp/kaze/mission/USER/20180519/35/3012705/157/500x718xedab7ba7e203cd7576d12004.jpg" root = tk.Tk() root.geometry('800x560') root.title('IMG') canvas = tk.Canvas( root, # 親要素をメインウィンドウに設定 width=500, # 幅を設定 height=500, # 高さを設定 #relief=tk.RIDGE # 枠線を表示 # 枠線の幅を設定 bg = "black" ) canvas.place(x=0, y=0) # メインウィンドウ上に配置 def btn_click_1_1(): global url global img img = imageprint(url) print(img) # ボタンを表示 command=処理 button= tk.Button(text="button",command=btn_click_1_1) button.place(x=0, y=200) def imageprint(url): headers = { "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0", } request = urllib.request.Request(url=url, headers=headers) f = io.BytesIO(urllib.request.urlopen(request).read()) img = Image.open(f) img.thumbnail((200, 200), Image.ANTIALIAS) img = ImageTk.PhotoImage(img) # 表示するイメージを用意 return img canvas.create_image( # キャンバス上にイメージを配置 0, # x座標 0, # y座標 image=img, # 配置するイメージオブジェクトを指定 tag="illust", # タグで引数を追加する。 anchor=tk.NW # 配置の起点となる位置を左上隅に指定 ) root.mainloop()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hayataka2049

2018/09/16 16:22

関数化していないコードも掲載してください
ads3hcgff

2018/09/16 18:07 編集

全ソースと書いてあるのが関数化していないコードに当たります
hayataka2049

2018/09/16 18:17

?  imageprintを使っているので関数化したコードだと思ったのですが、違うのですか?
ads3hcgff

2018/09/16 18:49

imageprintが、スクレイピングを関数化してそれをボタンが押されたらコールバック関数としたんです。
ads3hcgff

2018/09/17 08:13

いまさらですが、関数化していないコードの意味が分かりました。すいませんもう関数化してしまったので元のコードはないです。ただ、もう一つtkinterで画像を表示させるときに注意しなければならないことが見つかったのでそれを回答に載せておきます。
guest

回答2

0

ベストアンサー

btn_click_1_1関数にcanvas.create_imageの呼び出し文がないです。
そのため、変数:imgに値を格納しても画面の更新が行わなれないかと。

Python

1def btn_click_1_1(): 2 global url 3 global img 4 img = imageprint(url) 5 # canvas.create_imageの行を追加root.mainloopのcanvas.create_imageは不要です。 6 canvas.create_image( # キャンバス上にイメージを配置 7 0, # x座標 8 0, # y座標 9 image=img, # 配置するイメージオブジェクトを指定 10 tag="illust", # タグで引数を追加する。 11 anchor=tk.NW # 配置の起点となる位置を左上隅に指定 12 ) 13 print(img)

毎回webからスクレイピングをするのは負担がかかる

pathlibを使って画像をローカルに保存するという手(※)もありますが。
hashlibを使って、urlからハッシュ関数の出力結果を求め、保存ファイル名として使用すればよいかと。

同じURLに対してプログラム起動中はキャッシュを行いたいだけならば。
functools.lru_cacheが使えます。

Python

1# -*- coding: utf-8 -*- 2""" 3web上にある画像を保存します 4""" 5import tkinter as tk 6from PIL import Image, ImageTk 7import urllib.request 8from io import BytesIO 9from functools import lru_cache 10from PIL import Image 11 12 13@lru_cache(maxsize=None) 14def get_content(url: str): 15 headers = { 16 "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0", 17 } 18 request = urllib.request.Request(url=url, headers=headers) 19 print("content") 20 return BytesIO(urllib.request.urlopen(request).read()) 21 22 23def imageprint(url): 24 img = Image.open(get_content(url)) 25 img.thumbnail((200, 200), Image.ANTIALIAS) 26 img = ImageTk.PhotoImage(img) # 表示するイメージを用意 27 return img 28 29 30img ="" 31url = "http://imgcc.naver.jp/kaze/mission/USER/20180519/35/3012705/157/500x718xedab7ba7e203cd7576d12004.jpg" 32root = tk.Tk() 33root.geometry('800x560') 34root.title('IMG') 35canvas = tk.Canvas( 36 root, # 親要素をメインウィンドウに設定 37 width=500, # 幅を設定 38 height=500, # 高さを設定 39 #relief=tk.RIDGE # 枠線を表示 40 # 枠線の幅を設定 41 bg = "black" 42 ) 43canvas.place(x=0, y=0) # メインウィンドウ上に配置 44 45def btn_click_1_1(): 46 #global url # 再代入を伴わないので、globalはコメントアウト 47 global img 48 img = imageprint(url) 49 print(img) 50 canvas.create_image( # キャンバス上にイメージを配置 51 0, # x座標 52 0, # y座標 53 image=img, # 配置するイメージオブジェクトを指定 54 tag="illust", # タグで引数を追加する。 55 anchor=tk.NW # 配置の起点となる位置を左上隅に指定 56 ) 57# ボタンを表示 command=処理 58button= tk.Button(text="button",command=btn_click_1_1) 59button.place(x=0, y=200) 60 61root.mainloop()

投稿2018/09/16 18:48

umyu

総合スコア5846

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

umyu

2018/09/16 18:53

かぶった。
ads3hcgff

2018/09/16 18:56

回答ありがとうございます。最初のコードおっしゃる通りです。 Tk()でインスタンス化してからloopのなかのwigetを毎回読み込んでいると思っていましたが違うようですね。すいません。把握漏れです。2つ目のソースはあまり理解していません。取り合えずローカルには保存せず、メモリに保存して展開したかったのですが・・・url.openでメモリ上にロードしまくるとGCとかしてくれないんでしょうか。urllibの仕組みがよく分かっておらず・・・
ads3hcgff

2018/09/16 19:09

ありがとうございます。精進します。
guest

0

すいません。できました
create_imageを関数化したコードの中にいれればよかったみたいです。

tk()でインスタンス化してからloopのなかは実は一回しか読み込まれてない?
試しにcreate_imageを関数の外に出したら無理でした。

追記

勝手ながらもう一つ重要な項目が見つかったので載せておきます。
こちらの記事

create_canvasの引数 imageにはローカル変数ではだめで、グローバル変数を入れなきゃだめらしい
ここに入れるのはImageTk.PhotoImage()で作成したオブジェクトなんですが
どうやらこれをローカル変数に入れたままcanvas_create関数に入れるとうまく動きません。
理由はImageTk.PhotoImage()をローカルに入れると一瞬でGCが起きるらしいです。
意味不明ですね、この仕様・・・・
これはtkinterが悪いのかpythonの仕様上そうなってしまうのかそれともPILが悪いのか謎・・・
根本的な理由はtkinterにあるらしいのですが・・・やれやれw

canvas.create_image( # キャンバス上にイメージを配置 0, # x座標 0, # y座標 image=img, ここをローカル変数に入れたまま代入すると動きませんw無能すぎる・・ anchor=tk.NW # 配置の起点となる位置を左上隅に指定 tag="illust", )

投稿2018/09/16 18:48

編集2018/09/17 08:23
ads3hcgff

総合スコア16

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問