Как скачать картинки с сайта с помощью Python
И далее сгенерированный список ссылок надо сохранить как html и скачать их любым менеджером загрузок.
import os # importing all we need, it's not much import wget urls_to_load = list() # a list to store the urls path = 'download_folder' # the path where we will download those files a = "https://member.etn-net.org/magazines/en/2001/ETN-TF_4-2001_EN/ETN-TF_4-2001_EN_01.jpg" # the first two images are separate as the source has them named differently b = "https://member.etn-net.org/magazines/en/2001/ETN-TF_4-2001_EN/ETN-TF_4-2001_EN_31.jpg" urls_to_load.extend([a, b]) # add them to the url list # add all other images, generating their names as we need for i in range(2, 31): # it is important to make this second number +1, so PY makes the list correctly (as far as we start with 2) a = "https://member.etn-net.org/magazines/en/2001/ETN-TF_4-2001_EN/ETN-TF_4-2001_EN_" + str(i).zfill(2) + "a.jpg" b = "https://member.etn-net.org/magazines/en/2001/ETN-TF_4-2001_EN/ETN-TF_4-2001_EN_" + str(i).zfill(2) + "b.jpg" urls_to_load.extend([a, b]) # preparing to download if not os.path.exists(path): try: os.mkdir(path) except OSError: print("Creation of the directory %s failed" % path) else: print("Successfully created the directory %s " % path) # starting to download print("Starting downloading") for url in urls_to_load: file_name = path + '/' + os.path.basename(url) # get the full path to the file if os.path.exists(file_name): os.remove(file_name) # if exists, remove it directly file_name = wget.download(url, out=path) print(file_name) print("ok")
Тут смысл в том, что оно умеет по списку ссылок скачивать, а в остальном оно бесполезное, конечно. Просто мне было лень руками 30 ссылок вбивать. И да, будьте внимательнее с копирайтом, соблюдайте закон.
Может быть интересно:
- Select all images urls and download them
- Про Python и ArchiCAD: удалить лишние слои
- Скрипт для выбора победителя в инстаграме (из лайков)
- Задаём свойства объектам в ArchiCAD 23 через Python
- Распечатать дерево проекта в ArchiCAD 23 через Python
Как парсить и скачать картинки с сайта?
Мне нужно спарсить картинку а точнее .gif и скачать ее, а если так нельзя то спарсить ее URL или путь к ней. Код:
Мой парсер:
import requests from bs4 import BeautifulSoup as bs r = requests.get("https://gifer.com/ru/gifs/loading") soup = bs(r.content, 'lxml') img = soup.find('picture', class_='preview-media preview-media_loaded') print(img)
Отслеживать
51.6k 199 199 золотых знаков 59 59 серебряных знаков 242 242 бронзовых знака
задан 12 дек 2020 в 18:11
105 3 3 серебряных знака 9 9 бронзовых знаков
Хорошо было бы увидеть вашу попытку написать код парсера
12 дек 2020 в 18:14
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
У вас не работал код, т.к. при загрузке страницы там нет нужных вам тегов, а те теги подгружаются динамически при выполнении javascript.
У BeautifulSoup нет скриптового движка, поэтому он не будет выполнять код на странице. Вам нужно использовать ту библиотеку, у которой будет поддержка javascript, например selenium.
Тут я накидал простенький пример, но хочу заметить, что вам скорее всего придется его дописывать, т.к. гифки на том сайте тоже динамически подгружаются при прокручивании страницы вниз. В моем примере есть один скролл вниз, чтобы показать как это выглядит, а делать полную прогрузку всех гифок не буду (но тут у меня есть пример скролла для яндекс-плейлиста, можете с него пример брать).
Для установки selenium выполнить команду (для Firefox нужно будет еще скачать geckodriver.exe ):
pip install selenium
from selenium import webdriver from selenium.webdriver.firefox.options import Options def get_urls(driver): urls = [] for link in driver.find_elements_by_css_selector('figure.media-thumb.desktop link[itemprop=contentUrl]'): url_gif = link.get_attribute('content') gif_id = url_gif.split('/')[-1] url_download = URL_DOWNLOAD_TEMPLATE + gif_id urls.append(url_download) return urls URL_DOWNLOAD_TEMPLATE = 'https://i.gifer.com/embedded/download/' options = Options() options.add_argument('--headless') driver = webdriver.Firefox(options=options) driver.get('https://gifer.com/ru/gifs/loading') driver.implicitly_wait(20) urls = get_urls(driver) print(f': ') # 4: ['https://i.gifer.com/embedded/download/g0R5.gif', 'https://i.gifer.com/embedded/download/VAyR.gif', 'https://i.gifer.com/embedded/download/ZKZx.gif', 'https://i.gifer.com/embedded/download/ZZ5H.gif'] # Small scroll down driver.execute_script(f'window.scrollTo(0, 200);') urls = get_urls(driver) print(f': ') # 8: ['https://i.gifer.com/embedded/download/g0R5.gif', 'https://i.gifer.com/embedded/download/VAyR.gif', 'https://i.gifer.com/embedded/download/ZKZx.gif', 'https://i.gifer.com/embedded/download/ZZ5H.gif', 'https://i.gifer.com/embedded/download/g0R9.gif', 'https://i.gifer.com/embedded/download/ZWdx.gif', 'https://i.gifer.com/embedded/download/7pld.gif', 'https://i.gifer.com/embedded/download/AqCa.gif'] driver.quit()
Статья Парсим и скачиваем «нескучные обои» с использованием потоков в Python
». Привет, Денис Попов . Ну, а если более серьезно, то скачаем картинки с обоями с сайта, на котором их очень и очень много. Конечно же, для того, чтобы скачать картинки мы будем использовать Python, а загрузка картинок будет происходить в многопоточном режиме. Ну и наиболее полезная часть данной статьи состоит в том, что мы немного попрактикуемся в парсинге.

Что понадобиться?
Для отправки запросов и скачивание картинок будем использовать библиотеку 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, то данный пункт называется «Проверить». Ну и так далее. Суть в том, что нужно попасть в инструменты разработчика.
Заголовки для запроса

Копируем их и вставляем в скрипт:
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()
Сохранить картинку по ссылке
Python 3.x хочу сохранить картинку на комп по прямой ссылке на неё.
В гугле нашёл такой скрипт, по сравнению с другими он хотя бы запускается. Как я понял, он читает урл и открывает его. Но ничего не открывается, и мне требуется сохранить фото в какую нибудь папку.
1 2 3 4 5 6
import urllib.request url = "https://урл на картинку.jpg" img = urllib.request.urlopen(url).read() out = open("img.jpg", "wb") out.write(img) out.close
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

Как сохранить график pyqtgraph в картинку
Добрый день! Как сохранить график pyqtgraph в картинку? Взял пример с их сайта: import pyqtgraph.
Как сохранить картинку в модели, отправив её через ajax?
Я уже 2 дня, завтра третий, буду биться с казалось бы простой задачей: мне нужно тупо через аякс.

Сохранить картинку по прямой ссылке
Здравствуйте. Кароче КАК сохранить картинку по конкретной ссылке?
Необходимо скопировать изображение по ссылке, из сохранить по другой ссылке
Или может быть как изображение из Image, сохранить по ссылке, что бы размеры были ни как в Image, а.
Покозать картинку из бд по её ссылке
Доброго времени суток ест бд id avtor linc—ссылка на картинку data Как покозать картинку.