Как скачать изображение python
Перейти к содержимому

Как скачать изображение python

  • автор:

Как скачать картинку с сайта на Python?

Название файла парси из ссылки, принты на логгинг меняй. И логи на английском. Вынеси логику и клиентский код отдельно. Не вижу обработки ошибок для запросов. Библиотеку поменяй на httpx. Почему не class based, переписывай и сделай абстракцию для http клиента от которой и наследуйся. Если отдельный файл со скриптом то где if __name__ . ? Если запросов таких много будет, юзай асинхронку сразу лучше.

Так в целом по верхам прошлись, тегнешь после некст коммита, пока денаю пулл реквест.

P.s. Добавь ещё pillow, чекай что картинка валидная, пережми в jpeg и задай Макс разрешение по ширине и высоте чтобы большие картинки не сохранять в оригинале. Место на сторедже беречь надо, а не закидывать картинки по 50Мб.

Развернуть ветку

Как много лишних действий, лишь бы на С++ не переписывать.

Развернуть ветку

Лиду и тестировщику тоже самое скажешь? Не долго проработаешь на бэке, сударь.

Развернуть ветку

Человек хотел скачать картинку — человек скачал картинку. Нет, давайте переусложнять. Ясен пень, что без кафки и телебота сервис делать нельзя, плюс мониторинг в графану.

Развернуть ветку

А если картинка не png, то и обойдемся

Четыре метода загрузки изображений с веб-сайта с помощью 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

». Привет, Денис Попов . Ну, а если более серьезно, то скачаем картинки с обоями с сайта, на котором их очень и очень много. Конечно же, для того, чтобы скачать картинки мы будем использовать Python, а загрузка картинок будет происходить в многопоточном режиме. Ну и наиболее полезная часть данной статьи состоит в том, что мы немного попрактикуемся в парсинге.

000.jpg

Что понадобиться?

Для отправки запросов и скачивание картинок будем использовать библиотеку requests. Для того, чтобы распарсить полученные результаты и получить из них ссылки на картинки BeautifulSoup и lxml. Поэтому, для начала их нужно установить:

pip install bs4 requests lxml

В работе скрипта так же потребуется библиотека для создания потоков threading, а так же библиотеки time, os и json. Поэтому перед началом работы давайте все это импортируем в наш скрипт.

import json import os.path import threading import time import requests from bs4 import BeautifulSoup

Сайт, с которого будет происходить скачивание обоев,
Ссылка скрыта от гостей

, на самом деле очень лоялен ко всякого рода попыткам его парсить. Он не сбрасывает соединение, не психует и не нервничает, когда к нему прилетает слишком много запросов. Идеальный пациент, можно сказать. Думаю, что он будет отдавать все данные даже в том случае, если мы не станем указывать заголовки запроса. Но, все же, чтобы работать по правилам и попрактиковаться, создадим их. Идем на сайт и смотрим заголовки в любом запросе. Забираем user-agent и accept.

Для этого щелкаем правой кнопкой мыши и в Яндекс.Браузере выбираем пункт «Исследовать элемент». Если же это будет Edge, то данный пункт называется «Проверить». Ну и так далее. Суть в том, что нужно попасть в инструменты разработчика.

Заголовки для запроса

screenshot1.png

Копируем их и вставляем в скрипт:

headers = < 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.119 ' 'YaBrowser/22.3.0.2434 Yowser/2.5 Safari/537.36', 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,' 'application/signed-exchange;v=b3;q=0.9 ' >

Функция получения пагинации

Давайте для начала создадим функцию получения пагинации со страницы из категории. Назову ее get_page_count(url). На вход она принимает только лишь один параметр, это ссылка на страницу категории. Далее выполняется запрос и полученные данные передаются в BeautifulSoup. После этого ищем блок с тэгом div, у которого id=pages. Получаем из этого блока все ссылки на страницы и забираем последнюю ссылку. Далее, разделяем ее и обрезаем лишние пробелы. Но, опытным путем было выявлено, что в некоторых категориях нет стрелки в тексте последней ссылки. Так как количество страниц с картинками помещается в блок пагинации целиком. И в этом случае скрипт падает с ошибкой. Для этого добавим блок try – except, чтобы эту ошибку отловить и просто забрать текст, без обрезки, из последней ссылки в блоке пагинации.

Полный код функции получения пагинации

def get_page_count(url): req = requests.get(url=url, headers=headers) soup = BeautifulSoup(req.text, 'lxml') try: page_count = int(soup.find('div', ).find_all('a')[-1].text.split(" ")[1].strip()) except: page_count = int(soup.find('div', ).find_all('a')[-1].text.strip()) return page_count

Получение ссылок на категории, названия категорий и количества страниц в каждой из них

Для того, чтобы названия категорий, ссылки на них и количество страниц в каждой категории хранились локально, нужно их во что-то сохранить. Я решил, что удобнее всего это будет сделать в файл JSON. А для того, чтобы ускорить получение ссылок на категории и прочих параметров, буду обрабатывать это в многопоточном режиме.

Для начала напишем функцию для нахождения названия категории, ссылки на нее и количества в ней страниц. Назвал я ее def get_link_category(url). На вход она получает ссылку на категорию. И дальше в коде для начала формируется общая ссылка на категорию. Потом ссылка, которую передали в функцию разделяется по слэшу и снова собирается для записи этой ссылки, в которой уже нет привязки к определенной странице, для записи в JSON. Это будет нужно для того, чтобы впоследствии брать ссылку из JSON и формировать из нее ссылку на загрузку пагинации и прочих параметров с определенной страницы.

Ну и последний я нахожу наименование категории. Именно оно будет служить ключом в словаре, который запишется в JSON. Формирую словарь и записываю в файл.

Вот полный код функции

def get_link_category(url): url_cats = 'https://w-dog.ru' + url.find('div', class_='word').find('a')['href'] url_cat = str('https://w-dog.ru' + url.find('div', class_='word').find('a')['href']).split("/") url_cat_s = f'/////' name_category = url.find('div', class_='word').find('a').text.strip() p_count = get_page_count(url_cats) category_dict[name_category] = < 'url_category': url_cat_s, 'page_count': p_count >with open('category_res.json', 'w', encoding='utf-8') as file: json.dump(category_dict, file, indent=4, ensure_ascii=False)

Чтобы было понятнее. В данной функции получаются данные только из одной категории. А вот каждая последующая ссылка на категорию передается из функции, в которой запускаются потоки. Назвал я ее def thread_func_category(). На входе она ничего не принимает. В ней есть ссылка, по которой делается запрос на страницу и собираются все ссылки на категории, которые потом записываются в словарь.

На следующем этапе запускается цикл для перебора значений полученного словаря. И в данном цикле формируется поток с указанием на функцию и параметрами, которые в данную функцию передаются. Ну, а дальше, потоки просто стартуют.

Полный код функции старта потоков загрузки ссылок на категории:

def thread_func_category(): url = 'https://w-dog.ru/' req = requests.get(url=url, headers=headers) soup = BeautifulSoup(req.text, 'lxml') all_category = soup.find_all('div', class_='wpitem category') for url in all_category: t = threading.Thread(target=get_link_category, kwargs=) t.start()

Загрузка картинок из категории, выбранной пользователем

Теперь можно перейти к важной части, а именно к загрузке картинок обоев из категории, которую указал пользователь. Назову ее get_pict_download(item, name_cat). Здесь на вход прилетает объект из найденных ссылок страницы, а так же имя категории. Оно будет нужно для того, чтобы указать папку с именем категории и загрузить в нее картинки. На первом этапе ищется имя картинки, под которым она будет сохранена и это имя очищается от мусора в виде всяких специальных символов, которые не совместимы с сохранением файлов в операционной системе.

Затем делается проверка на наличие картинки с данным названием в папке. Если такого названия нет, то картинка загружается. Если же есть, то не делается ничего. Это позволяет не дублировать загрузку одних и тех же картинок с перезаписью. Что позволяет, в случае, если вы не докачали категорию, а вы можете ее не докачать, так как картинок там о-о-очень много, ускорить работу скрипта. Ну и дальше формируется ссылка на картинку, после чего происходит ее загрузка и запись на диск.

Код загрузки картинки:

def get_pict_download(item, name_cat): name_pict = item.find('b', class_='word').text.strip().replace("/", " ").replace('"', ''). \ replace("'", "").replace(".", "") if not os.path.isfile(os.path.join(name_cat, f'.jpg')): url_pict = 'https://w-dog.ru' + item.find('div', class_='action-buttons').find('a')['href'] req = requests.get(url=url_pict, headers=headers) with open(os.path.join(name_cat, f'.jpg'), 'wb') as file: file.write(req.content)

А дальше нужно создать функцию, в которой будут запускаться потоки для скачивания картинок. Назовем ее thread_func(url_cat, count_cat, name_cat). На входе данная функция принимает ссылку на категорию, пагинацию и имя категории.

Затем получаем время старта функции, для измерения скорости загрузки картинок. После выводим сообщение о том, что загружается категория такая-то, такая-то. И количество в ней страниц. От вывода сообщения о загрузке определенной картинки я отказался, потому, что порою вывод просто не успевает отобразиться в терминале. И получается перемешанная каша. Так как в итоге отображается все. Поэтому здесь я ограничился выводом сообщения о загрузке определенной страницы. Далее в цикле запускаем запрос, в котором получаем ссылки на картинки с первой и последующих страниц. Затем данные из запроса передаются в объект супа. Проверяется, если ли папка с именем категории. Если нет, создается. И в цикле запускаются потоки, которые привязаны к функции загрузки картинки и передают в нее необходимые параметры. А после того, как скрипт завершит свою работу, выводиться время загрузки картинок.

Полный код запуска потоков для загрузки картинок

def thread_func(url_cat, count_cat, name_cat): start_time = time.monotonic() print(f'[+] Загружаю категорию "". Количество страниц: \n') if not os.path.isdir(name_cat): os.mkdir(name_cat) for nc in range(1, count_cat + 1): print(f'[+] Загружаю >> Страница: /. ') req = requests.get(url=f"/best/", headers=headers) soup = BeautifulSoup(req.text, 'lxml') all_url_page = soup.find_all('div', class_='wpitem') for item in all_url_page: t = threading.Thread(target=get_pict_download, kwargs=) t.start() print(f'\nВремя загрузки файлов: ')

Осталась только функция main(). В ней для начала запускается функция обновления словаря. Мало ли что, может быть за время, пока не использовался скрипт появились новые категории или добавились обои и поэтому количество страниц может измениться. Тут есть один нюанс, который заключается в том, что запись категорий в словарь будет каждый раз производиться в произвольном порядке, а именно в порядке завершения работы потока. Поэтому отображение категорий всегда будет выводиться по-разному. Ну, или почти всегда. Далее делается небольшая пауза, чтобы дать сохраниться файлу на диск. Так как если этой паузы не делать, скрипт продолжает свою работу, файл еще не успевает сохраниться. А так как на следующем этапе этот словарь открывается для чтения, скрипт вываливается с ошибкой, что файл не найден. Потом формируется словарь из открытого JSON, с помощью которого определяется название категории, а так же ссылка и количество страниц.

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

Код функции main()

def main(): print('[+] Обновляю словарь. \n') thread_func_category() time.sleep(2) with open('category_res.json', 'r', encoding='utf-8') as file: cat_dict = json.load(file) dict_cat = <> for num, cat in enumerate(cat_dict): print(f'. | страниц. ') dict_cat[num] = < 'url_category': cat_dict[cat]["url_category"], 'page_count': cat_dict[cat]["page_count"], 'name_cat': cat >num_cat = int(input('\n[+] - Введите номер категории для загрузки: ')) # передача данных для запуска потоков загрузки картинок if num_cat in dict_cat: thread_func(f"/", dict_cat[num_cat]['page_count'], dict_cat[num_cat]['name_cat']) else: print('[-] Вы ввели неверный номер категории для загрузки.') exit(0)

На этом все. Нужно сказать, что я немного поэкспериментировал и первоначальную версию парсера обоев сделал без использования многопоточной загрузки. И попробовал загрузить какую-либо категорию. Надо сказать, что с такой скоростью загрузки, когда все выполняется последовательно, категорию можно грузить сутками. После чего было решено добавить многопоточность. И о чудо, скорость загрузки увеличилась в разы.

Я пробовал загрузить самую маленькую категорию, в которой шесть страниц. На каждой странице по двенадцать картинок. То есть, получается, что загружается 69. Скорее всего, потому, что некоторые картинки просто повторяются на страницах. Будем считать, что так, я просто не стал проверять. Так как это слишком долго и муторно. Так вот скрипт без потоков работает примерно от одной до двух минут. В зависимости от загруженности сети. А вот скрипт с потоками от пяти до семи секунд.

Вот небольшое видео, в котором я даю некоторые пояснения по сбору данных со страницы, а так же сравниваю скорость работы скрипта:

Полный код скрипта загрузки обоев

import json import os.path import threading import time import requests from bs4 import BeautifulSoup # заголовки для запроса headers = < 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.119 ' 'YaBrowser/22.3.0.2434 Yowser/2.5 Safari/537.36', 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,' 'application/signed-exchange;v=b3;q=0.9 ' >category_dict = <> # получение пагинации # находим последнюю станицу и чистим от мусора # исключение добавлено потому, что есть разделы, у которых # меньше 7 страниц. В этом случае пагинация немного отличается def get_page_count(url): req = requests.get(url=url, headers=headers) soup = BeautifulSoup(req.text, 'lxml') try: page_count = int(soup.find('div', ).find_all('a')[-1].text.split(" ")[1].strip()) except: page_count = int(soup.find('div', ).find_all('a')[-1].text.strip()) return page_count # получаем ссылки на категории и сохраняем с JSON # получение ссылок происходит при каждом запуске программы # так как считывается так же и количество стараниц в каждой категории # и по прошествии времени оно может изменяться def get_link_category(url): url_cats = 'https://w-dog.ru' + url.find('div', class_='word').find('a')['href'] url_cat = str('https://w-dog.ru' + url.find('div', class_='word').find('a')['href']).split("/") url_cat_s = f'/////' name_category = url.find('div', class_='word').find('a').text.strip() p_count = get_page_count(url_cats) category_dict[name_category] = < 'url_category': url_cat_s, 'page_count': p_count >with open('category_res.json', 'w', encoding='utf-8') as file: json.dump(category_dict, file, indent=4, ensure_ascii=False) def thread_func_category(): url = 'https://w-dog.ru/' req = requests.get(url=url, headers=headers) soup = BeautifulSoup(req.text, 'lxml') all_category = soup.find_all('div', class_='wpitem category') for url in all_category: t = threading.Thread(target=get_link_category, kwargs=) t.start() # загрузка картинок из категории # получение названия категории # создание папки с именем категории куда будут загружаться картинки # поиск всех ссылок настранице, скачивание их в цикле # и сохранение в созданную папку def get_pict_download(item, name_cat, count_cat): name_pict = item.find('b', class_='word').text.strip().replace("/", " ").replace('"', ''). \ replace("'", "").replace(".", "") if not os.path.isfile(os.path.join(name_cat, f'.jpg')): url_pict = 'https://w-dog.ru' + item.find('div', class_='action-buttons').find('a')['href'] req = requests.get(url=url_pict, headers=headers) with open(os.path.join(name_cat, f'.jpg'), 'wb') as file: file.write(req.content) def thread_func(url_cat, count_cat, name_cat): start_time = time.monotonic() print(f'[+] Загружаю категорию "". Количество страниц: \n') for nc in range(1, count_cat + 1): print(f'[+] Загружаю >> Страница: /. ') req = requests.get(url=f"/best/", headers=headers) soup = BeautifulSoup(req.text, 'lxml') name_cat = soup.find('div', ).find('h2').text.strip() if not os.path.isdir(name_cat): os.mkdir(name_cat) all_url_page = soup.find_all('div', class_='wpitem') for item in all_url_page: t = threading.Thread(target=get_pict_download, kwargs=) t.start() print(f'\nВремя загрузки файлов: ') def main(): print('[+] Обновляю словарь. \n') thread_func_category() time.sleep(2) with open('category_res.json', 'r', encoding='utf-8') as file: cat_dict = json.load(file) dict_cat = <> for num, cat in enumerate(cat_dict): print(f'. | страниц. ') dict_cat[num] = < 'url_category': cat_dict[cat]["url_category"], 'page_count': cat_dict[cat]["page_count"], 'name_cat': cat >num_cat = int(input('\n[+] - Введите номер категории для загрузки: ')) # передача данных для запуска потоков загрузки картинок if num_cat in dict_cat: thread_func(f"/", dict_cat[num_cat]['page_count'], dict_cat[num_cat]['name_cat']) else: print('[-] Вы ввели неверный номер категории для загрузки.') exit(0) if __name__ == "__main__": main()

Как скачивать изображения с помощью библиотеки requests в Python?

Я установил библиотеку requests в Python 3.6. Необходимо скачать изображения по предоставленной ссылке на файл. Подскажите, пожалуйста, как это можно реализовать? Доступ к изображению я получаю следующим образом: img = r.get(‘URL here’)

Отслеживать
задан 8 мар 2017 в 12:34
77 1 1 золотой знак 3 3 серебряных знака 6 6 бронзовых знаков
Связанный вопрос: How to download image using requests
8 мар 2017 в 12:56

1 ответ 1

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

В респонсе будет атрибут content в котором содержится изображение в двоичном виде. Таким образом после получения ответа необходимо будет сохранить в его файл.

 img = r.get("img_url") img_file = file('path_to_image', 'w') img_file.write(img.content) img_file.close() 

Отслеживать
ответ дан 13 мар 2017 в 3:03
Ivan Panov Ivan Panov
173 1 1 серебряный знак 6 6 бронзовых знаков
во второй строчке нужно исправить по моему img_file = open(‘path_to_image’, ‘wb’)
20 дек 2019 в 18:11

  • python
  • requests
    Важное на Мете
Похожие

Подписаться на ленту

Лента вопроса

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.11.15.1019

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

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

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