Использование инструментов разработчика вашего браузера для парсинга

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

В этом руководстве мы познакомим вас с основными инструментами, которые можно использовать из инструментов разработчика браузера, сканировав quotes.toscrape.com.

Предостережения при проверке живого DOM браузера

Поскольку инструменты разработчика работают с активной DOM браузера, то, что вы фактически увидите при проверке источника страницы, — это не исходный HTML, а измененный после применения некоторой очистки браузера и выполнения кода Javascript. В частности, Firefox известен тем, что добавляет в таблицы элементы <tbody>. Scrapy, с другой стороны, не изменяет исходный HTML-код страницы, поэтому вы не сможете извлечь какие-либо данные, если используете <tbody> в своих XPath выражениях.

Поэтому следует иметь в виду следующее:

  • Отключает Javascript при проверке DOM в поисках XPath для использования в Scrapy (в настройках инструментов разработчика нажмите «Отключить JavaScript»)

  • Никогда не используйте полные пути XPath, используйте относительные и умные, основанные на атрибутах (например, id, class, width и т. д.) Или любых идентифицирующих функциях, таких как contains(@href, 'image').

  • Никогда не включайте элементы <tbody> в выражения XPath, если вы действительно не знаете, что делаете

Проверка веб-сайта

Безусловно, самая удобная функция Developer Tools — это сайт Inspector функция, которая позволяет вам проверять базовый HTML-код любой вебстраницы. Чтобы продемонстрировать Инспектор, давайте посмотрим на quotes.toscrape.com.

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

Вместо того, чтобы просматривать весь исходный код страницы, мы можем просто щелкнуть правой кнопкой мыши по цитате и выбрать Inspect Element (Q), что откроет Inspector. В нем вы должны увидеть что-то вроде этого:

Инспектор Firefox

Для нас самое интересное:

<div class="quote" itemscope="" itemtype="http://schema.org/CreativeWork">
  <span class="text" itemprop="text">(...)</span>
  <span>(...)</span>
  <div class="tags">(...)</div>
</div>

Если вы наведете курсор на первый div непосредственно над тегом span, выделенным на снимке экрана, вы увидите, что соответствующий раздел веб-страницы также будет выделен. Итак, теперь у нас есть раздел, но мы нигде не можем найти текст цитаты.

Преимущество «Inspector» в том, что он автоматически разворачивает и сворачивает разделы и теги веб-страницы, что значительно улучшает читаемость. Вы можете развернуть и свернуть тег, щелкнув стрелку перед ним или дважды щелкнув непосредственно на теге. Если мы расширим тег span до class= "text", мы увидим текст цитаты, на который мы нажали. Инспектор позволяет копировать XPath в выбранные элементы. Давай попробуем.

Сначала откройте оболочку Scrapy по адресу http://quotes.toscrape.com/ в терминале:

$ scrapy shell "http://quotes.toscrape.com/"

Затем вернитесь в свой веб-браузер, щелкните правой кнопкой мыши тег span, выберите Copy > XPath и вставить его в оболочку Scrapy вот так:

>>> response.xpath('/html/body/div/div[2]/div[1]/div[1]/span[1]/text()').getall()
['“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”']

Добавив в конце text(), мы можем извлечь первую цитату с помощью этого базового селектора. Но данный XPath на самом деле не настолько умён. Все, что он делает, — это идёт по желаемому пути в исходном коде, начиная с html. Итак, давайте посмотрим, сможем ли мы немного улучшить наш XPath:

Если мы снова проверим «Inspector», то увидим, что непосредственно под нашим расширенным тегом div у нас есть девять идентичных тегов div, каждый с теми же атрибутами, что и наш первый. Если мы развернем любой из них, мы увидим ту же структуру, что и в нашей первой цитате: два тега span и один тег div. Мы можем расширить каждый тег span с помощью class="text" внутри наших тегов div и увидеть каждую цитату:

<div class="quote" itemscope="" itemtype="http://schema.org/CreativeWork">
  <span class="text" itemprop="text">
    “The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”
  </span>
  <span>(...)</span>
  <div class="tags">(...)</div>
</div>

Обладая этими знаниями, мы можем усовершенствовать наш XPath: вместо того, чтобы идти по пути, мы просто выберем все теги span с помощью class="text" с помощью has-class-extension:

>>> response.xpath('//span[has-class("text")]/text()').getall()
['“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”',
'“It is our choices, Harry, that show what we truly are, far more than our abilities.”',
'“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”',
...]

А с помощью одного простого и более умного XPath мы можем извлечь все цитаты со страницы. Мы могли бы построить цикл для нашего первого XPath, чтобы увеличить номер последнего div, но это было бы излишне сложно, и, просто построив XPath с has-class("text"), мы смогли извлечь все цитаты в одну строку.

«Inspector» имеет множество других полезных функций, таких как поиск в исходном коде или прямая прокрутка к выбранному вами элементу. Продемонстрируем вариант использования:

Допустим, вы хотите найти кнопку Next на странице. Введите Next в строку поиска в правом верхнем углу «Inspector». Вы должны получить два результата. Первый — это тег li с class="next", второй — текст тега a. Щёлкните правой кнопкой мыши тег a и выберите Scroll into View. Если вы наведете курсор на тег, вы увидите, что кнопка выделена. Отсюда мы могли бы легко создать Извлечение ссылок, чтобы следовать нумерации страниц. На таком простом сайте, как данный, может не потребоваться визуальный поиск элемента, но функция Scroll into View может быть весьма полезной на сложных сайтах.

Обратите внимание, что панель поиска также можно использовать для поиска и тестирования селекторов CSS. Например, вы можете выполнить поиск по запросу span.text, чтобы найти все тексты цитат. Вместо полнотекстового поиска выполняется поиск именно по тегу span с class="text" на странице.

Сетевой инструмент

При парсинге вы можете встретить динамические веб-страницы, на которых некоторые части страницы загружаются динамически через несколько запросов. Хотя это может быть довольно сложно, Network-tool в Developer Tools значительно облегчает эту задачу. Чтобы продемонстрировать Network-tool, давайте посмотрим на страницу quotes.toscrape.com/scroll.

Эта страница очень похожа на базовую страницу quotes.toscrape.com, но вместо вышеупомянутой кнопки Next страница автоматически загружает новые цитаты при прокрутке вниз. Мы могли бы попробовать разные XPath напрямую, но вместо этого мы проверим другую довольно полезную команду из оболочки Scrapy:

$ scrapy shell "quotes.toscrape.com/scroll"
(...)
>>> view(response)

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

Ответ с сайта quotes.toscrape.com/scroll

Команда view(response) позволяет нам просмотреть ответ, который наша оболочка или более поздняя версия нашего паука получает от сервера. Здесь мы видим, что загружен некий базовый шаблон, который включает заголовок, кнопку входа и нижний колонтитул, но кавычки отсутствуют. Это говорит нам о том, что котировки загружаются из другого запроса, чем quotes.toscrape/scroll.

Если вы щелкните вкладку Network, вы, вероятно, увидите только две записи. Первое, что мы делаем, это включаем постоянные журналы, щёлкнув Persist Logs. Если данный параметр отключён, журнал автоматически очищается каждый раз, когда вы переходите на другую страницу. Включение этой опции — хороший вариант по умолчанию, поскольку он дает нам контроль над тем, когда очищать журналы.

Если мы перезагрузим страницу сейчас, вы увидите, что журнал заполнен шестью новыми запросами.

Таб Network с постоянными журналами и запросами

Здесь мы видим каждый запрос, сделанный при перезагрузке страницы, и можем проверить каждый запрос и его ответ. Итак, давайте выясним, откуда берутся наши цитаты:

Сначала нажмите на запрос с названием scroll. Справа теперь вы можете просмотреть запрос. В Headers вы найдете подробную информацию о заголовках запросов, таких как URL-адрес, метод, IP-адрес и так далее. Мы проигнорируем другие табы и нажмем прямо на Response.

На панели Preview вы должны увидеть визуализированный HTML-код, это именно то, что мы видели, когда вызывали view(response) в оболочке. Соответственно type запроса в журнале — html. Другие запросы имеют типы вроде css или js, но нас интересует один запрос с именем quotes?page=1 с типом json.

Если мы щелкнем по этому запросу, мы увидим, что URL-адрес запроса — http://quotes.toscrape.com/api/quotes?page=1, а ответ — это JSON-объект, содержащий наши цитаты. Мы также можем щелкнуть запрос правой кнопкой мыши и открыть Open in new tab, чтобы получить лучший обзор.

JSON-объект, возвращённый API quotes.toscrape

С помощью этого ответа мы теперь можем легко проанализировать JSON-объект, а также запросить каждую страницу, чтобы получить каждую цитату на сайте:

import scrapy
import json


class QuoteSpider(scrapy.Spider):
    name = 'quote'
    allowed_domains = ['quotes.toscrape.com']
    page = 1
    start_urls = ['http://quotes.toscrape.com/api/quotes?page=1']

    def parse(self, response):
        data = json.loads(response.text)
        for quote in data["quotes"]:
            yield {"quote": quote["text"]}
        if data["has_next"]:
            self.page += 1
            url = f"http://quotes.toscrape.com/api/quotes?page={self.page}"
            yield scrapy.Request(url=url, callback=self.parse)

Данный паук запускается на первой странице кавычки-API. С каждым ответом мы анализируем response.text и присваиваем ему data. Это позволяет нам работать с JSON-объектом, как со словарем Python. Мы перебираем quotes и распечатываем quote["text"]. Если удобный элемент has_next — это true (попробуйтк загрузить quotes.toscrape.com/api/quotes?page=10 в вашем браузере или номер страницы больше 10), мы увеличиваем атрибут page, а yield — новый запрос, вставляя увеличенный номер страницы в наш url.

На более сложных веб-сайтах может быть сложно легко воспроизвести запросы, поскольку нам может потребоваться добавить headers или cookies, чтобы заставить его работать. В данных случаях вы можете экспортировать запросы в формате cURL, щёлкнув правой кнопкой мыши по каждому из них в сетевом инструменте и используя метод from_curl() для создания эквивалентного запроса:

from scrapy import Request

request = Request.from_curl(
    "curl 'http://quotes.toscrape.com/api/quotes?page=1' -H 'User-Agent: Mozil"
    "la/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0' -H 'Acce"
    "pt: */*' -H 'Accept-Language: ca,en-US;q=0.7,en;q=0.3' --compressed -H 'X"
    "-Requested-With: XMLHttpRequest' -H 'Proxy-Authorization: Basic QFRLLTAzM"
    "zEwZTAxLTk5MWUtNDFiNC1iZWRmLTJjNGI4M2ZiNDBmNDpAVEstMDMzMTBlMDEtOTkxZS00MW"
    "I0LWJlZGYtMmM0YjgzZmI0MGY0' -H 'Connection: keep-alive' -H 'Referer: http"
    "://quotes.toscrape.com/scroll' -H 'Cache-Control: max-age=0'")

В качестве альтернативы, если вы хотите узнать аргументы, необходимые для воссоздания этого запроса, вы можете использовать функцию curl_to_request_kwargs(), чтобы получить словарь с эквивалентными аргументами:

Обратите внимание, что для преобразования команды cURL в запрос Scrapy вы можете использовать curl2scrapy.

Как видите, с помощью нескольких проверок в инструменте «Network» мы смогли легко воспроизвести динамические запросы функции прокрутки страницы. Сканирование динамических страниц может быть довольно сложным, а страницы могут быть очень сложными, но это (в основном) сводится к определению правильного запроса и воспроизведению его в вашем пауке.