Перейти к содержимому

Request parser что это

  • автор:

Net::HTTP — Универсальный базовый парсер с поддержкой многостраничного парсинга и обходом CloudFlare

Обзор парсераNet::HTTPNet::HTTP – это универсальный парсер, который позволяет решать большинство нестандартных задач. Может быть использован как основа для для парсинга произвольного контента с любых сайтов. Позволяет скачать код страницы по ссылке, поддерживает многостраничный парсинг (переход по страницам), автоматическую работу с прокси, позволяет выполнить проверку успешного ответа по коду или по содержимому страницы.

Кейсы по применению парсера​

�� Аукцион доменов REG.RU

Парсинг аукциона свобождающихся доменов с возможностью фильтрации

�� Данные по SSL сертификату

Парсинг данных SSL сертификата доменов с сайта leaderssl.ru

�� Парсинг ресурса Booking.com

Получение результатов поиска квартир и отелей на сайте

�� Сбор характеристик товара

Пример парсинга неизвестного количества характеристик товара

�� Парсинг базы фильмов из IMDB

Получает данные о каждом фильме и записывает их в результат

�� Проверка наличия HTTPS

Пресет проверяет наличие HTTPS на сайте

Собираемые данные​

Собираемые данные

  • Контент
  • Код ответа сервера
  • Описание ответа сервера
  • Заголовки ответа сервера
  • Прокси, использованные при запросе
  • Массив со всеми собранными страницами (используется при работе опции Use Pages)

Возможности​

  • Многостраничный парсинг (переход по страницам)
  • Автоматическая работа с прокси
  • Проверка успешного ответа по коду или по содержимому страницы
  • Поддерживает сжатия gzip/deflate/brotli
  • Определение и преобразование кодировок сайтов в UTF-8
  • Обход защиты CloudFlare
  • Выбор движка (HTTP или Chrome)
  • Опция Check content – выполняет указанное регулярное выражение на полученной странице. Если выражение не сработало, страница будет загружена заново с другой прокси.
  • Опция Use Pages – позволяет перебрать указанное количество страниц с определенным шагом. Переменная $pagenum содержит текущий номер страницы при переборе.
  • Опция Check next page – необходимо указывать регулярное выражение, которое будет извлекать ссылку на следующую страницу (обычно кнопка «Вперёд»), если она существует. Переход между страницами осуществляется в рамках указанного лимита (0 — без ограничений).
  • Опция Page as new query – переход на следующую страницу происходит в новом запросе. Позволяет убрать ограничение на количество страниц для перехода.

Варианты использования​

  • Скачивание контента
  • Скачивание картинок
  • Проверка кода ответа сервера
  • Проверка наличия HTTPS
  • Проверка наличия редиректов
  • Вывод списка URL редиректов
  • Получение размера страницы
  • Сбор мета-тегов
  • Извлечение данных из исходного кода страницы и/или заголовков

Запросы​

В качестве запросов необходимо указывать ссылки на страницы, например:

http://lenta.ru/ http://a-parser.com/pages/reviews/ 

Варианты вывода результатов​

A-Parser поддерживает гибкое форматирование результатов благодаря встроенному шаблонизатору Template Toolkit, что позволяет ему выводить результаты в произвольной форме, а также в структуированной, например CSV или JSON

Вывод контента​

$data 
DOCTYPE html>html id="XenForo" lang="ru-RU" dir="LTR" class="Public NoJs uix_javascriptNeedsInit LoggedOut Sidebar Responsive pageIsLtr hasTabLinks hasSearch is-sidebarOpen hasRightSidebar is-setWidth navStyle_0 pageStyle_0 hasFlexbox" xmlns:fb="http://www.facebook.com/2008/fbml"> head>     meta charset="utf-8" /> meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" /> meta name="viewport" content="width=device-width, initial-scale=1" /> base href="https://a-parser.com/" /> title>A-Parser - парсер для профессионалов SEOtitle> noscript>style>.JsOnly, .jsOnly  display: none !important; >style>noscript> link rel="stylesheet" href="css.php?css=xenforo,form,public,parser_icons&style=9&dir=LTR&d=1612857138" /> link rel="stylesheet" href="css.php?css=facebook,google,login_bar,moderator_bar,nat_public_css,node_category,node_forum,node_list,notices,panel_scroller,resource_list_mini,sidebar_share_page,thread_list_simple,twitter,uix_extendedFooter&style=9&dir=LTR&d=1612857138" /> link rel="stylesheet" href="css.php?css=uix,uix_style&style=9&dir=LTR&d=1612857138" /> 

Код ответа сервера​

$code 

Формат результата [% response.Redirects.0.Status || сode %] позволяет выводить статус 301, если в запросе присутствуют редиректы.

Получение данных о запросе​

Переменная $response помогает получить о запросе и ответе сервера

$response.json\n 
  "Time": 3.414, "connection": "keep-alive", "Decode": "Decode from utf-8(meta charset)", "cache-control": "max-age=3600,public", "last-modified": "Tue, 18 May 2021 12:42:56 GMT", "transfer-encoding": "chunked", "date": "Thu, 27 May 2021 14:18:42 GMT", "Status": 200, "content-encoding": "gzip", "Body-Length-Decoded": 1507378, "Reason": "OK", "Proxy": "http://51.255.55.144:25302", "content-type": "text/html", "Redirects": [], "server": "nginx", "Request-Raw": "GET / HTTP/1.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9\r\nConnection: keep-alive\r\nHost: a-parser.com\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)\r\n\r\n", "URI": "https://a-parser.com/", "HTTPVersion": "1.1", "Body-Length": 299312, "Decode-Mode": "auto-html", "etag": "W/\"60a3b650-170032\"", "Decode-Time": 0.003, "IP": "remote", "expires": "Thu, 27 May 2021 15:18:42 GMT" > 

Получение редиректов​

https://google.it 
$response.Redirects.0.URI -> $response.URI 
https://google.it/ -> https://www.google.it/ 

JSON с редиректами​

$response.Redirects.json 
["x-powered-by":"PleskLin","connection":"keep-alive","URI":"http://a-parser.com/","location":"https://a-parser.com/","date":"Thu, 18 Feb 2021 09:16:36 GMT","HTTPVersion":"1.1","Status":301,"content-length":"162","Reason":"Moved Permanently","Proxy":"socks5://51.255.55.144:29683","content-type":"text/html","IP":"remote","server":"nginx","Request-Raw":"GET / HTTP/1.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9\r\nConnection: keep-alive\r\nHost: a-parser.com\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)\r\n\r\n">] 

Вывод статуса ответа сервера​

$reason 

Время ответа сервера​

$response.Time 
1.457 

Получение размера страницы​

В качестве примера размер представлен в трех разных вариантах.

[% "data-length: " _ data.length _ "\n"; "Body-Length: " _ response.$'Body-Length'> _ "\n"; "Body-Length-Decoded: " _ response.$'Body-Length-Decoded'> _ "\n" %] 
data-length: 70257 Body-Length: 23167 Body-Length-Decoded: 75868 

Обработка результатов​

A-Parser позволяет обрабатывать результаты непосредственно во время парсинга, в этом разделе мы привели наиболее популярные кейсы для парсера Net::HTTP

Вывод заголовков H1-H6​

Добавить регулярку (опция Использовать регулярку) (.+?) , в поле «Применить к» выбрать $pages.$i.data — Page content , в поле напротив регулярки выбрать модификаторы sg . В качестве типа результата будет автоматически выбран массив. В поле «Имя» указать headers , в «$1 to» указать tag , нажать на плюсик напротив и в «$2 to» указать content . В Формате результата использовать $p1.headers.format(‘$content\n’) .

eJx9VE1v2zAM/SsFkcMGBEFy2MW3NFiKDVnTNekpyEGNaUOLLGmSnDUw/N9H+ktO N/Rmko+PfCTlCoLwZ//k0GPwkBwqsM03JLD7miQPxuQK7zZSn/3di5a/S4QpWOE8 OoYfRigKpJiJUgWYVhCuFonEXNA5mXJQpmRbZ96uDoOT6Ml3Eapk2GI+n0P9QZrI 8WRKHWLO4gO44n4tOk4bZcxHKWUvhuRyy8kBSJMlByfDcdoh9i3cU8c6h977oMyr UJAEV2J9PPYsfm1cIXh4E7uYdZMcgjtxwb2hYCZVrOzXZD2KgqtMUhGQo7OsIfr0 eRbemEGkqQzSaKHaCjz7WLVbTALaEJY+ebprZwpyBWwI2HntuzvApLGjyp9tDiSZ UB6n4KnVtaBG0vcRGdCJYNzWcj/kr8DopVIbvKCKsIb/vpQqpUNZZpT0rUv8P2T7 D0c9yBuXokX/cdTDwNJY99sfMSs1G5OT8vS1WWYhA9l+1VxPAnNynhHtMLNHnllh HA5lOuauOr0Ni5qvKq5saaPrRsbNWm6dJ6MzmW+7S+2Rpd7TA9zqlSmsQtalS6Vo LR6f43ksfbcGNmKD75NXTQmW3r9DCMYo/33XtmqdpPP7wg0WNMlx1Y7yJJR6ed6M IxBPqjknz7QnutPc0AWRivo4/BGG/0g1/i8kVU1r+eWfWhBrYAj5aBieZs6P+S/t 6pW4 
  • Использование регулярных выражений
  • Форматирование и представление результатов

Сбор мета-тегов​

Добавить регулярку (опция Использовать регулярку) (]+>) , в поле «Применить к» выбрать $pages.$i.data — Page content , в поле напротив регулярки выбрать модификатор g . В качестве типа результата будет автоматически выбран массив. В поле «Имя» указать meta , в «$1 to» указать item . В Формате результата использовать $p1.meta.format(‘$item\n’) .

eJxtVO9v2jAQ/V8spBatg/XDvkRTJYqEtokRRtNPNJMscsk8/Gu2Q0FR/vfeJSGB bp/ie37v3Z3PTsUC93u/duAheBZtK2abNYtYBjkvZWB3zHLnwdH2lq0gRNHXJFkj 3jMqFk4WULMrfTBqA74VunYRbdGiAE8SHjhLaaeAIwpuvygIfPvrIf3wMGYdnrRm Re/QAdw5fkKw+a64IozkPY9KZCKAYmmdpj26ME5xamlk7yckmOQNcnszIvLLi74Z Dx5P/ACJQXYuJAzwAqMu5wi7ANo9+4wn4Uj98iwTQRjNZZuS6hnKeNbib0l6bZCL SyfAL5xRCAVoDAg8ncvdslET03mVjfZnq2FRzqWHO+ax1AXHQrL3O9iX48G42FI9 iFfM6JmUSziAHGiN/2MpZIbzneUo+tYJ/0+J//Go+/YuUx3AvTqsoXdposf4x6DK zNIU58OQQomAsZ+bUtOkPiG4B7D9ma2IpoyDPk3n3GXHK2xBZ8gcRjazA3TVxtVY rsGd0bkoYmzAiQzOzFIn+E5iPTfKSqC+dCkljsXDZrgeM9+NgYKhwPfieZPi6oUF Y6T//tSWap3A6/eZClR4kpdZO8sdl/J5s7zcYcOVwuB3CNZH0yn/2L7dyc6o6avY i6nQGRynjDwCFAZvF3ZYp/0j738F1cVTj6oaJ/bHr1sOtUcMxPCcPI6DRff1GzD1 gDE= 
  • Использование регулярных выражений
  • Форматирование и представление результатов

Варианты прохода по пагинации​

Использование Use pages​

Use pages. Данная функция позволяет проходить по пагинации с указанием наперед известного числа страниц. Для примера возьмем одну из категорий на сайте каталога товаров https://www.proball.ru/catalog/myachi/ . Вверху и внизу мы видим панель пагинации. При клике по пиктограмах с номерами страниц можно увидеть в строке браузера, как осуществляется передача параметра с номером страницы в конце запроса:

https://www.proball.ru/catalog/myachi/?PAGEN_1=1 

Use pages — это своего рода счетчик, который фактически в переменную $pagenum подставляет по порядку номера, увеличивая их на то значение, которое мы укажем

Использование Use pages

Как видно на скриншоте, в формате запроса парсера в нужном месте используется переменная $pagenum . Функция Use pages переберет и подставит в запрос все значения, фактически мы будем получать ссылки для запроса

https://www.proball.ru/catalog/myachi/?PAGEN_1=$pagenum 

где вместо переменной $pagenum будет подставлен номер страницы, начиная от 1 и до 4 с шагом 1. Таким образом, получается проход по страницах нужного диапазона. В этом заключается ограничение данного метода — нужно заранее знать количество страниц, которые есть в пагинации. Очевидно, что при одновременном парсинге нескольких категорий, количество страниц везде будет разное, и как выход, мы можем просто указать большее количество предполагаемых страниц. Но это не совсем правильно, поэтому есть более оптимальное решение, о котором речь пойдет дальше

eJx1VNtu2kAQ/ZVqhJSgUAhV+2I1jSgqvSgCmtAnjKKtPTZu1rubvXAR8r931jY2 pOmTvWfPXM7M7BzAMvNk5hoNWgPB8gCq/IcAnME5SxF6oJg2qP31EqZog+DbYjEn PMaEOW6hdwC7V0g2coNaZ7E3ymI6p1LGY1meN4w7oizfXV+vitYicsbK/B5N6Qh0 9RMsKWiKxgdhlsHK36S4I4OP7E3EmTE3IaQU6m1mMX98XCOLUYcQhuZqrTGh28v+ 1W03hE9Q2y6qgGkTpQaY1mxPYPmdstxjPBNPpiF65SUEp5lLZTMpzFFqXS7TSoWh 9xrHmecxDsGhEvVgUdW3/hxJJ3y930NR/L+Szw71PpE6Z/YkQqeEb+ejr1+mj8Ob jvcnXA7FatUkP6mMiKyG/VJYv/JzebG2VplgMNhut32l5W/GeV+7jieFobjothV4 YBtcSHKSZBxbeEKnumQdahT626P3bj8ym7MKVJn4arbZ/RLZcylFSOJ6ORmaiZY5 QRZ3tgb3RxXLWrMfCVfa/qxsIEgYN9gDQ6lOGCUSv7yhUdHMSj2rO0cNkWLE+R1u kLe00v9nl3GaKDNKyOh7bfg6ZfaPj6KRdxqKOrrVlENLiuWdTI/anxBVU42pR3Kp sXFQR6790otVKPxgtM0YqRY6S/Cs4OdgJEWSpbN62I5MJxa0FmZiLHPF0WcsHOc9 P+P3beNHpi6wP7QJvjQelyEorWZdgJWSmx8PVapKZzRYH5rmE/r6XA4iWgVcpoN8 z6J1NiBbQjCVNA1+c5XjQi9Hl/J6gDvFRIxUEasdFqti1ayyZuEdThZacKAHCH/M vOJ4VZ5BGJXHUBcgGBZ/AXULzRU= 

Использование Сheck next page​

Сheck next page — это еще одна функция, которая позволяет организовать проход по пагинации. Особенность ее использования заключается в том, что для перехода на следующую страницу, нужно использовать регулярное выражение, которое будет возвращать ссылку на следующую страницу. Это более удобный и наиболее часто применяемый способ. Но применить его для https://www.proball.ru/catalog/myachi/ не получится, т.к. в коде нету ссылок на следующие страницы. Ссылки там генерируются скриптом. Поэтому возьмем в качестве примера сайт http://www.imdb.com/search/name?gender=female . Здесь есть пагинация как в начале так и в конце списка. Посмотрев и проанализировав исходный код, можно увидеть наличие ссылки, которая позволяет переходить на следующую страницу:

img

Использование Сheck next page

  • в поле Next page RegEx запишем регулярное выражение
  • в поле Лимит укажем количество страниц, которое нужно пройти

В примере указано 4 . Указав лимит, мы определяем, сколько страниц парсер должен пройти. В нашем случае будет пройдено 5 страниц, так как отсчет начинается с 0 . Если указать лимит 0 , то парсер будет работать до того времени, пока не пройдет все страницы в независимости от их количества. Это очень удобно использовать, когда нужно спарсить все результаты со всех страниц

eJx1VGFT2kAQ/SuZG2aUggGq4DSijnXG2qpAlY4fCM6cZANXL7n07iJYhv/e3RAS sO0XuH3ZvX1vd2+XzHLzYgYaDFjDvNGSJdmZeWwyg8lLDxZ2wKfA6izh2oAmpxHr gfW86+FwgHgAIU+lZfUls28JYKR6Ba1FQEEiQHuqVHCpMvuVyxRdRh+bzfHq/xEp ZjrAtLEtY9id+i2k5I2223T2H0UcqLlxekOn47ZOHLQ7RyfOonNUdS6SRMIjPN8I 22gfHruHHWf/5np4d1t3pHgB5wsKU1XncqZVBI32J7fpHjaPW26r1XYeeMi1yMPY FsVJaqyK7sFkWpleH7wR1mUKhurALWdj+jKFBQZ0TcJjZyK5Mac+k8JY1CQsRAdI HRZuzWdnvm8+7Lu18yodur7foBhCa10+ejob19Yeo6fueMuJn7E8zXDNbVoQygGu NX9DMPvv8YgwSm0KR+oji9PoGZGYHHbakVihYrPpxvtJ2DSky52ZhhDVrTUwIv5O MFXnIMZYh34y02fELAgEJeGSecvdDLciEjSAR2y1Go8LwldKR5zwStJyMzFumEH7 exUS4lRIh+/He9VS5QN/haHCoFBIKOErtPKyVLBvQF83t1Vdu7A7DNeZqWIlmx+x +JUVIVboi0ctwFzhQCFkIbuAwLcN6xGrZDZNSJrFfl/HMC/k0kCdGaR6xZFI8P4L itXcKt3P24IFU/GFlLfwCrJ0y+7/nAoZ4DO9CDHoax74b5f+X3esCnnbqfBtzjVy KJ0CdaumG+0vAElRjR4hkdJQXJBnzu/FTZNATENVNgOfawHtENwp+C44UXEopv18 bWw803iI66wfX6oINwAxjlMp67RO7svGX5i8wGSUBN8HX2YpkFax4JhVSppvD2uq iRY4WO2i+YjOrE28RmM+n7siCp7diYoaBriezBo0m+e40FDCaQgRz6ZxgqM3VTgU tHizqaHhMZQKFrgJAsCyWJ3CarwaFxu42NbLrT3sLVfYmJ9msPYhaeSBGNbIYCuY 11r9ASIaBUM= 

Как было сказано выше, есть возможность динамически ограничивать количество страниц в Use pages. Для этого нужно совместно использовать Use pages и Сheck next page. Дополним пример, который был рассмотрен при описании Use pages и добавим в него функцию Сheck next page:

Использование Сheck next page (2)

Эти две функции в паре работают следующим образом: Use pages обеспечивает проход по страницам, а Check next page проверяет, существует ли следующая. Как только Check next page не найдет следующей страницы, парсинг этой категории будет остановлен, не дожидаясь прохода по всему количеству, которое указано в Use pages. Совмещая эти функции, мы добавляем эффективности в работе парсера, экономя время и ресурсы

eJx1VNtuGjEQ/ZXKQkqiEC6V+rJqGtGo9KIIaEKfWBS5u7OLi9d2bC8EIf69M3uF XJ52fTyXM2fGs2eeu7WbWXDgHQsWe2aKfxaw3MGMp8C6zHDrwNL1gk3AB8GP+XyG eAwJz6Vn3T3zOwPoozdgrYjJScR4TrWOb3Vx3nCZo8ni42CwPLQeUe68zu7BFYGY LX+CBSZNwVES7jlb0k0Kz+jwmX+IJHfuOmQpproSHrLHxxXwGGzIwtBdriwkeHve u7y5CNkXVvnOy4Rpk6UCuLV8h2DxnfCMMCnU2jWGVHkBsWPm2nihlatLreRybals SFHjWJAdlyzYl0U9eDDVLZ0jnSvSezgYsMPhfS2fcrC7RNuM+6McnQK+mY2+f5s8 Dq87FFHlGXufaLSCaD2BZ191t45EQl8pxK8oxjVpGV+G7FUNJ/53IhNEnqgvl41g 45Im0jPDXiFmr2R+frby3rig399utz1j9V8uZc/mHTIKQ3V20ar+wDcw1xgkERJa eIynqk0d5Ax0W0e/6EVuc8K4ZEIdbNn9UeKpKFlptCUBBbix1RlCHgurwF1dxaJS mcYwL3x/lz4sSLh00GUOqY45Eolf3uB4Wu61nVZNQAG1Gkl5BxuQrVkR/2suJE6x GyXo9LNyfNtk+irGoSnvOBXO0NYih9Yo1nc6rWtfA5hGjQkhmbbQBKgyV3FxSxhQ NEJtM0amhU4Ingh+CkZaJSKdVuNdW+Zqjqtoqm51ZiQQY5VL2aV3dd82fuQqgenQ EnzpfFukoKGuVxTzWkv366GkaqzAwfrUNB/Rt+eyH+GrkDrtZzserUQffRGBVOM0 0LYsxgWfmC3K6zJ4NlzFgIoMD8vDstmdzYbdH23QYI/vnf1zs9KGSiILxFAbhy2g KP8Byg3yDQ== 

Использование макросов подстановок​

Макросы подстановок позволяют реализовать последовательную подстановку значений из указанного диапазона

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

Данный пресет будет работать следующим образом. Указав в формате запроса шаблон:

$query?PAGEN_1= 

мы добавляем подстановку значений от 1 до 10 (диапазон можно указать любой) в сам запрос. Таким образом мы получаем запросы, оторые обеспечивают проход по нужному количеству страниц, вида:

https://www.proball.ru/catalog/myachi/?PAGEN_1=1 https://www.proball.ru/catalog/myachi/?PAGEN_1=2 . https://www.proball.ru/catalog/myachi/?PAGEN_1=10 

Использование макросов подстановок для прохода по пагинации похоже на функцию Use pages и имеет такие же ограничения, то есть нужно указывать конкретный диапазон значений. Преимуществом данного метода можно считать то, что через макросы подстановок можно подставлять разные значения, как числовые, так и текстовые, например, слова или выражения. Таким образом мы можем более гибко вставлять нужные части в запросы или формировать сами запросы из частей, которые будут размещаться в разных файлах, если этого требует задание

eJxtVFtP2zAU/iuTVQkQXUsn7SUaQx2iu4i1HXRPTYW85CT1cGzPx+lFUf47x26a AOMp8Xcu3+dzccUcx0ecW0BwyKJlxUz4ZxH7yROr8WbH+sxwi2C9fcmm4KLo22Ix JzyFjJfSsX7F3N4ABekNWCtSIKNI6ZxrnV7rcN5wWZLL8sPFxaruIpISnS7uAEMi Zg8/0ZJIc0BPwh1nK2/JYUcBn/i7RHLEy5jlRPVeOCgeHtbAU7Axi2M8X1vIyHo6 OL86i9ln1sQuDoR5y9IA3Fq+JzB8p7zwmBTqEVtHf/MAsVW9WrXoRNuC+1L1zGgQ IgZZgE5P1s4ZjIbD7XY7MFb/4VIObNnzTnGsTs661Pd8AwtNSTIhoYMndGq09KgC 4K3H7GeDBDdecJoKJ7Ti8qDEy+zU/Vbiny84U5p86dcKwInVBUEOdq4B98dbLFkv nK/m468304fRZaXKIhpFo4val78M6X4d0rAo4xKhz5DUTzhpS19bqC2WO21nxksk vGJajaW8hQ3Izi1QfimFpO7hOKOg703g2y6z/3LU7Y2fU9Ecbi1p6JxSfavzYzke AUxboKlHCm2hTdAwN3lpPQwoP85df8amg14IfNGDl2CiVSbyWbMiR89SLWgHZ+pa F0aCV6xKKangCHfdLIyxKbA/dAJfB18HCpLVriZzWkv8cX+QaqygWfvYzgOhb4/q MKG1kzofFnuerMWQYgmBXNt9eCbCBPlBQs8BO8NVClQPZ0uoaUvaR6N9W6pnT0dU 1dSRvzg/+Pg7eQ/CqDhIPWDRqH4C36ybyg== 

Использование Page as query​

Для уменьшения потребления памяти логику можно определить с помощью опции Page as query. При ее активации функции Check next page и Use pages будут каждую следующую страницу подставлять в запросы как отдельный самостоятельный запрос, тем самым не накапливая их контент в памяти. Page as query позволяет также определить, повышать ли уровень запроса Increase (аналогично работе инструмента tools.query.add), или нет Keep

Использование Page as query

Скачать пример

eJx1VNty2jAQ/RWPJg/QEts0gUydpBnCDE0bAiQhkwfgQbHXoCJbriQDKcO/dyXM tc0LeFd7OXv2siSaqqnqSVCgFQkGS5LZbxKQHh1DQ3Vg/piDfCcVklGpQBqrAemA DoK7fr+H+ghimnNNKkui3zNAVzEDKVkE+MgilMdCRE1h5RnlOZoMvvj+aPWxR46Z ThFAqnc+5EH8YZxTr+b6TumVpZGYK6fTd+pu9dJBuX5+6Szq52WnkWUcXuHtnmmv dnbhntWd0v1d/6FdcTibgvMdwqkoO82JFAl4ta+u7575F1W3Wq05zzSmkhVuZB9i pplI1QZhOMEgHVhow9MeyCvqTCTE10NScj/flIdkOFSfQ06VQhVnSmNhGbqcpujr mB8rDgnGoFHETBLKSbA8zNBmCTNd8cnqY0zZccsKUFrmcBx9CpBZszbMADX+ajUa VQh2H3upWkIm1OQ7yaquZpqbEou3ZzqDvsC3mO2rWyh1aGJgnURUg3l1YxunVHb1 Qh8UuE5ghmmX9CVlvy2HqUBb/JQMVAt7hCoNNoBRvm/ADciJlQmGyK3v49qHBDHl CktWCLVFEUh0/MKwD1QL2S0YREZE2uDcsrEzs/Fvc8YjnPxGjE4/Csf/m3T/ibHa lrefCsd9LhHDNoqVbrsPO69ItMUYK4/esG5u2o+yaoo8Xc9BxbZwy1nHcJYICds0 ReQiO+54BqmZkl3LcE+2qoMyDtqyp1wSJXIZmgX2ESHV1HBfDKOEMSxscPOPm2Dn 5lvJ/XRTvhoOvbW4MeivnczsamF6uZ6y0QoDhiKN2bhb3IQNmjzt47Hqpk2R4Hob 7tKc84q5FU+7EWyootVG2JFw7Ny0KQy9m+uFMARXP5/XdGSSIaqaAZtgt/azFiFD yvnLU3v/hezGFoWJ1lngefP53GVJ9OaGIvEUUBlOvBT35AavG9J6HUNC7R6FuDRj geOM5RoWinu7Pc7LvasbLPEMkF+qt7YxtRoL1CFpCvtPgurqL0u6AK8= 

Возможные настройки​

Название параметра Значение по умолчанию Описание
Good status All Выбор какой ответ с сервера будет считается успешным. Если при парсинге будет другой ответ от сервера, то запрос будет повторен с другим прокси
Good code RegEx Возможность указать регулярное выражения для проверки кода ответа
Ban Proxy Code RegEx Возможность банить прокси на время (Proxy ban time) на основе кода ответа сервера
Method GET Метод запроса
POST body Контент для передачи на сервер при использовании метода POST. Поддерживает переменные $query – URL запроса, $query.orig – исходный запрос и $pagenum — номер страницы при использовании опции Use Pages.
Cookies Возможность указать cookies для запроса.
User agent _Автоматически подставляется user-agent актуальной версии Chrome_ Заголовок User-Agent при запросе страниц
Additional headers Возможность указать произвольные заголовки запроса с поддержкой возможностей шаблонизатора и использованием переменных из конструктора запросов
Read only headers Читать только заголовки. В некоторых случаях позволяет экономить трафик, если нет необходимости обрабатывать контент
Detect charset on content Распознавать кодировку на основе содержимого страницы
Emulate browser headers Эмулировать заголовки браузера
Max redirects count 7 Максимальное кол-во редиректов, по которым будет переходить парсер
Follow common redirects Позволяет делать редиректы http https и www.domain domain в пределах одного домена в обход лимита Max redirects count
Max cookies count 16 Максимальное число cookies для сохранения
Engine HTTP (Fast, JavaScript Disabled) Позволяет выбрать движок HTTP (быстрее, без JavaScript) или Chrome (медленнее, JavaScript включен)
Chrome Headless Если опция включена, браузер не будет отображаться
Chrome DevTools Позволяет использовать инструменты для отладки Chromium
Chrome Log Proxy connections Если опция включена, в лог будет выводиться информация по подключениям chrome
Chrome Wait Until networkidle2 Определяет, когда страница считается загруженной. Подробнее о значениях.
Use HTTP/2 transport Определяет, использовать ли HTTP/2 вместо HTTP/1.1. Например, Google и Majestic сразу банят, если использовать HTTP/1.1.
Don’t verify TLS certs Отключение валидации TLS сертификатов
Randomize TLS Fingerprint Данная опция позволяет обходить бан сайтов по TLS отпечатку
Bypass CloudFlare with Chrome Автоматический обход проверки CloudFlare
Bypass CloudFlare with Chrome Max Pages 20 Макс. кол-во страниц при обходе CF через Chrome
Bypass CloudFlare with Chrome Headless Если опция включена, браузер не будет отображаться во время обхода CF через Chrome

Последнее обновление 28 дек. 2023 г.

  • Обзор парсера
  • Кейсы по применению парсера
  • Собираемые данные
  • Возможности
  • Варианты использования
  • Запросы
  • Варианты вывода результатов
    • Вывод контента
    • Код ответа сервера
    • Получение данных о запросе
    • Получение редиректов
    • JSON с редиректами
    • Вывод статуса ответа сервера
    • Время ответа сервера
    • Получение размера страницы
    • Вывод заголовков H1-H6
    • Сбор мета-тегов
    • Использование Use pages
    • Использование Сheck next page
    • Использование макросов подстановок
    • Использование Page as query

    HTTP запросы (+работа с куками, прокси, сессии)

    Чтобы собрать данные с веб-страницы нужно выполнить HTTP запрос. В JavaScript API v2 А-Парсера реализован легкий в использовании метод выполнения HTTP запросов, который в ответ возвращает JSON объект в зависимости от указанных аргументов метода. Далее вы узнаете: как производится HTTP запрос, какие аргументы и опции имеет метод, результаты указанных опций, как указывать условие успешности HTTP запроса, и другое.

    Также описаны методы позволяющие легко манипулировать куками, прокси и сессией в создаваемом парсере. После успешного выполнения HTTP запроса, или перед выполнением, вы можете установить/изменить данные прокси/кук/сессии для выполнения HTTP запросов или сохранить для выполнения другим потоком с помощью Менеджера сессий.

    Данные методы наследуются от BaseParser и являются основой для создания собственных парсеров

    await this.request(method, url[, queryParams][, opts]) ​

    await this.request(method, url, queryParams, opts) 

    Получение HTTP ответа по запросу, в качестве аргументов указывается:

    • method — метода запроса (GET, POST. )
    • url — ссылка для запроса
    • queryParams — хэш с get параметрами или хэш с телом post-запроса
    • opts — хэш с опциями запроса

    opts.check_content ​

    check_content: [ условие1, условие2, . ] — массив условий для проверки получаемого контента, если проверка не проходит, то запрос будет повторен с другим прокси.

    Возможности:​
    • использование в качестве условий строк (поиск по вхождению строки)
    • использование в качестве условий регулярных выражений
    • использование своих функций проверок, в которые передаются данные и хедеры ответа
    • можно задать сразу несколько разных типов условий
    • для логического отрицания поместите условие в массив, т.е. check_content: [‘xxxx’, [/yyyy/]] означает что запрос будет считаться успешным, если в полученных данных содержится подстрока xxxx и при этом регулярное выражение /yyyy/ не находит совпадений на странице

    Для успешного запроса должны пройти все указанные в массиве проверки

    Пример (в комментариях указано что нужно для того, чтобы запрос считался успешным):

    let response = await this.request('GET', set.query, >,   check_content: [ /|/, // на полученной странице должно сработать это регулярное выражение ['XXXX'], // на полученной странице не должно быть этой подстроки '', // на полученной странице должна быть такая подстрока (data, hdr) =>   return hdr.Status == 200 && data.length > 100; > // эта функция должна вернуть true ] >); 

    opts.decode ​

    decode: ‘auto-html’ — автоматическое определение кодировки и преобразование в utf8

    • auto-html — на основе заголовков, тегов meta и по содержимому страници (оптимальный рекомендуемый вариант)
    • utf8 — указывает что документ в кодировке utf8
    • — любая другая кодировка

    opts.headers ​

    headers: < . >— хэш с заголовками, название заголовка задается в нижнем регистре, можно указать в т.ч. cookie.

    headers:   accept: 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8', 'accept-encoding': 'gzip, deflate, br', cookie: 'a=321; b=test', 'user-agent' 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36' > 

    opts.headers_order ​

    headers_order: [‘cookie’, ‘user-agent’, . ] — позволяет переопределить порядок сортировки заголовков

    opts.onlyheaders ​

    onlyheaders: 0 — определяет чтение data , если включено (1), получает только заголовки

    opts.recurse ​

    recurse: N — максимальное число переходов по редиректам, по умолчанию 7 , используйте 0 для отключения перехода по редиректам

    opts.proxyretries ​

    proxyretries: N — число попыток выполнения запроса, по умолчанию берется из настроек парсера

    opts.parsecodes ​

    parsecodes: < . >— перечень кодов HTTP ответов, которые парсер будет считать удачными, по умолчанию берется из настроек парсера. Если указать ‘*’: 1 то все ответы будут считаться удачными.

    parsecodes:   200: 1, 403: 1, 500: 1 > 

    opts.timeout ​

    timeout: N — таймаут ответа в секундах, по умолчанию берется из настроек парсера

    opts.do_gzip ​

    do_gzip: 1 — определяет использовать ли компрессию (gzip/deflate/br), по умолчанию включено (1), для выключения нужно задать значение 0

    opts.max_size ​

    max_size: N — максимальный размер ответа в байтах, по умолчанию берется из настроек парсера

    opts.cookie_jar ​

    cookie_jar: < . >— хэш с куками. Пример хэша:

    "cookie_jar":   "version": 1, ".google.com":   "/":   "login":   "value": "true" >, "lang":   "value": "ru-RU" > > >, ".test.google.com":   "/":   "id":   "value": 155643 > > > 

    opts.attempt ​

    attempt: N — указывает на номер текущей попытки, при использовании этого параметра встроенный обработчик попыток для данного запроса игнорируется

    opts.browser ​

    browser: 1 — автоматическая эмуляция заголовков браузера (1 — включено, 0 — выключено)

    opts.use_proxy ​

    use_proxy: 1 — переопределяет использование прокси для отдельного запроса внутри JS парсера поверх глобального параметра Use proxy (1 — включено, 0 — выключено)

    opts.noextraquery ​

    noextraquery: 0 — отключает добавление Extra query string к урлу запроса (1 — включено, 0 — отключено)

    opts.save_to_file ​

    save_to_file: file — позволяет скачать файл напрямую на диск, минуя запись в память. Вместо file указывается имя и путь под каким сохранить файл. При использовании этой опции игнорируется все, что связано с data (проверка контента в opts.check_content не будет выполнена, response.data будет пустой и т.д.)

    opts.bypass_cloudflare ​

    bypass_cloudflare: 0 — автоматический обход JavaScript защиты CloudFlare используя браузер Chrome (1 — включено, 0 — выключено)

    Контроль Chrome Headless в этом случае осуществляется настройками парсера bypassCloudFlareChromeMaxPages и bypassCloudFlareChromeHeadless , которые нужно указать в static defaultConf и static editableConf :

    static defaultConf: typeof BaseParser.defaultConf =   version: '0.0.1',  results:   flat: [ ['title', 'Title'], ] >,  max_size: 2 * 1024 * 1024,  parsecodes:   200: 1, >,  results_format: "$title\n",  bypass_cloudflare: 1,  bypassCloudFlareChromeMaxPages: 20,  bypassCloudFlareChromeHeadless: 0 >;  static editableConf: typeof BaseParser.editableConf = [ ['bypass_cloudflare', ['textfield', 'bypass_cloudflare']], ['bypassCloudFlareChromeMaxPages', ['textfield', 'bypassCloudFlareChromeMaxPages']], ['bypassCloudFlareChromeHeadless', ['textfield', 'bypassCloudFlareChromeHeadless']], ];  async parse(set, results)   const success, data, headers> = await this.request('GET', set.query, >,   bypass_cloudflare: this.conf.bypass_cloudflare >); return results; > 

    opts.follow_meta_refresh ​

    follow_meta_refresh: 0 — позволяет переходить по редиректам, объявленным через HTML метатег:

    meta http-equiv="refresh" content="time; url=. "/> 

    opts.redirect_filter ​

    redirect_filter: (hdr) => 1 | 0 — позволяет задать функцию фильтрации перехода по редиректам, если функция возвращает 1 , то парсер перейдет по редиректу (учитывая параметр opts.recurse ), при возврате 0 переход по редиректам прекратиться:

    redirect_filter: (hdr) =>   if (hdr.location.match(/login/)) return 1; return 0; > 

    opts.follow_common_rediects ​

    opts.follow_common_rediects: 0 — определяет переходить ли по стандартным редиректам (например http -> https и/или www.domain.com -> domain.com ), если указать 1 то парсер будет переходить по стандартным редиректам без учета параметра opts.recurse

    opts.http2 ​

    opts.http2: 0 — определяет переходить использовать ли протокол HTTP/2 при выполнении запросов, по умолчанию используется HTTP/1.1

    opts.randomize_tls_fingerprint ​

    opts.randomize_tls_fingerprint: 0 — данная опция позволяет обходить бан сайтов по TLS отпечатку (1 — включено, 0 — выключено)

    opts.tlsOpts ​

    tlsOpts: < . >– позволяет передавать настройки для https соединений ​

    await this.cookies.* ​

    Работа с cookies для текущего запроса

    .getAll() ​

    Получение массива cookies

    await this.cookies.getAll(); 

    Пример результата получения массива cookies

    .setAll(cookie_jar) ​

    Установка cookies, в качестве аргумента должен быть передан хэш с куками

    async parse(set, results)   this.logger.put("Start scraping query: " + set.query);  await this.cookies.setAll(  "version": 1, ".google.com":   "/":   "login":   "value": "true" >, "lang":   "value": "ru-RU" > > >, ".test.google.com":   "/":   "id":   "value": 155643 > > > >);  let cookies = await this.cookies.getAll();  this.logger.put("Cookies: " + JSON.stringify(cookies));  results.SKIP = 1; return results; > 

    Пример результата установки массива cookies

    .set(host, path, name, value) ​

    await this.cookies.set(host, path, name, value) — установка одиночного cookie

    async parse(set, results)   this.logger.put("Start scraping query: " + set.query);  await this.cookies.set('.a-parser.com', '/', 'Test-cookie-1', 1); await this.cookies.set('.a-parser.com', '/', 'Test-cookie-2', 'test-value');  let cookies = await this.cookies.getAll();  this.logger.put("Cookies: " + JSON.stringify(cookies));  results.SKIP = 1; return results; > 

    Пример результата установки одиночного cookie

    await this.proxy.* ​

    Работа с прокси

    .next() ​

    Сменить прокси на следующий, старый прокси больше не будет использован для текущего запроса

    .ban() ​

    Сменить и забанить прокси (необходимо использовать когда сервис блокирует работу по IP), прокси будет забанен на время, указанное в настройках парсера ( proxybannedcleanup )

    .get() ​

    Получить текущий прокси (последний прокси с которым был сделан запрос)

    .set(proxy, noChange?) ​

    await this.proxy.set(‘http://127.0.0.1:8080’, true) — установить прокси для следующего запроса. Параметр noChange необязательный, если задан true то прокси не будет меняться между попытками. По умолчанию noChange = false

    await this.sessionManager.* ​

    Методы для работы с сессиями. Каждая сессия обязательно хранит использованный прокси и куки. Также можно дополнительно сохранять произвольные данные. Для использования сессий в JS парсере сначала обязательно нужно инициализировать Менеджер сессий. Делается это с помощью метода await this.sessionManagerinit() в init()

    .init(opts?) ​

    Инициализация Менеджера сессий. В качестве аргумента можно передавать объект ( opts ) с дополнительными параметрами (все параметры необязательны):

    • name — позволяет переопределить имя парсера, которому принадлежат сессии, по-умолчанию равно имени парсера, в котором происходит инициализация
    • waitForSession — указывает парсеру ждать сессию пока она не появится (это актуально только когда работают несколько заданий, например одно генерирует сессии, второе их использует), т.е. .get() и .reset() будут всегда ждать сессию
    • domain — указывает искать сессии среди всех сохраненных для этого парсера (если значение не задано), или же только для конкретного домена (необходимо указывать домен с точкой спереди, например .site.com )
    • sessionsKey — позволяет задать вручную названия хранилища сессий, если он не задан, то имя формируется автоматически на основе name (или названия парсера, если name не задан), домена и проксичекера
    • expire — задает время жизни сессии в минутах, по-умолчанию неограничено
    async init()   await this.sessionManager.init(  name: 'JS::test', expire: 15 * 60 >); > 

    .get(opts?) ​

    Получение новой сессии, необходимо вызывать перед осуществлением запроса (перед первой попыткой). Возвращает объект с произвольными данными, сохраненными в сессии. В качестве аргумента можно передавать объект ( opts ) с дополнительными параметрами (все параметры необязательны):

    • waitTimeout — возможность указать сколько минут ждать появления сессии, работает независимо от параметра waitForSession в .init() (игнорирует его), по истечению будет использована пустая сессия
    • tag — получение сесии с заданным тегом, можно использовать например имя домена для привязки сессий к доменам с которых они получены
    await this.sessionManager.get(  waitTimeout: 10, tag: 'test session' >) 

    .reset(opts?) ​

    Очистка кук и получение новой сессии. Необходимо использовать, если с текущей сессией запрос не был удачным. Возвращает объект с произвольными данными, сохраненными в сессии. В качестве аргумента можно передавать объект ( opts ) с дополнительными параметрами (все параметры необязательны):

    • waitTimeout — возможность указать сколько минут ждать появления сессии, работает независимо от параметра waitForSession в .init() (игнорирует его), по истечению будет использована пустая сессия
    • tag — получение сесии с заданным тегом, можно использовать например имя домена для привязки сессий к доменам с которых они получены
    await this.sessionManager.reset(  waitTimeout: 5, tag: 'test session' >) 

    .save(sessionOpts?, saveOpts?) ​

    Cохранение успешной сессии с возможностью сохранять произвольные данные в сессии. Поддерживает 2 необязательных аргумента:

    • sessionOpts — произвольные данные для хранения в сессии, может быть число, строка, массив или объект
    • saveOpts — объект с параметрами сохранения сессии:
      • multiply — необязательный параметр, позволяет размножить сессию, в качестве значения нужно указать число
      • tag — необязательный параметр, задает тег для сохраняемой сессии, можно использовать например имя домена для привязки сессий к доменам с которых они получены
      await this.sessionManager.save('some data here',   multiply: 3, tag: 'test session' >) 

      .count() ​

      Возвращает количество сессий для текущего Менеджера сессий

      let sesCount = await this.sessionManager.count(); 

      .removeById(sessionId) ​

      Удаляет все сессии с заданным id. Возвращает количество удаленных сессий. Id текущей сессии содержится в переменной this.sessionId Пример использования:

      const removedCount = await this.sessionManager.removeById(this.sessionId); 

      Комплексный пример использования Менеджера сессий​

      async init()   await this.sessionManager.init(  expire: 15 * 60 >); >  async parse(set, results)   let ses = await this.sessionManager.get();  for(let attempt = 1; attempt  this.conf.proxyretries; attempt++)   if(ses) this.logger.put('Data from session:', ses); const  success, data > = await this.request('GET', set.query, >,  attempt >); if(success)   // process data here  results.success = 1; break; > else if(attempt  this.conf.proxyretries)   const removedCount = await this.sessionManager.removeById(this.sessionId); this.logger.put(`Removed $removedCount> bad sessions with id #$this.sessionId>`);  ses = await this.sessionManager.reset(); > >  if(results.success)   await this.sessionManager.save('Some data',  multiply: 2 >); this.logger.put(`Total we have $await this.sessionManager.count()> sessions`); >  return results; > 

      Пример сохранения произвольных данных и дальнейшего их получения

      Методы запросов await this.request ​

      Метод GET ​

      Передать параметры запроса можно напрямую в строке запроса https://a-parser.com/users/?type=staff :

      const  success, data, headers > = await this.request('GET', 'https://a-parser.com/users/?type=staff'); 

      Или как объект в queryParams , где key: value равно param=value :

      const  success, data, headers > = await this.request('GET', 'https://a-parser.com/users/',   type: 'staff' >); 

      Метод POST ​

      Если используется метод POST, тело запроса можно передать двумя способами:

        Перечислить названия переменных и их значения в queryParams , например:

        "key": set.query, "id": 1234, "type": "text" > 
      body: 'key=' + set.query + '&id=1234&type=text' 

      Если тело запроса передается как объект он автоматически преобразуется в форму form-urlencoded , так же если указан body и не указан content-type заголовок, то автоматически присвоится content-type: application/x-www-form-urlencoded :

      const  success, data, headers > = await this.request('POST', 'https://jsonplaceholder.typicode.com/posts',   title: 'foo,', body: 'bar', userId: 1 >); 

      Если тело POST запроса строка или буффер, то оно так и передается:

      // запрос со строкой const string = 'title=foo&body=bar&userId=1'; const  success, data, headers > = await this.request('POST', 'https://jsonplaceholder.typicode.com/posts', >,   body: string >);  // запрос с буффером const string = 'title=foo&body=bar&userId=1'; const buf = Buffer.from(string, 'utf8'); const  success, data, headers > = await this.request('POST', 'https://jsonplaceholder.typicode.com/posts', >,   body: buf >); 

      Загрузка файлов ​

      Отправка файла POST запросом с использованием модуля form-data :

      const file = fs.readFileSync('pathToFile'); const FormData = require('form-data'); const format = new FormData(); format.append('file', file, 'fileName.ext');  const  success, data, headers > = await this.request('POST', 'https://file.io', >,   headers: format.getHeaders(), body: format.getBuffer() >); 

      Пример отправки файла в POST запросе с типом контента multipart/form-data :

      const EOL = '\r\n'; const file = fs.readFileSync('pathToFile'); const boundary = '----WebKitFormBoundary' + String(Math.random()).slice(2); const requestHeaders =   'content-type': 'multipart/form-data; boundary=' + boundary >;  const body = '--' + boundary + EOL + 'Content-Disposition: form-data; name="file"; filename="fileName.ext"' + EOL + 'Content-Type: text/html' + EOL + EOL + file + EOL + '--' + boundary + '--';  const  success, data, headers > = await this.request('POST', 'https://file.io', >,   headers: requestHeaders,  body >); 

      Парсинг на Python с Beautiful Soup

      Парсинг — это распространенный способ получения данных из интернета для разного типа приложений. Практически бесконечное количество информации в сети объясняет факт существования разнообразных инструментов для ее сбора. В процессе скрапинга компьютер отправляет запрос, в ответ на который получает HTML-документ. После этого начинается этап парсинга. Здесь уже можно сосредоточиться только на тех данных, которые нужны. В этом материале используем такие библиотеки, как Beautiful Soup, Ixml и Requests. Разберем их.

      Установка библиотек для парсинга

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

      pip install lxml pip install requests pip install beautifulsoup4

      Поиск сайта для скрапинга

      Для знакомства с процессом скрапинга можно воспользоваться сайтом https://quotes.toscrape.com/, который, похоже, был создан для этих целей.

      сайт для скрапинга

      Из него можно было бы создать, например, хранилище имен авторов, тегов или самих цитат. Но как это сделать? Сперва нужно изучить исходный код страницы. Это те данные, которые возвращаются в ответ на запрос. В современных браузерах этот код можно посмотреть, кликнув правой кнопкой на странице и нажав «Просмотр кода страницы».

      Просмотр кода страницы

      На экране будет выведена сырая HTML-разметка страница. Например, такая:

      На этом примере можно увидеть, что разметка включает массу на первый взгляд перемешенных данных. Задача веб-скрапинга — получение доступа к тем частям страницы, которые нужны. Многие разработчики используют регулярные выражения для этого, но библиотека Beautiful Soup в Python — более дружелюбный способ извлечения необходимой информации.

      Создание скрипта скрапинга

      В PyCharm (или другой IDE) добавим новый файл для кода, который будет отвечать за парсинг.

       
      # scraper.py
      import requests
      from bs4 import BeautifulSoup

      url = 'https://quotes.toscrape.com/'
      response = requests.get(url)
      soup = BeautifulSoup(response.text, 'lxml')

      print(soup)

      Отрывок выше — это лишь начало кода. В первую очередь в верхней части файла выполняется импорт библиотек requests и Beautiful Soup. Затем в переменной url сохраняется адрес страницы, с которой будет поступать информация. Эта переменная затем передается функции requests.get() . Результат присваивается переменной response . Дальше используем конструктор BeautifulSoup() , чтобы поместить текст ответа в переменную soup . В качестве формата выберем lxml . Наконец, выведем переменную. Результат должен выглядеть приблизительно вот так.

      Вот что происходит: ПО заходит на сайт, считывает данные, получает исходный код — все по аналогии с ручным подходом. Единственное отличие в том, что в этот раз достаточно лишь одного клика.

      Парсинг на Python с Beautiful Soup

      Прохождение по структуре HTML

      HTML — это HyperText Markup Language («язык гипертекстовой разметки»), который работает за счет распространения элементов документа со специальными тегами. В HTML есть много разнообразных тегов, но стандартный шаблон включает три основных: html , head и body . Они организовывают весь документ. В случае со скрапингом интерес представляет только тег body .

      Написанный скрипт уже получает данные о разметке из указанного адреса. Дальше нужно сосредоточиться на конкретных интересующих данных.

      Если в браузере воспользоваться инструментом «Inspect» (CTRL+SHIFT+I), то можно достаточно просто увидеть, какая из частей разметки отвечает за тот или иной элемент страницы. Достаточно навести мышью на определенный тег span , как он подсветит соответствующую информацию на странице. Можно увидеть, что каждая цитата относится к тегу span с классом text .

      Парсинг на Python с Beautiful Soup

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

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

      Парсинг HTML-разметки

      В HTML-документе хранится много информации, но благодаря Beautiful Soup проще находить нужные данные. Порой для этого требуется всего одна строка кода. Пойдем дальше и попробуем найти все теги span с классом text . Это, в свою очередь, вернет все теги. Когда нужно найти несколько одинаковых тегов, стоит использовать функцию find_all() .

       
      # scraper.py
      import requests
      from bs4 import BeautifulSoup

      url = 'https://quotes.toscrape.com/'
      response = requests.get(url)
      soup = BeautifulSoup(response.text, 'lxml')
      quotes = soup.find_all('span', class_='text')

      print(quotes)

      Этот код сработает, а переменной quotes будет присвоен список элементов span с классом text из HTML-документа. Вывод этой переменной даст следующий результат.

      Парсинг HTML-разметки

      Свойство text библиотеки Beautiful Soup

      Возвращаемая разметка — это не совсем то, что нужно. Для получения только данных — цитат в этом случае — можно использовать свойство .text из библиотеки Beautiful Soup. Обратите внимание на код, где происходит перебор всех полученных данных с выводом только нужного содержимого.

       
      # scraper.py
      import requests
      from bs4 import BeautifulSoup

      url = 'https://quotes.toscrape.com/'
      response = requests.get(url)
      soup = BeautifulSoup(response.text, 'lxml')
      quotes = soup.find_all('span', class_='text')

      for quote in quotes:
      print(quote.text)

      Это и дает вывод, который требовался с самого начала.

      Парсинг на Python с Beautiful Soup

      Для поиска и вывода всех авторов можно использовать следующий код. Работаем по тому же принципу — сперва нужно вручную изучить страницу. Можно обратить внимание на то, что каждый автор заключен в тег с классом author . Дальше используем функцию find_all() и сохраняем результат в переменной authors . Также стоит поменять цикл, чтобы перебирать сразу и цитаты, и авторов.

       
      # scraper.py
      import requests
      from bs4 import BeautifulSoup

      url = 'https://quotes.toscrape.com/'
      response = requests.get(url)
      soup = BeautifulSoup(response.text, 'lxml')
      quotes = soup.find_all('span', class_='text')

      for quote in quotes:
      print(quote.text)

      Таким образом теперь есть и цитаты, и их авторы.

      “The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.” --Albert Einstein “It is our choices, Harry, that show what we truly are, far more than our abilities.” --J.K. Rowling “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.” --Albert Einstein . 

      Наконец, добавим код получения всех тегов для каждой цитаты. Здесь уже немного сложнее, потому что сперва нужно получить каждый внешний блок каждой коллекции тегов. Если этот первый шаг не выполнить, то теги можно будет получить, но ассоциировать их с конкретной цитатой — нет.

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

       
      # scraper.py
      import requests
      from bs4 import BeautifulSoup

      url = 'https://quotes.toscrape.com/'
      response = requests.get(url)
      soup = BeautifulSoup(response.text, 'lxml')
      quotes = soup.find_all('span', class_='text')
      authors = soup.find_all('small', class_='author')
      tags = soup.find_all('div', class_='tags')

      for i in range(0, len(quotes)):
      print(quotes[i].text)
      print('--' + authors[i].text)
      tagsforquote = tags[i].find_all('a', class_='tag')
      for tagforquote in tagsforquote:
      print(tagforquote.text)
      print('\n')

      Этот код даст такой результат. Круто, не так ли?

      “The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.” --Albert Einstein change deep-thoughts thinking world “It is our choices, Harry, that show what we truly are, far more than our abilities.” --J.K. Rowling abilities choices . 

      Практика парсинга с Beautiful Soup

      Еще один хороший ресурс для изучения скрапинга — scrapingclub.com. Там есть множество руководств по использованию инструмента Scrapy. Также имеется несколько страниц, на которых можно попрактиковаться. Начнем с этой https://scrapingclub.com/exercise/list_basic/?page=1.

      Нужно просто извлечь название элемента и его цену, отобразив данные в виде списка. Шаг первый — изучить исходный код для определения HTML. Судя по всему, здесь использовался Bootstrap.

      Практика парсинга с Beautiful Soup

      После этого должен получиться следующий код.

       
      # shop_scraper.py
      import requests
      from bs4 import BeautifulSoup

      url = 'https://scrapingclub.com/exercise/list_basic/?page=1'
      response = requests.get(url)
      soup = BeautifulSoup(response.text, 'lxml')
      items = soup.find_all('div', class_='col-lg-4 col-md-6 mb-4')

      for n, i in enumerate(items, start=1):
      itemName = i.find('h4', class_='card-title').text.strip()
      itemPrice = i.find('h5').text
      print(f': за ')
      1: $24.99 за Short Dress 2: $29.99 за Patterned Slacks 3: $49.99 за Short Chiffon Dress 4: $59.99 за Off-the-shoulder Dress . 

      Скрапинг с учетом пагинации

      Ссылка выше ведет на одну страницу коллекции, включающей на самом деле несколько страниц. На это указывает page=1 в адресе. Скрипт Beautiful Soup можно настроить и так, чтобы скрапинг происходил на нескольких страницах. Вот код, который будет извлекать данные со всех связанных страниц. Когда все URL захвачены, скрипт может выполнять запросы к каждой из них и парсить результаты.

       
      # shop_scraper.py
      # версия для понимания процессов
      import requests
      from bs4 import BeautifulSoup

      url = 'https://scrapingclub.com/exercise/list_basic/?page=1'
      response = requests.get(url)
      soup = BeautifulSoup(response.text, 'lxml')
      items = soup.find_all('div', class_='col-lg-4 col-md-6 mb-4')

      for n, i in enumerate(items, start=1):
      itemName = i.find('h4', class_='card-title').text.strip()
      itemPrice = i.find('h5').text
      print(f': за ')

      pages = soup.find('ul', class_='pagination')
      urls = []
      links = pages.find_all('a', class_='page-link')

      for link in links:
      pageNum = int(link.text) if link.text.isdigit() else None
      if pageNum != None:
      hrefval = link.get('href')
      urls.append(hrefval)

      for slug in urls:
      newUrl = url.replace('?page=1', slug)
      response = requests.get(newUrl)
      soup = BeautifulSoup(response.text, 'lxml')
      items = soup.find_all('div', class_='col-lg-4 col-md-6 mb-4')
      for n, i in enumerate(items, start=n):
      itemName = i.find('h4', class_='card-title').text.strip()
      itemPrice = i.find('h5').text
      print(f': за ')

      Результат будет выглядеть следующим образом.

      1: $24.99 за Short Dress 2: $29.99 за Patterned Slacks 3: $49.99 за Short Chiffon Dress . 52: $6.99 за T-shirt 53: $6.99 за T-shirt 54: $49.99 за Blazer

      Этот код можно оптимизировать для более продвинутых читателей:

       
      import requests
      from bs4 import BeautifulSoup

      url = 'https://scrapingclub.com/exercise/list_basic/'
      params =
      # задаем число больше номера первой страницы, для старта цикла
      pages = 2
      n = 1

      while params['page'] for n, i in enumerate(items, start=n):
      itemName = i.find('h4', class_='card-title').text.strip()
      itemPrice = i.find('h5').text
      print(f': за ')

      # [-2] предпоследнее значение, потому что последнее "Next"
      last_page_num = int(soup.find_all('a', class_='page-link')[-2].text)
      pages = last_page_num if pages < last_page_num else pages
      params['page'] += 1

      Выводы

      Beautiful Soup — одна из немногих библиотек для скрапинга в Python. С ней очень просто начать работать. Скрипты можно использовать для сбора и компиляции данных из интернета, а результат — как для анализа данных, так и для других сценариев.

      Request parser что это

      �� Самоучитель по Python для начинающих. Часть 17: Основы скрапинга и парсинга

      Парсинг полученных данных

      Извлечь адрес ссылки можно 4 разными способами – с помощью:

      • Методов строк.
      • Регулярного выражения.
      • Запроса XPath.
      • Обработки BeautifulSoup.

      Рассмотрим все эти способы по порядку.

      Методы строк

      Это самый трудоемкий способ – для извлечения каждого элемента нужно определить 2 индекса – начало и конец вхождения. При этом к индексу вхождения надо добавить длину стартового фрагмента:

      Путь XPath

      В приведенном выше примере для извлечения ссылки к пути /html/body/div/p[2]/a/ мы добавили указание для получения значения ссылки @href , и индекс [0] , поскольку результат возвращается в виде списка. Если @href заменить на text() , программа вернет текст ссылки, а не сам URL :

      �� Самоучитель по Python для начинающих. Часть 17: Основы скрапинга и парсинга

      Пока страница не прокручена, полный HTML -код с информацией о планшетах получить невозможно. Для имитации прокрутки мы воспользуемся скриптом 'window.scrollTo(0, document.body.scrollHeight);' . Цены планшетов находятся в тегах h 4 класса pull-right price, а названия моделей – в тексте ссылок a класса title. Готовый код выглядит так :

      �� Самоучитель по Python для начинающих. Часть 17: Основы скрапинга и парсинга

      Пример результата:

      �� Самоучитель по Python для начинающих. Часть 17: Основы скрапинга и парсинга

      from bs4 import BeautifulSoup import requests import re url = 'https://www.livelib.ru/book/1002978643-ohotnik-za-tenyu-donato-karrizi' headers = res = requests.get(url, headers=headers) soup = BeautifulSoup(res.text,'html.parser') sp = soup.find('div', class_='bc-menu__image-wrapper') img_url = re.findall(r'(?:https\:)?//.*\.(?:jpeg)', str(sp))[0] response = requests.get(img_url, headers=headers) if response.status_code == 200: file_name = url.split('-', 1)[1] with open(file_name + '.jpeg', 'wb') as file: file.write(response.content) 

      Задание 6

      Напишите программу, которая составляет рейтинг топ-100 лучших триллеров на основе этого списка.

      Пример результата:

      1. "Побег из Шоушенка", Стивен Кинг - 4.60 2. "Заживо в темноте", Майк Омер - 4.50 3. "Молчание ягнят", Томас Харрис - 4.47 4. "Девушка с татуировкой дракона", Стиг Ларссон - 4.42 5. "Внутри убийцы", Майк Омер - 4.38 . 98. "Абсолютная память", Дэвид Болдаччи - 4.22 99. "Сломанные девочки", Симона Сент-Джеймс - 4.11 100. "Цифровая крепость", Дэн Браун - 3.98 
      from bs4 import BeautifulSoup import requests url = 'https://www.livelib.ru/genre/%D0%A2%D1%80%D0%B8%D0%BB%D0%BB%D0%B5%D1%80%D1%8B/top' headers = res = requests.get(url, headers=headers) soup = BeautifulSoup(res.content,'html.parser') titles = soup.find_all('a', class_='brow-book-name with-cycle') authors = soup.find_all('a', class_='brow-book-author') rating = soup.find_all('span', class_='rating-value stars-color-orange') i = 1 for t, a, r in zip(titles, authors, rating): print(f'. "", - ') i += 1 

      Задание 7

      Напишите программу, которая составляет топ-20 языков программирования на основе рейтинга популярности TIOBE .

      Пример результата:

      1. Python: 14.83% 2. C: 14.73% 3. Java: 13.56% 4. C++: 13.29% 5. C#: 7.17% 6. Visual Basic: 4.75% 7. JavaScript: 2.17% 8. SQL: 1.95% 9. PHP: 1.61% 10. Go: 1.24% 11. Assembly language: 1.11% 12. MATLAB: 1.08% 13. Delphi/Object Pascal: 1.06% 14. Scratch: 1.00% 15. Classic Visual Basic: 0.98% 16. R: 0.93% 17. Fortran: 0.79% 18. Ruby: 0.76% 19. Rust: 0.73% 20. Swift: 0.71% 
      import requests from lxml import html url = 'https://www.tiobe.com/tiobe-index/' headers = page = requests.get(url, headers=headers) tree = html.fromstring(page.content) languages, rating = [], [] for i in range(1, 21): languages.append(tree.xpath(f'//*[@id="top20"]/tbody/tr[]/td[5]/text()')[0]) rating.append(tree.xpath(f'//*[@id="top20"]/tbody/tr[]/td[6]/text()')[0]) i = 1 for l, r in zip(languages, rating): print(f'. : ') i += 1 

      Задание 8

      Напишите программу для получения рейтинга 250 лучших фильмов по версии IMDb. Названия должны быть на русском языке.

      Пример результата:

      1. Побег из Шоушенка, (1994), 9,2 2. Крестный отец, (1972), 9,2 3. Темный рыцарь, (2008), 9,0 . 248. Аладдин, (1992), 8,0 249. Ганди, (1982), 8,0 250. Танцующий с волками, (1990), 8,0 
      import requests from lxml import html url = 'https://www.imdb.com/chart/top/' headers = page = requests.get(url, headers=headers) tree = html.fromstring(page.content) movies, year, rating = [], [], [] for i in range(1, 251): movies.append(tree.xpath(f'//*[@id="main"]/div/span/div/div/div[3]/table/tbody/tr[]/td[2]/a/text()')[0]) year.append(tree.xpath(f'//*[@id="main"]/div/span/div/div/div[3]/table/tbody/tr[]/td[2]/span/text()')[0]) rating.append(tree.xpath(f'//*[@id="main"]/div/span/div/div/div[3]/table/tbody/tr[]/td[3]/strong/text()')[0]) i = 1 for m, y, r in zip(movies, year, rating): print(f'. , , ') i += 1 

      Задание 9

      Напишите программу, которая сохраняет в текстовый файл данные о фэнтези фильмах с 10 первых страниц соответствующего раздела IMDb . Если у фильма/сериала еще нет рейтинга, следует указать N / A .

      Ожидаемый результат в файле fantasy . txt – 500 записей:

      Мандалорец, (2019– ), 8,7 Всё везде и сразу, (2022), 8,0 Атака титанов, (2013–2023), 9,0 Peter Pan & Wendy, (2023), N/A Игра престолов, (2011–2019), 9,2 . Шрэк 3, (2007), 6,1 Кунг-фу Панда 3, (2016), 7,1 Смерть ей к лицу, (1992), 6,6 Исход: Цари и боги, (2014), 6,0 Кошмар на улице Вязов 3: Воины сна, (1987), 6,6 
      import requests import mechanicalsoup from lxml import html import time url = 'https://www.imdb.com/search/title/?genres=fantasy' headers = browser = mechanicalsoup.StatefulBrowser() j = 51 for _ in range(10): browser.open(url) page = requests.get(url, headers=headers) tree = html.fromstring(page.content) titles, year, rating = [], [], [] for i in range(1, 51): if tree.xpath(f'//*[@id="main"]/div/div[3]/div/div[]/div[3]/p[1]/b/text()') != []: titles.append(tree.xpath(f'//*[@id="main"]/div/div[3]/div/div[]/div[3]/h3/a/text()')[0]) year.append(tree.xpath(f'//*[@id="main"]/div/div[3]/div/div[]/div[3]/h3/span[2]/text()')[0]) rating.append('N/A') else: titles.append(tree.xpath(f'//*[@id="main"]/div/div[3]/div/div[]/div[3]/h3/a/text()')[0]) year.append(tree.xpath(f'//*[@id="main"]/div/div[3]/div/div[]/div[3]/h3/span[2]/text()')[0]) rating.append(tree.xpath(f'//*[@id="main"]/div/div[3]/div/div[]/div[3]/div/div[1]/strong/text()')[0]) with open('fantasy.txt', 'a', encoding='utf-8') as file: for t, y, r in zip(titles, year, rating): file.write(f', , \n') time.sleep(2) lnk = browser.follow_link('start=' + str(j)) url = browser.url j += 50 

      Задание 10

      Напишите программу для получения главных новостей (на русском) с портала Habr. Каждый заголовок должен сопровождаться ссылкой на полный текст новости.

      Пример вывода:

      Bethesda назвала дату релиза Starfield на ПК, Xbox Series и Xbox Game Pass — 6 сентября 2023 года https://habr.com/ru/news/t/721148/ Honda запатентовала съёмные подушки безопасности для мотоциклистов https://habr.com/ru/news/t/721142/ . Microsoft увольняет 689 сотрудников из своих офисов в Сиэтле https://habr.com/ru/news/t/721010/ «Ъ»: в России образовались большие запасы бытовой техники из-за низкого спроса https://habr.com/ru/news/t/721006/ 
      from bs4 import BeautifulSoup import requests url = 'https://habr.com/ru/news/' headers = res = requests.get(url, headers=headers) soup = BeautifulSoup(res.content,'html.parser') articles = soup.find_all('a', class_='tm-article-snippet__title-link') for a in articles: print(f'\nhttps://habr.com') 

      Заключение

      Мы рассмотрели основные приемы работы с главными Python -инструментами для скрапинга и парсинга. Способы извлечения и обработки данных варьируются от сайта к сайту – в некоторых случаях эффективнее использование XPath , в других – разбор с BeautifulSoup , а иногда может потребоваться применение регулярных выражений.

      В следующей главе приступим к изучению основ ООП (объектно-ориентированного программирования).

      1. Особенности, сферы применения, установка, онлайн IDE
      2. Все, что нужно для изучения Python с нуля – книги, сайты, каналы и курсы
      3. Типы данных: преобразование и базовые операции
      4. Методы работы со строками
      5. Методы работы со списками и списковыми включениями
      6. Методы работы со словарями и генераторами словарей
      7. Методы работы с кортежами
      8. Методы работы со множествами
      9. Особенности цикла for
      10. Условный цикл while
      11. Функции с позиционными и именованными аргументами
      12. Анонимные функции
      13. Рекурсивные функции
      14. Функции высшего порядка, замыкания и декораторы
      15. Методы работы с файлами и файловой системой
      16. Регулярные выражения
      17. Основы скрапинга и парсинга
      18. Основы ООП – инкапсуляция и наследование
      19. Основы ООП – абстракция и полиморфизм
      20. Графический интерфейс на Tkinter
      21. Основы разработки игр на Pygame
      22. Основы работы с SQLite
      23. Основы веб-разработки на Flask
      24. Основы работы с NumPy
      25. Основы анализа данных с Pandas

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *