CoderCastrov logo
CoderCastrov
Веб-разработка

Исследование случая: RotoWorld и парсинг ASP.NET

Исследование случая: RotoWorld и парсинг ASP.NET
просмотров
6 мин чтение
#Веб-разработка

Я решил написать краткое описание своего опыта парсинга данных с веб-сайта RotoWorld и парсинга веб-сайтов на ASP.NET в целом, в надежде, что если кто-то из студентов или подобных мне понадобится написать подобную утилиту, у них будет некоторое руководство.

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

Веб-сайт: RotoWorld

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

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


Первоначальные мысли

Первое, что я делаю, когда хочу спарсить веб-сайт, это перехожу на сам веб-сайт и пытаюсь проанализировать, что мне дает DOM. Я сделал обычный поиск, чтобы найти веб-страницу, которая меня интересует, и начал исследовать.

The URL of my first web search

Мой первый веб-поиск случайно привел меня на страницу новостей об игроке НБА. Сначала давайте посмотрим на схему URL. У нас есть хост rotoworld.com, некоторые подкаталоги (или просто определенные маршруты) и некоторые имена. Мы можем сказать, что эта страница доступна, вероятно, перейдя в раздел NBA->Kyrie Irving. Теперь я задаюсь вопросом, что означают эти числа, если они вообще что-то означают.

Я делаю похожий поиск, на этот раз для другого игрока НБА, и что вы думаете

The URL of my second web search

У него было другое число. Из этого можно сделать вывод, даже не заглядывая в инструмент "Исследовать элемент", который я буду использовать в дальнейшем, я могу понять, как работает схема URL. Теперь это было особенно важно для меня, потому что я хочу спарсить нескольких игроков одновременно, и идея того, что мне придется вручную или, что еще хуже, написать еще один скрипт, чтобы получить все их уникальные идентификаторы игроков, не звучала идеально в то время. Поэтому я провел немного экспериментов. Я попробовал дать разные идентификаторы с произвольными номерами игроков, чтобы увидеть, как реагирует веб-сайт. Из своих исследований я обнаружил нечто, что будет важным для меня позже:

RotoWorld не заботится о имени игрока, указанном в URL. Все, что имеет значение, - это наличие действительного идентификатора игрока.

Вооружившись этим знанием, я погрузился в свой любимый инструмент - инспектор элементов, и приступил к работе.

Инспектор элементов и вкладка "Сеть"

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

Просмотрев отображаемую веб-страницу, я сначала определился, что я хочу получить. Вся необходимая информация находится в таблице в разделе "Новости об игроке". Я заметил кнопку "Старые", что означает, что для доступа к данным, которые не видны на веб-странице, мне придется нажать эту кнопку.

И вот лучшая часть. Все мои первоначальные предположения оказались абсолютно неверными! Это самая лучшая часть всего этого опыта парсинга. Вы пытаетесь работать вокруг реализации другого человека. Несмотря на то, что я могу думать одним образом, разработчик(и), создавшие этот веб-сайт, имеют полное право думать по-другому. Главное здесь - адаптироваться к возможностям.

Вкладка 'Сеть'!!!

Следующий шаг - перейти на вкладку "Сеть" в инспекторе элементов. Это мощный инструмент, доступный в Chrome и FireFox (и, возможно, в Safari?). С помощью этого меню вы можете видеть все заголовки запросов, заголовки ответов, данные формы, параметры. Все это.

Есть несколько вещей, о которых я должен сказать, прежде чем я приступлю к конкретному случаю RotoWorld. Фактически я хочу скачать базу данных кого-то. Без сомнения, существует некоторый вид базы данных, будь то SQL, NoSQL или набор CSV-файлов, с которыми работает бэкэнд, чтобы предоставить эти данные. Как он заполняет таблицу или другую структуру DOM, относительно просто навигироваться. Самая сложная задача, которую мы выполняем, - это попытка связаться с бэкэндом, чтобы он предоставил нам базу данных в наиболее простой форме.

При парсинге веб-сайтов всегда важно посмотреть, есть ли у него какое-то API. Большинство API разработаны таким образом, чтобы предоставить конечному потребителю наиболее удобные данные. Если его нет, попробуйте просмотреть сетевые запросы. Иногда веб-сайты делают запросы, результатом которых являются JSON-ответы, содержащие данные в разбираемом формате. Худший вариант - отсутствие доступа к базовому API и простое чтение DOM и навигация по нему.

В данном случае мы имеем дело с худшим вариантом.

Просмотрев ответы пакетов, я вижу, что мой первый запрос - это GET-запрос к URL, на который перешел мой браузер, без перенаправлений или дополнительных запросов для получения начальных данных. Просматривая фактический HTML, который рендерит Chrome, я встречаю следующее

По сути, все эти "элементы таблицы" на самом деле окружены серией CSS-стилей. Это не так уж и тревожно с точки зрения получения данных, BeautifulSoup делает этот процесс тривиальным, настоящая проблема возникает, когда я пытаюсь выяснить, что делает кнопка "Старые".

Это точно ввод, но без ссылки. Ничего. Я нажимаю на нее и читаю вывод пакета, чтобы узнать, есть ли что-то, что может мне помочь

POST-запрос? На тот же веб-сайт?

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

Прежде всего, давайте посмотрим на параметры POST-запроса. Что отправляется на сервер.

На этом скриншоте не указано еще одно поле, которое содержит сотни бессмысленных символов, уникально идентифицирующих наше событие и ситуацию. Теперь мы знаем, что все эти данные отправляются в теле POST-запроса, поэтому, если мы сделаем то же самое, мы сможем получить похожие результаты. Если вас интересует, как создавать POST- и GET-запросы на Python, поищите "requests" и "BeautifulSoup".

Все это тело POST-запроса на самом деле является частью начального ответа на первый GET-запрос, который я сделал на веб-сайт. Посмотрите на нашу начальную веб-страницу и найдите слова "EVENTVALIDATION"

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

Теперь самая сложная часть. Чтобы фактически спарсить веб-сайт, вам нужно написать свой скрипт для рекурсивного вставления этих параметров в ваши запросы по мере навигации и парсинга веб-страницы. Вот и все! Если ваша программа не работает, вот отображаемый вывод ошибки, который я смог получить, спамя бессмысленными параметрами POST из-за гнева.

Эта ошибка сообщила мне, что веб-сайт не принимает мой POST-запрос, потому что тело запроса было неправильно сформировано. Если вы изучите спецификацию ошибки в документации Microsoft ASP.NET, вы узнаете, что причина, по которой бэкэнд вообще выдает ошибку, заключается в том, что он настроен не принимать запросы, которые не прошли правильную проверку контролем.

Моя конкретная реализация того, как я сканировал все необходимые данные POST. Затем я просто написал простой парсер BeautifulSoup для чтения всех данных.


Резюме: Завершение

При парсинге веб-сайтов на ASP.NET вам, скорее всего, придется проверять события с помощью кода управления, который находится в исходном коде сайта. Использование комбинации вкладок "Сеть" и "Элемент" будет крайне важным для определения того, как сайт реализует свою структуру управления. Фактическое написание POST-запроса тривиально, как только вы определите элементы, которые вам нужно прочитать из исходного кода.

По всем вопросам или для получения конкретной помощи свяжитесь со мной: cheenar@mail.usf.edu