Рубрики
Без рубрики

Введение в Scrapy: Веб-скребок в Python

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

Автор оригинала: Adarsh Punj.

Эта статья была первоначально опубликована в Pythongasm

Вступление

Scrapy-это веб-фреймворк с открытым исходным кодом, и он делает гораздо больше, чем просто библиотека. Он управляет запросами, анализирует веб-страницы HTML, собирает данные и сохраняет их в нужном формате. Следовательно, вам не нужны отдельные библиотеки для каждого второго шага. Вы также можете использовать промежуточное программное обеспечение в scrapy. Промежуточные программы-это своего рода “плагины”, которые добавляют дополнительные функции в scrapy. Существует множество промежуточного программного обеспечения с открытым исходным кодом, которое мы можем прикрепить к scrapy для дополнительных функций. В этой статье вы узнаете, как собирать данные с веб-страниц с помощью scrapy. Более конкретно, мы будем очищать Craigslist и собирать некоторые данные о недвижимости с их веб-страницы. Было бы неплохо иметь некоторый опыт работы с HTML/CSS, но вы можете продолжить, даже если вы не знакомы с HTML, поскольку небольшая часть этой статьи была посвящена HTML.

Установка

Убедитесь, что вы используете Python 3. Откройте терминал и выполните следующую команду:

pip install scrapy

Скребковая оболочка

Вы не захотите отправлять новые запросы каждый раз, когда вам придется вносить небольшие изменения в свой код. Вместо этого более логично “сохранить” веб-страницу локально с помощью одного запроса, а затем посмотреть, как вызывать функции и извлекать данные. Вот почему мы используем scrapy shell для отладки. Это быстро, легко и эффективно.

Выполните эту команду, чтобы запустить оболочку scrapy:

scrapy shell

Мы очищаем раздел недвижимости Craigslist (Нью-Йорк) по адресу: https://newyork.craigslist.org/d/real-estate/search/rea

(Вы можете перейти на newyork.craigslist.com, и выберите недвижимость из списка вариантов)

Мы используем функцию fetch() для извлечения ответа из URL-адреса.

fetch("https://newyork.craigslist.org/d/real-estate/search/rea")

Это вернет a Html-ответ объект, хранящийся в переменной response .

Вы можете просмотреть этот ответ (который сохраняется локально на устройстве) в своем браузере:

view(response)

Разбор HTML

Давайте рассмотрим этот пример:

Фрагмент HTML-кода

Чтобы проанализировать веб-страницу, мы находим элементы, используя имя тега и/или класс CSS этого тега. Мы можем поручить нашему пауку найти тег h2 , который имеет “заголовок main” в качестве своего CSS-класса, и он вернет нам этот фрагмент. В этом случае есть только один тег h2 , поэтому нам даже не нужно указывать имя класса, мы можем просто сказать нашему пауку искать тег h2 , и он вернет нам этот фрагмент. Если мы хотим получить тег span внутри тега h2 , мы можем либо получить его, указав id , ЛИБО сообщив скребку, что мы ищем тот, который находится внутри тега h2 . Цель состоит в том, чтобы ваш скребок однозначно идентифицировал элемент, который вы ищете.

Теперь давайте вернемся к браузеру и найдем название веб-страницы, которую мы только что загрузили. Щелкните правой кнопкой мыши на веб-странице и выберите Проверить. Заголовки обычно присутствуют внутри тега head .

Заглавие

Мы используем эту функцию css () (также называемую селектором CSS) для выбора элементов веб-страницы. Например, мы можем выбрать тег title следующим образом:

response.css("title")
[]

функция css() возвращает список (называемый Selector List ), и каждый элемент этого списка является объектом Selector . На веб-странице есть только один тег title , поэтому неудивительно, что длина этого списка равна 1.

Однако это не желаемый результат. Мы ищем текст внутри заголовка, а не весь HTML. Чтобы получить текст внутри тега, мы используем ::text :

response.css("title::text")
[

Вы можете видеть , что данные в выходных данных теперь изменились на data='new york real estate' , что является текстом внутри тега title .

Мы можем получить строковые значения из Селектора объектов, вызвав для них функцию get () .

response.css("title::text")[0].get()
'new york real estate - craigslist'

Интересно, что когда вы вызываете функцию get() непосредственно в списке ( Список селекторов ), она по-прежнему дает вам тот же результат.

response.css("title::text").get()
'new york real estate - craigslist'

Это связано с тем, что при вызове функции get() без указания индекса она возвращает строковое значение самого первого элемента в списке SelectorList . Другими словами, вы можете вызвать get() в списке селекторов , и вместо того, чтобы выдавать ошибку, он вызывает функцию get () для первого элемента в списке.

У нас есть еще один метод, называемый get all() . Эта функция просто вызывает функцию get() для каждого элемента в списке селекторов . Следовательно, функция getall() может быть вызвана в списке селекторов для получения списка строк.

Резюме

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

Скраповый проект

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

scrapy startproject craigslist

Это создаст папку “craigslist” в вашем текущем рабочем каталоге со следующей структурой:

Структура каталога craigslist

Перейдите в каталог пауков. Именно здесь мы будем спасать наших пауков (краулеров). Вы можете создать там новый файл python и начать писать код. Однако мы также можем выполнить следующую команду, чтобы сгенерировать паука с некоторым начальным кодом.

scrapy genspider realestate newyork.craigslist.org/d/real-estate/search/rea

Теперь откройте realestate.py файл в каталоге пауков. Это должно выглядеть так:

import scrapy class RealestateSpider(scrapy.Spider): name = 'realestate' allowed_domains = ['https://newyork.craigslist.org/d/real-estate/search/rea'] start_urls = ['http://https://newyork.craigslist.org/d/real-estate/search/rea/'] def parse(self, response): pass

Когда мы запускаем паука, запрос отправляется на все URL-адреса внутри start_urls . Это специальная переменная, которая автоматически вызывает функцию parse() и передает ответ в качестве аргумента.

функция parse () – это место, где мы будем писать наш код для анализа ответа. Давайте определим это так:

def parse(self, response): print("\n") print("HTTP STATUS: "+str(response.status)) print(response.css("title::text").get()) print("\n")

Сохраните файл и запустите паука с помощью этой команды:

scrapy crawl realestate
HTTP STATUS 200
new york real estate - craigslist

Теперь давайте извлекем другие элементы на веб-странице. Проверьте HTML-код первого объявления. (Щелкните правой кнопкой мыши > Проверить элемент, который вы хотите проверить):

Проверить

Вы можете увидеть всю информацию об этом объявлении (название, дата, цена и т.д.) Внутри этого тега p с именем класса “result-info”

На веб-странице должно быть 120 (или равно количеству списков) таких фрагментов.

allAds = response.css("p.result-info")

Это позволит выбрать все такие фрагменты и составить из них список Селекторов|/.

Давайте попробуем извлечь данные, цену, заголовок объявления и гиперссылку из первого объявления

firstAd = allAds[0]

Дата присутствует внутри тега time . Поскольку здесь есть только один тег time , нам не нужно указывать здесь имя класса CSS:

date = firstAd.css("time").get()

Теперь извлеките заголовок и гиперссылку из объявления, которые присутствуют внутри тега a . Нам нужно удалить пробелы в имени класса CSS с помощью . :

title = firstAd.css("a.result-title.hdrlnk::text").get()
link = firstAd.css("a.result-title.hdrlnk::attr(href)").get()

Кроме того, как вы можете видеть, мы добавляем ::attr() в аргумент для извлечения атрибутов, таких как src , href из тегов.

Наконец, нам нужно найти цену, которая находится внутри тега span с именем класса “result-price”:

price = firstAd.css("span.result-price::text").get()

Давайте завершим функцию parse () . Нам просто нужно перебрать список Селекторов и получить подробную информацию из Селектора объектов внутри него , как мы сделали с первым Селектором объектом

def parse(self, response): allAds = response.css("p.result-info") for ad in allAds: date = ad.css("time::text").get() title = ad.css("a.result-title.hdrlnk::text").get() price = ad.css("span.result-price::text").get() link = ad.css("a::attr(href)").get() print("====NEW PROPERTY===") print(date) print(title) print(price) print(link) print("\n")

Запустите этого паука еще раз, и вы увидите такой результат:

Мы успешно очистили нужные нам данные из Craigslist. Вы всегда можете включить дополнительную информацию, которую, возможно, захотите извлечь. С небольшими изменениями мы также можем очистить следующие несколько страниц Craigslist (2,3,4 и так Далее).

Экспорт данных

Теперь пришло время структурировать его, как только у нас будет готов скребок, и сделать полезный набор данных. Это довольно легко сделать.

Перейдите в Craigslist > Craigslist > items.py

Вам просто нужно определить новые атрибуты элемента Craigslist класса (это очень похоже на класс словаря Python):

import scrapy

`class CraigslistItem(scrapy.Item): date = scrapy.Field() title = scrapy.Field() price = scrapy.Field() link = scrapy.Field()
`

Откройте realestate.py файл и импортируйте элемент Craigslist класс из items.py:

from ..items import CraigslistItem

Создайте экземпляр этого класса, называемый items , и назначьте значения точно так же, как вы сделали бы со словарем.

def parse(self, response): allAds = response.css("p.result-info") for ad in allAds: date = ad.css("time::text").get() title = ad.css("a.result-title.hdrlnk::text").get() price = ad.css("span.result-price::text").get() link = ad.css("a.result-title.hdrlnk::attr(href)").get() items = CraigslistItem() items['date'] = date items['title'] = title items['price'] = price items['link'] = link yield items

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

Запустите паука с аргументом -o output.csv вот так:

scrapy crawl realestate -o output.csv

Вы обнаружите, что выходные данные были сохранены в родительском каталоге (Craigslist). Помимо CSV, вы также можете экспортировать данные в другие форматы, такие как JSON, XML и т.д.

Настройки Scrapy

Перейдите в craigslist > craigslist > settings.py. Этот файл в основном позволяет вам настраивать множество вещей.

Например, перед обходом веб-страницы пауки scrapy посещают robots.txt файл для проверки разрешений/ограничений, установленных владельцем сайта для веб-искателей. Если конкретная страница, которую вы хотите очистить, “ограничена” веб-сайтом, scrapy не перейдет на эту страницу. Однако вы можете отключить эту функцию, просто изменив значение ROBOTS TXT_OBEY на False в settings.py файл, и ваш искатель перестанет следовать рекомендациям внутри robots.txt.

Аналогично, вы можете настроить пользовательский агент вашего искателя (строки пользовательского агента-это идентификаторы, с помощью которых веб-сайт распознает, какой запрос он получает). Вы можете прочитать больше о user-agent здесь . Допустим, вы хотите подделать пользовательский агент Google Chrome (работающий на macOS). Вы можете назначить строку агента пользователя USER_AGENT

USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36".

Вывод

Это было знакомство со скрэпи. Как мы уже обсуждали, есть много других вещей, которые мы можем сделать с помощью scrapy (или веб-скребка в целом). Существует множество общедоступных веб-сайтов, которые вы, возможно, захотите очистить и преобразовать их содержимое в огромные наборы данных для последующего использования (визуализация, прогнозирование и т. Д.). Например, вы можете очистить все твиты, сделанные пользователем. Надеюсь, вам понравилось читать эту статью.

Дальнейшие показания