Получаем картиночки на python при помощи grab for Fun and Profit
от Virus-ONЪ
Давеча понадобилось мне выкачать пак из 8к картиночек с зерочана. Делать это вручную было как-то совсем не вариантом, поэтому выбор пал на вариант с грабом картиночек.
Языком на котором я решил пилить грабер стал пайтон, почему? Огромное количество сторонних инструментов которые без особой жопной боли можно приспособить под свои нужды. Таким вот инструментом и стал фреймворк grab о котором и пойдёт сегодня речь.
Стоит сразу обмолвиться что нормальной документации у него нет и по сей день, так что я оперировал немного устаревшей инфой, однако даже так, фреймворк делал своё дело и очень мне понравился.
Для начала нужно его поставить, это вполне спокойно делается командой
Окей, теперь, для примера получим страницу, ну скажем, с артами по Undertale, тобишь http://www.zerochan.net/Undertale
Для этого:
скачать
Думаю, у многих возник логичный вопрос - а зачем такой большой таймаут? Дело в том, что в фреймворке используется библиотека pycurl, и лично у меня первый коннект может занимать до 40 секунд. От чего так, я не понял, на 7й винде и линуксе всё было норм.
Итак, будем исходить из того что мы получили нашу html страницу.
Ага, вот и оно, картинки с маленькими превьюшками!
Превосходно. Попробуем теперь открыть какую-либо картинку в полном размере, посмотрим какой у неё линк?
Бинго!
превью: http://s3.zerochan.net/Undertale.240.1991330.jpg
сама картинка: http://static.zerochan.net/Undertale.full.1991330.jpg
Всего-лишь везение, но это крайне упростило мне задачу, давайте соберём их всех получим все картинки с этой страницы.
Для этого определим функцию get_img которая будет принимать list тегов img из которых мы извлечём параметр src, по которому мы потом и будем их скачивать при помощи urllib предварительно обработав.
скачать
Думаю, я достаточно подробно расписал где мы и что делаем, единственное чего я не объяснил, так это того что за магией мы получаем этот самый список с тегами. И тут мы подходим к такой возможности фрейморка как работа с DOM деревом.
Для этого и предназначены методы xpath
xpath — вернуть первый элемент удовлетворяющий запросу
xpath_list — вернуть все элементы
xpath_text — вернуть текстовое содержимое элемента (и всех вложенных элементов)
xpath_number — вернуть первое числовое вхождение из текста элемента (и всех вложенных элементов)
Итак, запускаем, и получаем аж 22 поименованные картиночки.
Однако мы ведь хотим ВСЕ картиночки, со ВСЕХ страниц.
Для этой задачи лучше вынести переход на страницу в отдельную функцию. Грабить будем циклом. Количество страниц получим автоматически парсингом, как и ссылку для перехода на следующую страницу.
А вот и нужная нам строка в html`e, значит получение ссылки для перехода будет выглядеть так:
Итак, готовый код
скачать
Полностью готовую версию моего проекта можно будет найти тут.
Напоследок, хотелось бы сказать, что возможности данного фреймворка далеко не исчерпываются тем что мы тут рассмотрели. Они гораздо более обширны и многогранны. Если кого-то это заинтересовало, значит цель этой статьи достигнута.
Полезные линки:
Site:
http://grablib.org
Github project: source code and issue tracker:
http://github.com/lorien/grab
English mailing list:
http://groups.google.com/group/grab-users
English documentation:
http://docs.grablib.org/en/latetst/
Russian mailing list:
http://groups.google.com/group/python-grab
Russian documentation:
http://docs.grablib.org/ru/latetst/
Статья на Хабрахабре
https://habrahabr.ru/post/127584/
Языком на котором я решил пилить грабер стал пайтон, почему? Огромное количество сторонних инструментов которые без особой жопной боли можно приспособить под свои нужды. Таким вот инструментом и стал фреймворк grab о котором и пойдёт сегодня речь.
Стоит сразу обмолвиться что нормальной документации у него нет и по сей день, так что я оперировал немного устаревшей инфой, однако даже так, фреймворк делал своё дело и очень мне понравился.
Для начала нужно его поставить, это вполне спокойно делается командой
- pip install grab
Окей, теперь, для примера получим страницу, ну скажем, с артами по Undertale, тобишь http://www.zerochan.net/Undertale
Для этого:
- from grab import *
- g = Grab(log_file='out.html')
- g.setup(connect_timeout=50, timeout=50)
- g.go('http://www.zerochan.net/Undertale')
Думаю, у многих возник логичный вопрос - а зачем такой большой таймаут? Дело в том, что в фреймворке используется библиотека pycurl, и лично у меня первый коннект может занимать до 40 секунд. От чего так, я не понял, на 7й винде и линуксе всё было норм.
Итак, будем исходить из того что мы получили нашу html страницу.
Ага, вот и оно, картинки с маленькими превьюшками!
Превосходно. Попробуем теперь открыть какую-либо картинку в полном размере, посмотрим какой у неё линк?
Бинго!
превью: http://s3.zerochan.net/Undertale.240.1991330.jpg
сама картинка: http://static.zerochan.net/Undertale.full.1991330.jpg
Всего-лишь везение, но это крайне упростило мне задачу, давайте соберём их всех получим все картинки с этой страницы.
Для этого определим функцию get_img которая будет принимать list тегов img из которых мы извлечём параметр src, по которому мы потом и будем их скачивать при помощи urllib предварительно обработав.
- # -*- coding: UTF-8 -*-
- from grab import *
- import time
- import os
- import urllib
- def get_img(img_link_list):
- for x in img_link_list:
- # Получаем параметр src тега img
- img_url = str(x.get('src'))
- # Исправляем ссылку
- img_url = img_url.replace('.240.', '.full.')
- img_url = img_url.replace('s3.', 'static.')
- # Скачиваем изображение
- img = urllib.urlopen(img_url).read()
- # Пусть его именем станет его номер и расширение
- img_name = img_url.split('.')[len(img_url.split('.')) - 2] + '.' + img_url.split('.')[len(img_url.split('.')) - 1]
- # Если такой файл уже существует, удаляем к чертям
- if os.path.isfile(img_name): os.remove(img_name)
- # Сохраняем, закрываем, ждём дабы нас не послали за попытку DDOS`a
- f = open(img_name, "wb")
- f.write(img)
- f.close()
- time.sleep(0.4)
- g = Grab()
- g.setup(connect_timeout=50, timeout=50)
- g.go('http://www.zerochan.net/Undertale')
- get_img(g.xpath_list('//li/a/img'))
Думаю, я достаточно подробно расписал где мы и что делаем, единственное чего я не объяснил, так это того что за магией мы получаем этот самый список с тегами. И тут мы подходим к такой возможности фрейморка как работа с DOM деревом.
Для этого и предназначены методы xpath
xpath — вернуть первый элемент удовлетворяющий запросу
xpath_list — вернуть все элементы
xpath_text — вернуть текстовое содержимое элемента (и всех вложенных элементов)
xpath_number — вернуть первое числовое вхождение из текста элемента (и всех вложенных элементов)
Итак, запускаем, и получаем аж 22 поименованные картиночки.
Однако мы ведь хотим ВСЕ картиночки, со ВСЕХ страниц.
Для этой задачи лучше вынести переход на страницу в отдельную функцию. Грабить будем циклом. Количество страниц получим автоматически парсингом, как и ссылку для перехода на следующую страницу.
А вот и нужная нам строка в html`e, значит получение ссылки для перехода будет выглядеть так:
- g.xpath('//p[@class="pagination"]/a[@rel="next"]').get('href')
- <p class="pagination" style="margin-bottom: 50px; ">
- page 1 of 15 <a href="?p=2" tabindex="1" rel="next">Next »</a>
- </p>
Итак, готовый код
- # -*- coding: UTF-8 -*-
- from grab import *
- import time
- import os
- import urllib
- def next_page(flink):
- global max_page, i, sub_link, g
- g.go(flink)
- time.sleep(0.4)
- if max_page != i: sub_link = g.xpath('//p[@class="pagination"]/a[@rel="next"]').get('href')
- def get_img(img_link_list):
- for x in img_link_list:
- # Получаем параметр src тега img
- img_url = str(x.get('src'))
- # Исправляем ссылку
- img_url = img_url.replace('.240.', '.full.')
- img_url = img_url.replace('s3.', 'static.')
- # Скачиваем изображение
- img = urllib.urlopen(img_url).read()
- # Пусть его именем станет его номер и расширение
- img_name = img_url.split('.')[len(img_url.split('.')) - 2] + '.' + img_url.split('.')[len(img_url.split('.')) - 1]
- # Если такой файл уже существует, удаляем к чертям
- if os.path.isfile(img_name): os.remove(img_name)
- # Сохраняем, закрываем, ждём дабы нас не послали за попытку DDOS`a
- f = open(img_name, "wb")
- f.write(img)
- f.close()
- time.sleep(0.4)
- g = Grab()
- g.setup(connect_timeout=50, timeout=50)
- link = 'http://www.zerochan.net/Undertale'
- sublink = '' # ?p=xxx и тому подобное
- i = 1
- # Получаем число страниц для грабежа и разбоя
- g.go(link)
- max_page = int(g.xpath_text('//p[@class="pagination"]').split(' ')[3])
- while i <= max_page:
- next_page(link + sub_link)
- get_img(g.xpath_list('//li/a/img'))
- print('Grab page number %i ended' % i)
- i += 1
- print('Done')
- exit()
Полностью готовую версию моего проекта можно будет найти тут.
Напоследок, хотелось бы сказать, что возможности данного фреймворка далеко не исчерпываются тем что мы тут рассмотрели. Они гораздо более обширны и многогранны. Если кого-то это заинтересовало, значит цель этой статьи достигнута.
Полезные линки:
Site:
http://grablib.org
Github project: source code and issue tracker:
http://github.com/lorien/grab
English mailing list:
http://groups.google.com/group/grab-users
English documentation:
http://docs.grablib.org/en/latetst/
Russian mailing list:
http://groups.google.com/group/python-grab
Russian documentation:
http://docs.grablib.org/ru/latetst/
Статья на Хабрахабре
https://habrahabr.ru/post/127584/