Как создать базовый веб-сканер для извлечения информации с веб-сайта

Вы когда-нибудь хотели программно получить конкретную информацию с веб-сайта для дальнейшей обработки? Скажите что-нибудь вроде спортивных результатов, тенденций на фондовом рынке или последних мод, биткойнов и других цен на криптовалюту? Если необходимая информация доступна на веб-сайте, вы можете написать сканер (также известный как скребок или паук), чтобы перемещаться по сайту и извлекать именно то, что вам нужно. Давайте выясним, как это сделать в Python.

Обратите внимание, что некоторые сайты не рекомендуют использовать сканер для доступа к информации.

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

Установка Scrapy

Мы используем модуль Python под названием Scrapy для обработки фактического сканирования. Это быстрый, простой и может перемещаться по нескольким веб-страницам, как вы можете с помощью браузера.

Обратите внимание, однако, что Scrapy не имеет средств для обработки JavaScript при навигации по сайту. Таким образом, те веб-сайты и приложения, которые используют javascript для манипулирования пользовательским интерфейсом, не могут быть правильно просканированы с помощью этого подхода.

Давайте теперь установим scrapy. Мы используем virtualenv

установить скрап. Это позволяет нам устанавливать scrapy в каталог, не затрагивая другие установленные модули системы.

Создайте каталог и инициализируйте виртуальную среду в этом каталоге.

mkdir crawler
cd crawler
virtualenv venv
. venv/bin/activate

Теперь вы можете установить scrapy в этот каталог.

pip install scrapy

Проверьте правильность установки скрапа.

scrapy
# prints
Scrapy 1.4.0 - no active project
Usage:
scrapy  [options] [args]
Available commands:
bench         Run quick benchmark test
fetch         Fetch a URL using the Scrapy downloader
genspider     Generate new spider using pre-defined templates
runspider     Run a self-contained spider (without creating a project)
...

Создание сканера веб-сайтов (также называемого пауком)

Давайте теперь напишем сканер для загрузки некоторой информации. Мы начнем с удаления некоторой информации со страницы Википедии о батарее по адресу https://en.wikipedia.org/wiki/Battery_(electricity).

Первым шагом в написании сканера является определение класса Python, который простирается от scrapy.Spider. Давайте назовем этот класс spider1.

Как минимум, класс паука требует следующее:

  • имя для идентификации паука, «Википедия» в этом случае.
  • переменная start_urls, содержащая список URL-адресов, с которых начинается сканирование. Мы используем URL Википедии, показанный выше, для нашего первого сканирования.
  • метод parse (), который, хотя пока и не используется, используется для обработки веб-страницы и извлечения того, что нам нужно.
import scrapy
class spider1(scrapy.Spider):
name = 'Wikipedia'
start_urls = ['https://en.wikipedia.org/wiki/Battery_(electricity)']
def parse(self, response):
pass

Теперь мы можем запустить этого паука, чтобы убедиться, что все работает правильно. Это выполняется следующим образом.

scrapy runspider spider1.py
# prints
2017-11-23 09:09:21 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: scrapybot)
2017-11-23 09:09:21 [scrapy.utils.log] INFO: Overridden settings: {'SPIDER_LOADER_WARN_ONLY': True}
2017-11-23 09:09:21 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.memusage.MemoryUsage',
'scrapy.extensions.logstats.LogStats',
...

Отключение регистрации

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

import logging
logging.getLogger('scrapy').setLevel(logging.WARNING)

При повторном запуске паука мы должны увидеть минимум сообщений журнала.

Использование Chrome Inspector

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

из веб-браузера Chrome использовать инспектор.

  • Перейдите на правильную страницу в Chrome.
  • Поместите мышь на элемент, для которого вы хотите информацию.
  • Щелкните правой кнопкой мыши, чтобы открыть контекстное меню.
  • Выбрать Осмотреть из меню.

Это должно появиться в консоли разработчика с элементы вкладка выбрана. Внизу под вкладкой вы должны увидеть строку состояния с позицией элемента, показанной следующим образом:

html body div # content.mw-body h1 # firstHeading.firstHeading.

Как мы объясним ниже, вам нужны некоторые или все части этой позиции.

Извлечение заголовка

Давайте теперь добавим некоторый код в метод parse (), чтобы извлечь заголовок страницы.

...
def parse(self, response):
print response.css('h1#firstHeading::text').extract()
...

Аргумент ответа для метода поддерживает метод css (), который выбирает элементы со страницы, используя заданное местоположение. Для нашего случая элемент h1.firstHeading. Нам нужно текстовое содержимое элемента, поэтому мы добавляем ::текст на выбор. Наконец, метод extract () возвращает выбранный элемент.

При повторном запуске scrapy в этом классе мы получаем следующий вывод:

[u'Battery (electricity)']

Это показывает, что заголовок был извлечен в список строк Unicode.

Как насчет описания?

Чтобы продемонстрировать еще некоторые аспекты извлечения данных из веб-страниц, давайте возьмем первый абзац описания со страницы Wikipedia выше.

При проверке с использованием Chrome Developer Console мы находим, что расположение элемента — это (Правая угловая скобка (>) указывает на родительско-дочерние отношения между элементами):

ДИВ # мвт-контент-текст> DIV> р

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

response.css('div#mw-content-text>div>p')[0]

Чтобы извлечь только текстовое содержимое, мы добавляем CSS extractor :: text:

response.css('div#mw-content-text>div>p')[0].css('::text')

В последнем выражении используется extract (), который возвращает список строк Unicode. Мы используем функцию python join (), чтобы присоединиться к списку.

    def parse(self, response):
print ''.join(response.css('div#mw-content-text>div>p')[0].css('::text').extract())

Результат выполнения scrapy с этим классом — это то, что мы ищем:

An electric battery is a device consisting of one or more electrochemical cells with external connections provided to power electrical devices such as flashlights, smartphones, and electric cars.[1] When a battery is supplying electric power, its positive terminal is
...

Сбор данных с использованием yield

Приведенный выше код выводит извлеченные данные на консоль. Когда вам нужно собрать данные как JSON, вы можете использовать оператор yield. Метод yield работает следующим образом: выполнение функции, содержащей оператор yield, возвращает вызывающей стороне то, что известно как генератор. Генератор — это функция, которую вызывающий абонент может выполнять многократно, пока не завершится.

Вот код, аналогичный приведенному выше, но который использует оператор yield для возврата списка элементов p в HTML.

...
def parse(self, response):
for e in response.css('div#mw-content-text>div>p'):
yield { 'para' : ''.join(e.css('::text').extract()).strip() }
...

Теперь вы можете запустить паука, указав выходной файл JSON следующим образом:

scrapy runspider spider3.py -o joe.json

Сгенерированный вывод выглядит следующим образом:

[
{"para": "An electric battery is a device consisting of one or more electrochemical cells with external connections provided to power electrical devices such as flashlights, smartphones, and electric cars.[1] When a battery is supplying electric power, its positive terminal is the cathode and its negative terminal is the anode.[2] The terminal marked negative is the source of electrons that when connected to an external circuit will flow and deliver energy to an external device. When a battery is connected to an external circuit, electrolytes are able to move as ions within, allowing the chemical reactions to be completed at the separate terminals and so deliver energy to the external circuit. It is the movement of those ions within the battery which allows current to flow out of the battery to perform work.[3] Historically the term \"battery\" specifically referred to a device composed of multiple cells, however the usage has evolved additionally to include devices composed of a single cell.[4]"},
{"para": "Primary (single-use or \"disposable\") batteries are used once and discarded; the electrode materials are irreversibly changed during discharge. Common examples are the alkaline battery used for flashlights and a multitude of portable electronic devices. Secondary (rechargeable) batteries can be discharged and recharged multiple
...

Обработка нескольких битов информации

Давайте теперь посмотрим на извлечение нескольких битов, связанных с информацией. В этом примере мы извлечем лучшие хиты IMDb Box Office за текущие выходные. Эта информация доступна по адресу http://www.imdb.com/chart/boxoffice, в таблице с рядом информации для каждого попадания.

Мы извлекаем различные поля в каждой строке, используя следующий метод parse (). Снова местоположения CSS элемента были определены с помощью Chrome Developer Console, как описано выше:

...
def parse(self, response):
for e in response.css('div#boxoffice>table>tbody>tr'):
yield {
'title': ''.join(e.css('td.titleColumn>a::text').extract()).strip(),
'weekend': ''.join(e.css('td.ratingColumn')[0].css('::text').extract()).strip(),
'gross': ''.join(e.css('td.ratingColumn')[1].css('span.secondaryInfo::text').extract()).strip(),
'weeks': ''.join(e.css('td.weeksColumn::text').extract()).strip(),
'image': e.css('td.posterColumn img::attr(src)').extract_first(),
}
...

Обратите внимание, что селектор изображений выше указывает, что img является потомком td.posterColumn, и мы извлекаем атрибут с именем src, используя выражение :: attr (src).

Запуск паука теперь возвращает следующий JSON:

[
{"gross": "$93.8M", "weeks": "1", "weekend": "$93.8M", "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BYWVhZjZkYTItOGIwYS00NmRkLWJlYjctMWM0ZjFmMDU4ZjEzXkEyXkFqcGdeQXVyMTMxODk2OTU@._V1_UY67_CR0,0,45,67_AL_.jpg", "title": "Justice League"},
{"gross": "$27.5M", "weeks": "1", "weekend": "$27.5M", "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BYjFhOWY0OTgtNDkzMC00YWJkLTk1NGEtYWUxNjhmMmQ5ZjYyXkEyXkFqcGdeQXVyMjMxOTE0ODA@._V1_UX45_CR0,0,45,67_AL_.jpg", "title": "Wonder"},
{"gross": "$247.3M", "weeks": "3", "weekend": "$21.7M", "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BMjMyNDkzMzI1OF5BMl5BanBnXkFtZTgwODcxODg5MjI@._V1_UY67_CR0,0,45,67_AL_.jpg", "title": "Thor: Ragnarok"},
...
]

Использование вашего сканера

Давайте завершим эту статью несколькими существенными моментами:

  • Использование python с scrapy упрощает написание сканеров веб-сайтов для извлечения любой необходимой информации.
  • Консоль разработчика Chrome (или инструмент Firefox Firefox) помогает находить расположения элементов для извлечения.
  • Оператор yield Python помогает извлекать повторяющиеся элементы данных.

Есть ли у вас какие-то конкретные проекты для очистки сайта? И с какими проблемами вы столкнулись, пытаясь добиться успеха? Пожалуйста, дайте нам знать в комментариях ниже.

Кредит изображения: dxinerz / Depositphotos | Lulzmango / Wikimedia Commons

Ссылка на основную публикацию
Adblock
detector