Перейти к содержимому

Как вставить картинку в python из интернета

  • автор:

Как в tkinter вставить картинку с сайта?

Есть сайт wolframalpha.com , там есть API для, я отправляю запрос, получаю решение уравнения в виде картинки, вопрос: как эту картинку взять и поместить в tkinter?

Отслеживать
задан 6 ноя 2019 в 13:05
Максим Синельников Максим Синельников
85 1 1 серебряный знак 4 4 бронзовых знака
Подробнее напишите свой вопрос. Как получаете своё решение в виде картинки? Исходник нужен.
6 ноя 2019 в 14:21
api.wolframalpha.com/v2/… любая из картинок
6 ноя 2019 в 14:35

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Допустим, вам уже известен url изображения.

Ниже два примера (синхронный и асинхронный). В обоих случаях изображение скачивается из интернета в память, потом с помощью библиотеки Pillow (ее нужно установить с помощью pip install pillow ) изображение преобразовывается в формат, который понимает tkinter, потом изображение устанавливается в label.

Первое решение синхронное (графический интерфейс подвисает, пока идет загрузка), загрузка с помощью requests :

import tkinter as tk import requests from io import BytesIO from PIL import Image, ImageTk url = "https://www6b3.wolframalpha.com/Calculate/MSP/MSP14531gg5c35255f535bi0000683dg2hfh4g5hh7i?MSPStoreType=image/gif&s=6" root = tk.Tk() def load_image(): label.config(text='Loading an image. ') root.update() try: response = requests.get(url, timeout=10) except requests.exceptions.Timeout: label.config(text='Timeout error') else: if response.status_code != 200: label.config(text=f'HTTP error ') else: pil_image = Image.open(BytesIO(response.content)) image = ImageTk.PhotoImage(pil_image) label.config(image=image, text='') # прикрепляем ссылку на изображение к объекту label, # чтобы изображение не удалил сборщик мусора label.image = image tk.Button(root, text='Load an image', command=load_image).pack() label = tk.Label(root) label.pack() root.mainloop() 

Второй вариант с асинхронностью (Python 3.5 и выше), загрузка с помощью библиотеки aiohttp (нужно установить ее с помощью pip install aiohttp ):

import tkinter as tk import asyncio import aiohttp from io import BytesIO from PIL import Image, ImageTk class AsyncTk(tk.Tk): """Асинхронная обертка для класса Tk""" def __init__(self): super().__init__() self.protocol("WM_DELETE_WINDOW", self.on_close) def on_close(self): self.done = True async def updater(self): self.done = False while not self.done: self.update() await asyncio.sleep(0.05) def mainloop(self): asyncio.get_event_loop().run_until_complete(self.updater()) async def fetch_image(url): async with aiohttp.ClientSession() as session: response = await session.get(url) if response.status != 200: label.config(text=f'HTTP error ') else: content = await response.content.read() pil_image = Image.open(BytesIO(content)) image = ImageTk.PhotoImage(pil_image) label.config(image=image, text='') label.image = image button.config(state=tk.NORMAL) url = "https://www6b3.wolframalpha.com/Calculate/MSP/MSP14531gg5c35255f535bi0000683dg2hfh4g5hh7i?MSPStoreType=image/gif&s=6" def load_image(): button.config(state=tk.DISABLED) label.config(text='Loading an image. ') asyncio.ensure_future(fetch_image(url)) root = AsyncTk() button = tk.Button(root, text='Load an image', command=load_image) button.pack() label = tk.Label(root) label.pack() root.mainloop() 

Идеи для данной реализации взяты из этих ответов:

  • Use asyncio and Tkinter
  • Проблема с asyncio: RuntimeWarning: coroutine ‘message_send’ was never awaited self.tk.mainloop(n)

P.S. минутка саморекламы. Второй вариант (в немного другой реализации, без наследования от Tk ) я оформил в виде модуля, выкатил на pypi. Возможно кому-то пригодится.

  • Ставится через pip install async-tkinter-loop , см. на pypi:
    https://pypi.org/project/async-tkinter-loop/
  • Проект и примеры использования (папка examples):
    https://github.com/insolor/async-tkinter-loop

Вариант с использованием модуля async_tkinter_loop :

import tkinter as tk import aiohttp from async_tkinter_loop import async_handler, async_mainloop from io import BytesIO from PIL import Image, ImageTk async def load_image(url): button.config(state=tk.DISABLED) label.config(text='Loading an image. ') root.update() async with aiohttp.ClientSession() as session: response = await session.get(url) if response.status != 200: label.config(text=f'HTTP error ') else: content = await response.content.read() pil_image = Image.open(BytesIO(content)) image = ImageTk.PhotoImage(pil_image) label.config(image=image, text='') label.image = image button.config(state=tk.NORMAL) url = "https://www6b3.wolframalpha.com/Calculate/MSP/MSP14531gg5c35255f535bi0000683dg2hfh4g5hh7i?MSPStoreType=image/gif&s=6" root = tk.Tk() # Объект окна создается как обычно button = tk.Button(root, text='Load an image', command=async_handler(load_image, url)) button.pack() label = tk.Label(root) label.pack() async_mainloop(root) # Вместо стандартного `mainloop()` используется своя реализация с поддержкой асинхронности 

Встраиваем картинки в Jupyter

Рассмотрим способы вставки картинок в Jupyter ноутбук.

Синтаксис Markdown

Выглядит следующим образом:

![подпись](путь_до_картинки)

Например, исполним Markdown ячейку со следующим содержимым:

![picture_of_bird](data/картинки/kartinki-ryabchiki-28.jpeg)

Синтаксис HTML

Для этого в Markdown ячейке используем тег . Этот способ позволяет задавать дополнительные настройки, в частности, размеры:

Возможности Ipython

В отличие от предыдущих способов позволяет совместить код и вывод картинки в одной ячейке, так как делает это посредством использования функции Image из модуля IPython.display:

from IPython.display import Image print('Картинка с птицей') Image("data/картинки/kartinki-ryabchiki-28.jpeg", width=320, height=240)

Четыре метода загрузки изображений с веб-сайта с помощью Python

Недавно пришлось по работе написать простенький парсер на питоне, который бы скачивал с сайта изображения (по идее тот же самый парсер может качать не только изображения, но и файлы других форматов) и сохранял их на диске. Всего я нашел в интернете четыре метода. В этой статье я их решил собрать все вместе.

1-ый метод

Первый метод использует модуль urllib (или же urllib2). Пусть имеется ссылка на некое изображение img. Метод выглядит следующим образом:

import urllib resource = urllib.urlopen(img) out = open(". \img.jpg", 'wb') out.write(resource.read()) out.close() 

Здесь нужно обратить внимание, что режим записи для изображений — ‘wb’ (бинарный), а не просто ‘w’.

2-ой метод

Второй метод использует тот же самый urllib. В дальнейшем будет показано, что этот метод чуть медленнее первого (отрицательный оттенок фактора скорости парсинга неоднозначен), но достоин внимания из-за своей краткости:

import urllib urllib.urlretrieve(img, ". \img.jpg") 

Притом стоит заметить, что функция urlretrieve в библиотеке urllib2 по неизвестным мне причинам (может кто подскажет по каким) отсутствует.

3-ий метод

Третий метод использует модуль requests. Метод имеет одинаковый порядок скорости выгрузки картинок с первыми двумя методами:

import requests p = requests.get(img) out = open(". \img.jpg", "wb") out.write(p.content) out.close() 

При этом при работе с веб в питоне рекомендуется использовать именно requests вместо семейств urllib и httplib из-за его краткости и удобства обращения с ним.

4-ый метод

Четвертый метод по скорости кардинально отличается от предыдущих методов (на целый порядок). Основан на использовании модуля httplib2. Выглядит следующим образом:

import httplib2 h = httplib2.Http('.cache') response, content = h.request(img) out = open('. \img.jpg', 'wb') out.write(content) out.close() 

Здесь явно используется кэширование. Без кэширования (h = httplib2.Http()) метод работает в 6-9 раза медленнее предыдущих аналогов.

Тестирование скорости проводилось на примере скачивания картинок с расширением *.jpg c сайта новостной ленты lenta.ru. Выбор картинок, подпадающих под этот критерий и измерение времени выполнения программы производились следующим образом:

import re, time, urllib2 url = "http://lenta.ru/" content = urllib2.urlopen(url).read() imgUrls = re.findall('img .*?src="https://habr.com/ru/articles/210238/(.*?)"', сontent) start = time.time() for img in imgUrls: if img.endswith(".jpg"): """реализация метода по загрузке изображения из url""" print time.time()-start 

Постоянно меняющиеся картинки на сайте не повлияли на чистоту измерений, поскольку методы отрабатывали друг за другом. Полученные результаты таковы:

Таблица сравнения скоростей методов

Метод 1, с Метод 2, с Метод 3, с Метод 4, с (без кэширования, с)
0.823 0.908 0.874 0.089 (7.625)

Данные представлены как результат усреднения результатов семи измерений.
Просьба к тем, кто имел дело с библиотекой Grab (и с другими), написать в комментариях аналогичный метод по скачиванию изображений с помощью этой и других библиотек.

  • питон и парсинг
  • изображения

Python. Работа с изображениями в tkinter.

На уроке Python. Работа с изображениями мы с вами научились загружать и отображать картинки, а также всяко извращаться с ними. Это мы делали при помощи библиотеки PIL. На уроке Python. GUI мы с вами при помощи библиотеки tkinter создавали виндовый интерфейс программы: всякие кнопочки, флажки, и прочие элементы управления. Но возникает вопрос: а нельзя ли при помощи tkinter как-то выводить изображение на виндовую форму? Можно. Например вот такая программа:

import tkinter from PIL import Image, ImageTk root = tkinter.Tk() # создаем рабочую область frame = tkinter.Frame(root) frame.grid() #Добавим метку label = tkinter.Label(frame, text="Hello, World!").grid(row=1,column=1) # вставляем кнопку but = tkinter.Button(frame, text="Кнопка").grid(row=1, column=2) #Добавим изображение canvas = tkinter.Canvas(root, height=400, width=700) image = Image.open("d:/3/Dscn0116.jpg") photo = ImageTk.PhotoImage(image) image = canvas.create_image(0, 0, anchor='nw',image=photo) canvas.grid(row=2,column=1) root.mainloop()

выдаст вот такое окно:

Что интересно, PIL здесь нужен, чтобы загружать изображения типа jpg, gif-ы и png можно открыть и без него:

import tkinter root = tkinter.Tk() # создаем рабочую область frame = tkinter.Frame(root) frame.grid() #Добавим метку label = tkinter.Label(frame, text="Hello, World!").grid(row=1,column=1) # вставляем кнопку but = tkinter.Button(frame, text="Кнопка").grid(row=1, column=2) #Добавим изображение canvas = tkinter.Canvas(root, height=400, width=700) img = tkinter.PhotoImage(file = 'd:/3/Dscn0116.png') image = canvas.create_image(0, 0, anchor='nw',image=img) canvas.grid(row=2,column=1) root.mainloop()

А теперь попробуем при нажатии на кнопку сменить изображение:

import tkinter from PIL import Image, ImageTk root = tkinter.Tk() # создаем рабочую область frame = tkinter.Frame(root) frame.grid() # Добавим метку label = tkinter.Label(frame, text="Hello, World!").grid(row=1, column=1) image = Image.open("d://1//DSCN1128.png") photo = ImageTk.PhotoImage(image) def my_event_handler(): print("my_event_handler") image = Image.open("d://1//original.jpg") photo = ImageTk.PhotoImage(image) image = canvas.create_image(0, 0, anchor='nw', image=photo) canvas.grid(row=2, column=1) # вставляем кнопку but = tkinter.Button(frame, text="Кнопка", command=my_event_handler).grid(row=1, column=2) # Добавим изображение canvas = tkinter.Canvas(root, height=400, width=700) image = canvas.create_image(0, 0, anchor='nw', image=photo) canvas.grid(row=2, column=1) root.mainloop()

Но не тут то было. При нажатии на кнопку изображение не меняется. Хотя, казалось бы, все написано правильно, и наш обработчик событий работает, наше сообщение, что мы выводим командой print выводится в окно сообщений. В чем же дело? А дело в сборщике мусора (garbage collector). Как только мы вышли из my_event_handler, локальные переменные тут же уничтожаются сборщиком мусора. Именно поэтому мы видим на форме ту же самую картинку, что и до нажатия на кнопку. Как же быть? Не использовать локальные переменные. Давайте объявим класс, пусть изображение и прочие объекты хранятся в его полях:

import tkinter from PIL import Image, ImageTk class App: def __init__(self): self.root = tkinter.Tk() # создаем рабочую область self.frame = tkinter.Frame(self.root) self.frame.grid() # Добавим метку self.label = tkinter.Label(self.frame, text="Hello, World!").grid(row=1, column=1) self.image = Image.open("d://1//DSCN1128.png") self.photo = ImageTk.PhotoImage(self.image) # вставляем кнопку self.but = tkinter.Button(self.frame, text="Кнопка", command=self.my_event_handler).grid(row=1, column=2) # Добавим изображение self.canvas = tkinter.Canvas(self.root, height=600, width=700) self.c_image = self.canvas.create_image(0, 0, anchor='nw', image=self.photo) self.canvas.grid(row=2, column=1) self.root.mainloop() def my_event_handler(self): print("my_event_handler") self.image = Image.open("d://1//original.jpg") self.photo = ImageTk.PhotoImage(self.image) self.c_image = self.canvas.create_image(0, 0, anchor='nw', image=self.photo) self.canvas.grid(row=2, column=1) app= App()

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *