Разное

Парсер html страниц: HTML парсер онлайн

Содержание

30 бесплатных программ для парсинга сайтов в 2020 году — Сервисы на vc.ru

Моя компания занимается парсингом сайтов в России уже более трёх лет, ежедневно мы парсим более 500 крупнейших интернет-магазинов в России. На выходе мы, как правило, отдаем данные в формате Excel/CSV. Но существуют и другие решения — готовые сервисы (конструкторы) для запуска парсинга практически без программирования. Ниже их список, краткая аннотация и рейтинг к каждому.

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

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

Ищете ли вы потенциальных клиентов, проводите анализ рынка или собираете данные для проверки своих моделей машинного обучения — вам так или иначе нужно получать данные со сторонних ресурсов. Вот некоторые из лучших бесплатных (или условно бесплатных) программ для парсинга веб-страниц с независимым рейтингом.

1. Mozenda

Mozenda помогает компаниям в сборе и организации данных наиболее экономичным и эффективным способом. Компания предлагает облачную архитектуру, которая обеспечивает масштабируемость, простоту использования и быстрое развертывание.

Внедрить Mozenda можно довольно быстро, к тому же развернуть это ПО можно за считанные минуты на уровне бизнес-подразделения без какого-либо участия ИТ-отдела. Его простой point-and-click интерфейс помогает пользователям создавать проекты и быстро экспортировать результаты, самостоятельно или по расписанию.

Благодаря простоте интеграции пользователи могут публиковать полученные результаты в формате CSV, TSV, XML или JSON.

  • Лучшая функция: безопасная облачная среда.
  • Сайт: mozenda.com.
  • Минусы: крутая кривая обучения.

Бенчмарк HTML парсеров / Хабр

Переписывал в островке кусок одного сервиса с Python на Erlang. Сам сервис занимается тем, что скачивает по HTTP значительное количество однотипных HTML страниц и извлекает из них некоторую информацию. Основная CPU нагрузка сервиса приходится на парсинг HTML в DOM дерево.

Сперва захотелось сравнить производительность Erlang парсера mochiweb_html с используемым из Python lxml.etree.HTML(). Провел простейший бенчмарк, нужные выводы сделал, а потом подумал что неплохо было бы добавить в бенчмарк ещё парочку-другую парсеров и платформ, оформить покрасивее, опубликовать код и написать статью.

На данный момент успел написать бенчмарки на Erlang, Python, PyPy, NodeJS и С в следующих комбинациях:

  • Erlang — mochiweb_html
  • CPython — lxml.etree.HTML
  • CPython — BeautifulSoup 3
  • CPython — BeautifulSoup 4
  • CPython — html5lib
  • PyPy — BeautifulSoup 3
  • PyPy — BeautifulSoup 4
  • PyPy — html5lib
  • Node.JS — cheerio
  • Node.JS — htmlparser
  • Node.JS — jsdom
  • C — libxml2 (скорее для справки)

В тесте сравниваются скорость обработки N итераций парсера и пиковое потребление памяти.

Интрига: кто быстрее — Python или PyPy? Как сказывается иммутабельность Erlang на скорости парсинга и потреблении памяти? Насколько быстра V8 NodeJS? И как на всё это смотрит код на чистом C.

Термины

Скорее всего вы с ними знакомы, но почему бы не повторить?

Нестрогий HTML парсер — парсер HTML, который умеет обрабатывать некорректный HTML код (незакрытые теги, знаки > < внутри тегов <script>, незаэскейпленные символы амперсанда &, значения атрибутов без кавычек и т.п.). Понятно, что не любой поломанный HTML можно восстановить, но можно привести его к тому виду, к которому его приводит браузер. Примечательно, что большая часть HTML, которая встречается в интернете, является в той или иной степени невалидной!
DOM дерево — Document Object Model если говорить строго, то DOM это тот API, который предоставляется яваскрипту в браузере для манипуляций над HTML документом. Мы немного упростим задачу и будем считать, что это структура данных, которая представляет из себя древовидное отображение структуры HTML документа. В корне дерева находится элемент <html>, его дочерние элементы — <head> и <body> и так далее. Например, в Python документ

<html lang="ru-RU">
    <head></head>
    <body>Hello, World!</body>
</html>

Можно в простейшем виде представить как

("html", {"lang": "ru-RU"}, [
    ("head", {}, []),
    ("body", {}, ["Hello, World!"])
])

Обычно HTML преобразуют в DOM дерево для трансформации или для извлечения данных. Для извлечения данных из дерева очень удобно использовать XPath или CSS селекторы.

Конкурсанты

  • Erlang
    • Mochiweb html parser. Единственный нестрогий HTML парсер для Erlang. Написан на эрланге.

  • CPython
    • lxml.etree.HTML биндинг libxml2. Cython
    • BeautifulSoup 3 Написанный на python HTML DOM парсер (3-я версия).
    • BeautifulSoup 4 HTML DOM парсер с подключаемыми бекендами.
    • html5lib Написанный на питоне DOM парсер, ориентированный на HTML5.

  • PyPy (те же парсеры, что и CPython, кроме lxml)
    • BeautifulSoup 3
    • BeautifulSoup 4
    • html5lib

  • Node.JS
    • cheerio написанный на JS HTML DOM парсер с поддержкой jQuery API
    • htmlparser HTML DOM парсер на чистом JS
    • jsdom написанный на JS HTML DOM парсер с навороченным API, похожем на API браузера

  • C
    • libxml2 Написанный на C нестрогий HTML SAX/DOM парсер.

Цели

Вообще, парсинг HTML (как и JSON) интересен тем, что документ нужно просматривать посимвольно. В нём нет инструкций вроде «следующие 10Кб — это сплошной текст, его копируем как есть». Если мы встретили в тексте тег <p>, то нам нужно последовательно просматривать все последующие символы на наличие конструкции </. Тот факт, что HTML может быть невалидным, заставляет «перепроверять всё по 2 раза». Потому что, например, если мы встретили тег <option>, то далеко не факт, что встретим закрывающий </option>. Вторая проблема, которая обычно возникает с такими форматами — экранирование спецсимволов. Например, если весь документ это <html>...100 мегабайт текста... &amp; ...ещё 100 мегабайт текста...</html>, то парсер будет вынужден создать в памяти полную копию содержимого тега с единственным изменением — «&», преобразованный в «&» (хотя некоторые парсеры просто разбивают такой текст на 3 отдельных куска).

Необходимость строить в памяти довольно большую структуру — дерево из мелких объектов, накладывает довольно жесткие требования на управление памятью, сборщик мусора, на оверхед на создание множества мелких объектов.

Нашим бенчмарком хотим:

  • Сравнить производительность и потребление памяти различных нестрогих HTML DOM парсеров.
  • Изучить стабильность работы парсера. Возрастет ли время обработки одной страницы и объём потребляемой памяти с ростом числа итераций?
  • Как зависит скорость парсинга и потребление памяти от размера HTML документа.
  • Ну и оценить эффективность платформы: скорость работы со строками, эффективность менеджмента памяти

Проверять качество работы парсера в плане полноты восстановления поломанных документов не будем. Сравнение удобства API и наличие инструментов для работы с деревом тоже оставим за кадром.

Условия и методика тестирования

Программа один раз считывает документ с диска в память и затем N раз последовательно парсит его в цикле.
Парсер на каждой итерации должен строить в памяти полное DOM дерево.
После N итераций программа печатает время работы цикла и завершается.

Каждый парсер запускаем на наборе из нескольких HTML документов на N = 10, 50, 100, 400, 600 и 1000 итераций.

Измеряем User CPU, System CPU, Real runtime и (примерное?) пиковое потребление памяти с помощью /usr/bin/time.

HTML документы:

  • page_google.html (116Kb) — выдача гугла, 50 результатов на странице. Очень много встроенного в страницу HTML и JS, мало текста, весь HTML в одну строку.
  • page_habrahabr-70330.html (1,6Mb) — статья на хабре с 900 комментариями. Очень большая страница, много тегов, пробелов и табуляции.
  • page_habrahabr-index.html (95Kb) — главная страница habrahabr. Типичная страница блога.
  • page_wikipedia.html (99Kb) — статья на wikipedia. Хотел страничку, на которой будет много текста и мало тегов, но выбрал не самую удачную. В итоге много тегов и встроенного CSS.

На самом деле понял, что большинство документов одинакового размера только под конец, но переделывать не стал, т.к. сам процесс измерения занимает довольно много времени. А так было бы интересно отследить различные зависимости ещё и от размера страницы. UPD: готовится вторая часть статьи, в ней будем парсить сайты из TOP1000 Alexa.

Тесты запускал последовательно на Ubuntu 3.5.0-19-generic x86_64, процессор Intel Core i7-3930K CPU @ 3.20GHz × 12. (Нафига 12 ядер, если тесты запускать последовательно? Эхх…)

Код

Весь код доступен на github. Можете попробовать запустить самостоятельно, подробные инструкции есть в README файле. Даже нет — настоятельно рекомендую не верить мне, а проверить как поведут себя тесты на вашем окружении!
Tip: если хотите протестировать только часть платформ (например, не хотите устанавливать себе Erlang или PyPy), то это легко задается переменной окружения PLATFORMS.
Буду рад пулл-реквестам с реализацией парсеров на других языках (PHP? Java? .NET? Ruby?), постараюсь добавить в результаты (в первую очередь интересны нативные реализации — биндинги к libxml как правило не отличаются по скорости). Интересно было бы попробовать запустить тесты на каких-нибудь других интересных HTML файлах (большая вложенность тегов, различные размеры файлов).

Результаты

Вот сырые результаты измерений в виде CSV файлов results-1000.csv results-600.csv results-400.csv results-100.csv results-50.csv results-10.csv. Попробуем их проанализировать, для этого воспользуемся скриптом на языке R (находится в репозитории с бенчмарком в папке stats/).

Скорость

Для исследования зависимости скорости работы парсера от числа итераций, построим гистограммы зависимости [времени на обработку одной страницы] от [числа итераций]. Время на обработку одной страницы считаем как время работы парсера, разделенное на число итераций. В идеальном варианте скорость работы парсера не должна зависеть от числа итераций, а лучше — должна возрастать (за счет JIT например).
Все графики кликабельны! Не ломайте глаза!

Зависимость времени на обработку документа от числа итераций парсера (здесь и далее — для каждой HTML страницы отдельный график).


Столбики одинаковой высоты — хорошо, разной — плохо. Видно, что для большинства парсеров зависимости нет (все столбики одинаковой высоты). Исключение составляют только BeautifulSoup 4 и html5lib под PyPy; по какой-то причине у них с ростом числа итераций производительность снижается. То есть если ваш парсер на PyPy должен работать продолжительное время, то производительность будет постепенно снижаться. Неожиданно…

Теперь самый интересный график — средняя скорость обработки одной странички каждым парсером. Построим box-plot диаграмму.
Среднее время на обработку документа.


Чем выше находится бокс — тем медленнее работает парсер. Чем больше бокс по площади, тем больше разброс значений (т.е. выше зависимость производительности от числа итераций). Видно, что парсер на C лидирует, за ним следуют lxml.etree, почти вплотную парсеры на NodeJS и Erlang, потом bsoup3 парсер на PyPy, парсеры на CPython и потом с большим отрывом те же парсеры, запущенные на PyPy. Вот так сюрприз! PyPy всем сливает.

Ещё одна странность — bsoup 3 парсеру на Python чем-то не понравилась страничка википедии :-).

Пример табличных данных:

> subset(res, (file=="page_google.html") & (loops==1000))[ c("platform", "parser", "parser.s", "real.s", "user.s") ]
    platform                parser   parser.s real.s user.s
6  c-libxml2 libxml2_html_parser.c   2.934295   2.93   2.92
30    erlang     mochiweb_html.erl  13.346997  13.51  13.34
14    nodejs     cheerio_parser.js   5.303000   5.37   5.36
38    nodejs  htmlparser_parser.js   6.686000   6.72   6.71
22    nodejs       jsdom_parser.js  98.288000  98.42  98.31
33      pypy      bsoup3_parser.py  40.779929  40.81  40.62
57      pypy      bsoup4_parser.py 434.215878 434.39 433.91
41      pypy    html5lib_parser.py 361.008080 361.25 360.46
65    python      bsoup3_parser.py  78.566026  78.61  78.58
49    python      bsoup4_parser.py  33.364880  33.45  33.43
60    python    html5lib_parser.py 200.672682 200.71 200.70
67    python        lxml_parser.py   3.060202   3.08   3.08
Память

Теперь посмотрим на использование памяти. Сперва посмотрим, как потребление памяти зависит от числа итераций. Снова построим гистограммы. В идеале все столбики одного парсера должны быть одинаковой высоты. Если потребление растет с увеличением числа итераций, то это указывает на утечки памяти или проблемы со сборщиком мусора.
Потребление памяти в зависимости от числа итераций парсера.

Занятно. Bsoup4 и html5lib под PyPy заняли по 5Гб памяти после 1000 итераций по 1Мб файлу. (Привел здесь только 2 графика, т.к. на остальных такая же картина). Видно, что с ростом числа итераций практически линейно растет и потребляемая память. Получается, что PyPy просто не совместим с Bsoup4 и html5lib парсерами. С чем это связано и кто виноват я не знаю, но зато понятно, что использование PyPy без тщательной проверки совместимости со всеми используемыми библиотеками — весьма рискованное занятие.
Выходит, что комбинация PyPy с этими парсерами выбывает. Попробуем убрать их с графиков:
Потребление памяти в зависимости от числа итераций парсера (без Bsoup4 и html5lib на PyPy).

Видим, что для парсера на C все столбики практически идентичной высоты. То же самое для lxml.etree. Для большинства парсеров потребление памяти при 10 итерациях немного меньше. Возможно просто time не успевает её замерить. NodeJS парсер jsdom ведет себя довольно странно — у него потребление памяти для некоторых страниц скачет весьма случайным образом, но в целом виден рост потребления памяти со временем. Возможно какие-то проблемы со сборкой мусора.

Сравним усредненное потребление памяти для оставшихся парсеров. Построим box-plot.
Усредненное потребление памяти.


Видим, что расстановка примерно такая же, как в сравнении скорости, но у Erlang потребление памяти оказалось ниже, чем у NodeJS. lxml.etree требует памяти примерно в 2 раза больше, чем C libxml2, но меньше чем любой другой парсер. NodeJS парсер jsdom несколько выпадает из общей картины, потребляя ~ в 2 раза больше памяти, чем другие NodeJS парсеры — видимо у него значительный оверхед, связанный с созданием дополнительных атрибутов у элементов DOM дерева.

Пример табличных данных:

> subset(res, (file=="page_google.html") & (loops==1000))[ c("platform", "parser", "maximum.RSS") ]
    platform                parser maximum.RSS
6  c-libxml2 libxml2_html_parser.c        2240
30    erlang     mochiweb_html.erl       21832
14    nodejs     cheerio_parser.js       49972
38    nodejs  htmlparser_parser.js       48740
22    nodejs       jsdom_parser.js      119256
33      pypy      bsoup3_parser.py       61756
57      pypy      bsoup4_parser.py     1701676
41      pypy    html5lib_parser.py     1741944
65    python      bsoup3_parser.py       42192
49    python      bsoup4_parser.py       54116
60    python    html5lib_parser.py       45496
67    python        lxml_parser.py        9364
Оверхед на запуск программы

Это уже не столько тест HTML парсера, сколько попытка выяснить какую платформу стоит использовать для написания консольных утилит. Просто небольшое дополнение (раз у нас уже есть данные). Оверхед платформы — это время, которое программа тратит не на непосредственно работу, а на подготовку к ней (инициализация библиотек, считывание HTML файла и т.п.). Что бы его вычислить, вычтем из времени, которое вывела утилита time — «time.s», время, которое замерили вокруг цикла парсера — «parser.s».

Видно, что оверхед в большинстве случаев несущественный. Примечательно, что у Erlang он сравнимый с Python. Можно предположить, что он зависит от массивности библиотек, которые программа импортирует.

Выводы

Как видим — реализация на C впереди планеты всей (но и кода в ней получилось побольше).

Биндинг libxml2 к питону (lxml.etree.HTML) работает практически с такой же скоростью, но потребляет в 2 раза больше памяти (скорее всего оверхед собственно интерпретатора). Выходит, предпочтительный парсер на Python — это lxml.

Парсер на голом Erlang показывает на удивление высокие результаты, несмотря на приписываемые эрлангу «копирования данных на каждый чих» ©. Скорость сравнима с простыми парсерами на NodeJS и выше, чем у Python парсеров. Потребление памяти ниже только у C и lxml. Стабильность отличная. Такой парсер можно выпускать в продакшн (что я и сделал).

Простые парсеры на NodeJS работают очень быстро — в 2 раза медленнее сишной libxml. V8 работает крайне эффективно. Но памяти потребляют на уровне с Python, причем память расходуется не слишком стабильно (расход памяти может вырасти при увеличении числа итераций с 10 до 100, но потом стабилизируется). Парсер jsdom для простого парсинга явно не подходит, т.к. у него слишком высокие накладные расходы. Так что для парсинга HTML в NodeJS лучший выбор — cheerio.

Парсеры на чистом Python сливают как по скорости, так и по потреблению памяти, причем результаты сильно скачут на разных страницах. Но при этом ведут себя стабильно на разном количестве итераций (GC работает равномерно?)

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

Ссылки

Код бенчмарка Мой блог
Document Object Model

Присылайте свои реализации! Это очень просто!

UPD:
Результаты для добавленных парсеров (графики, CSV):

golang (3 шт, один быстрее С(!!!))

haskell (крайне неплохо)

java (openjdk, oracle-jre) (автоматически параллелится, занимая ~150% CPU, user CPU > real CPU)

perl

php + tidy

ruby (биндинг к libxml)

dart (очень медленный)

mono (2 шт) (автоматически параллелится, занимая ~150% CPU, user CPU > real CPU)

Полноценную статью + исследование зависимости скорости и потребления памяти от размера страницы по TOP1000 Alexa будет позже (надеюсь).

Осваиваем парсинг сайта: короткий туториал на Python

Постоянно в Интернете, ничего не успеваете? Парсинг сайта спешит на помощь! Разбираемся, как автоматизировать получение нужной информации.

Чтобы быть в курсе, кто получит кубок мира в 2019 году, или как будет выглядеть будущее страны в ближайшие 5 лет, приходится постоянно зависать в Интернете. Но если вы не хотите тратить много времени на Интернет и жаждете оставаться в курсе всех событий, то эта статья для вас. Итак, не теряя времени, начнём!

Доступ к новейшей информации получаем двумя способами. Первый – с помощью API, который предоставляют медиа-сайты, а второй – с помощью парсинга сайтов (Web Scraping).

Использование API предельно просто, и, вероятно, лучший способ получения обновлённой информации – вызвать соответствующий программный интерфейс. Но, к сожалению, не все сайты предоставляют общедоступные API. Таким образом, остаётся другой путь – парсинг сайтов.

Парсинг сайта

Это метод извлечения информации с веб-сайтов. Эта методика преимущественно фокусируется на преобразовании неструктурированных данных – в формате HTML – в Интернете в структурированные данные: базы данных или электронные таблицы. Парсинг сайта включает в себя доступ к Интернету напрямую через HTTP или через веб-браузер. В этой статье будем использовать Python, чтобы создать бот для получения контента.

Последовательность действий

  • Получить URL страницы, с которой хотим извлечь данные.
  • Скопировать или загрузить HTML-содержимое страницы.
  • Распарсить HTML-содержимое и получить необходимые данные.

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

Пакеты

Для анализа HTML-содержимого и получения необходимых данных используется библиотека Beautiful Soup. Это удивительный пакет Python для парсинга документов формата HTML и XML.

Для входа на веб-сайт, перехода к нужному URL-адресу в рамках одного сеанса и загрузки HTML-содержимого будем использовать библиотеку Selenium. Selenium Python помогает при нажатии на кнопки, вводе контента и других манипуляциях.

Погружение в код

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

# импорт библиотек
from selenium import webdriver
from bs4 import BeautifulSoup

Затем укажем драйверу браузера путь к Selenium, чтобы запустить наш веб-браузер (Google Chrome). И если не хотим, чтобы наш бот отображал графический интерфейс браузера, добавим опцию headless в Selenium.

Браузеры без графического интерфейса (headless) предоставляют автоматизированное управление веб-страницей в среде, аналогичной популярным веб-браузерам, но выполняются через интерфейс командной строки или с использованием сетевых коммуникаций.

# путь к драйверу chrome
chromedriver = '/usr/local/bin/chromedriver'
options = webdriver.ChromeOptions()
options.add_argument('headless')  # для открытия headless-браузера
browser = webdriver.Chrome(executable_path=chromedriver, chrome_options=options)

После настройки среды путём определения браузера и установки библиотек приступаем к HTML. Перейдём на страницу входа и найдём идентификатор, класс или имя полей для ввода адреса электронной почты, пароля и кнопки отправки, чтобы ввести данные в структуру страницы.

# Переход на страницу входа
browser.get('http://playsports365.com/default.aspx')
# Поиск тегов по имени
email = browser.find_element_by_name('ctl00$MainContent$ctlLogin$_UserName')
password = browser.find_element_by_name('ctl00$MainContent$ctlLogin$_Password')
login = browser.find_element_by_name('ctl00$MainContent$ctlLogin$BtnSubmit')

Затем отправим учётные данные в эти HTML-теги, нажав кнопку «Отправить», чтобы ввести информацию в структуру страницы.

# добавление учётных данных для входа
email.send_keys('********')
password.send_keys('*******')
# нажатие на кнопку отправки
login.click()

После успешного входа в систему перейдём на нужную страницу и получим HTML-содержимое страницы.

# После успешного входа в систему переходим на страницу «OpenBets»
browser.get('http://playsports365.com/wager/OpenBets.aspx')
# Получение HTML-содержимого
requiredHtml = browser.page_source

Когда получили HTML-содержимое, единственное, что остаётся, – парсинг. Распарсим содержимое с помощью библиотек Beautiful Soup и html5lib.

html5lib – это пакет Python, который реализует алгоритм парсинга HTML5, на который сильно влияют современные браузеры. Как только получили нормализованную структуру содержимого, становится доступным поиск данных в любом дочернем элементе тега html. Искомые данные присутствуют в теге table, поэтому ищем этот тег.

soup = BeautifulSoup(requiredHtml, 'html5lib')
table = soup.findChildren('table')
my_table = table[0]

Один раз находим родительский тег, а затем рекурсивно проходим по дочерним элементам и печатаем значения.

# получение тегов и печать значений
rows = my_table.findChildren(['th', 'tr'])
for row in rows:
    cells = row.findChildren('td')
    for cell in cells:
        value = cell.text
        print (value)

Чтобы выполнить указанную программу, установите библиотеки Selenium, Beautiful Soup и html5lib с помощью pip. После установки библиотек команда #python <program name> выведет значения в консоль.

Так парсятся данные с любого сайта.

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

Используете парсинг сайта?

Для вывода результатов необязательно ограничиваться консолью, правда?

Как вы предпочитаете отображать данные подобных программ: выводить на панель уведомлений, отправлять на почту или иначе? Делитесь полезными находками 🙂

Надеемся, вам понравилась статья.

Оригинал

Действие HTML: Поиск тегов | Инструкция по программе Parser

Действие «HTML: Поиск тегов» является одним из основных действий программы, при помощи которого можно осуществлять разнообразные операции с html-тегами — поиск, удаление, извлечение из тегов атрибутов и т.д.

Параметры действия:

Предназначение действия:

Извлечь нужные данные из исходного кода страницы сайта.

В качестве параметров задаётся: тип элемента (например, DIV или TABLE), название искомого атрибута (id, class, itemprop, name), значение проверяемого атрибута, и тип результата (innerHTML — только содержимое элемента, outerHTML — элемент целиком, или ConvertToText — преобразованное в текст содержимое).

Возвращаемое значение: один или несколько результатов (HTML или текст)

 


Параметр «Тип элемента»

Тип параметра: выбор из списка, или ввод вручную

Примеры значений параметра: div; span; ul; li; meta; input; img; meta; table; tr; a; p; h2; h3; h4; Any Tag

Значение по умолчанию: div

Можно указать (ввести или выбрать из списка) любое название тега.

Если нужно найти любые теги (независимо от названия тега), укажите в этом параметре Any Tag.
Можно использовать подстановочный символ * в начале или конце имени тега, а также использовать регулярные выражения (RegExp). Например, для поиска всех заголовков (теги h2, h3, h4 … h6) можно применить записи вида h*, h[123456], h\d.

Если требуется искать 2 или больше названий тегов, применяется RegExp синтаксис вида (div|span)

 

Параметр «Название проверяемого атрибута»

Тип параметра: выбор из списка, или ввод вручную

Примеры значений параметра: AttributesPattern; id; name; class; title; type; itemprop

Можно указать (ввести или выбрать из списка) любое название атрибута, например class или id.
Для поиска значения (из третьего параметра) как в названиях атрибутов, так и в значениях, выберите в этом поле опцию AttributesPattern.

 

Параметр «Значение проверяемого атрибута»

Тип параметра: произвольное текстовое значение

 

Параметр «Тип результата / извлекаемый атрибут»

Тип параметра: выбор из списка, или ввод вручную

Примеры значений параметра: тег или его начинка (outerHTML; innerHTML), тег преобразованный в текст (ConvertToText), название извлекаемого атрибута (content; href; href_with_prefix; src; src_with_prefix; value; data), спец. команды (URL|Text; DeleteTags; ReplaceTagWithItsText; TagHeaderOnly)

Значение по умолчанию: innerHTML

В этом параметре допустимо указать 2 опции (через пробел):

Опция 1 (обязательная): тип результата / команда
Подробнее о всех типах результата можно узнать из видеоинструкции.

Опция 2 (необязательная): порядковый номер результата (на случай, если результатов несколько, а нужен только один)
Если в исходном HTML коде найдено несколько подходящих тегов, действие возвращает МАССИВ результатов (если порядковый номер не указан, т.е. тип результата задан в виде innerHTML или ConvertToText. Задав порядковый номер в виде числа (1, 2 и т.п.) или кодового слова last, мы получим на выходе один результат (первый, второй, или последний), например: innerHTML 1ConvertToText last.

 

Параметр «Сохранить результат в переменную»

Тип параметра: произвольное текстовое значение

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

 

Параметр «Использовать новое значение»

Тип параметра: выбор из списка предопределенных значений

Допустимые значения параметра: да; нет

Значение по умолчанию: да

Этот параметр ставится равным НЕТ только в одном единственном случае, при выполнении сразу 2 условий:

  1. мы не будет использовать результат действия сразу, в следующем действии / выводе на лист (а только сохраняем его в переменную, для использования в другом месте парсера)
  2. для дальнейшей обработки (например, поиска следующего тега) нам нужен исходный HTML, а не результат выполнения этого действия

 

Примеры использования:

 

Действие Параметр Значение
HTML: Поиск тегов Тип элемента a
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут outerHTML
 
Исходное значение   Результат (массив)
<ul><li><a href="/popular" target="_self">Поиск HTML тегов</a></li>
<li><a href="/NewArticles2" target="_self">Последние публикации</a></li>
<li><a href="/tools" target="_self">Инструменты разработчика</a></li></ul>
 
<a href="/popular" target="_self">Поиск HTML тегов</a>
<a href="/NewArticles2" target="_self">Последние публикации</a>
<a href="/tools" target="_self">Инструменты разработчика</a>

В данном примере мы в куске кода ищем теги <a> и на выходе получаем массив из 3 элементов.

Параметр Тип элемента

Обязательный параметр, в котором указывается тип тега, который мы ищем. Может указываться любое значение — не только стандартные теги, но вообще любой тег. Например, в приведенном ниже куске XML мы можем искать тег matchCollectionId

Действие Параметр Значение
HTML: Поиск тегов Тип элемента matchCollectionId
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут outerHTML
 
Исходное значение   Результат
<tournament><id>72040</id><type>fantasy</type><userId></userId><whiteLabelId>1</whiteLabelId><matchCollectionId>7347</matchCollectionId><maxPlayersPerTeam>3</maxPlayersPerTeam><name>Full Round </name><buyIn>10.00</buyIn><freeroll>False</freeroll><substitutes>1</substitutes></tournament>
 
<matchCollectionId>7347</matchCollectionId>

Отдельно стоит указать, что можно использовать значение первого параметра — Any Tag — это значит, что будет искаться любой тег, удовлетворяющий условиям 2 и 3 параметров Действия.

Параметры Название проверяемого атрибута и Значение проверяемого атрибута

Обычно эти параметры используются вместе. Давайте рассмотрим на примере, как они работают, а заодно покажем пример использования значения Any Tag в первом параметре.

Действие Параметр Значение
HTML: Поиск тегов Тип элемента Any Tag
Название проверяемого атрибута class
Значение проверяемого атрибута Main
Тип результата / извлекаемый атрибут outerHTML
 
Исходное значение   Результат (массив)
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
<div>Поиск HTML тегов</div>
<span>Поиск HTML тегов</span>
<tr>Поиск HTML тегов</tr>
 
<span>Поиск HTML тегов</span>
<div>Поиск HTML тегов</div>

В примере мы видим искусственно созданный html из разных тегов с разными атрибутами. Ищется любой тег с условием, что у него должен быть класс Main.

Если, например, класс состоит из нескольких слов, то не обязательно указывать его полностью. Достаточно, чтобы искомое слово (3 параметр) был отделен пробелом от остальных слов в классе.

Действие Параметр Значение
HTML: Поиск тегов Тип элемента Any Tag
Название проверяемого атрибута class
Значение проверяемого атрибута row
Тип результата / извлекаемый атрибут outerHTML
 
Исходное значение   Результат (массив)
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
 
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>

Находятся все теги, где в классе «row» встречается как отдельное слово.

Если к третьему параметру добавить в начале и/или в конце *, то это будет означать «любые символы до и/или после» соответственно.

Чтобы звездочка сработала внутри значения, надо использовать два символа: точку и звездочку .*

 

Действие Параметр Значение
HTML: Поиск тегов Тип элемента Any Tag
Название проверяемого атрибута class
Значение проверяемого атрибута *Main
Тип результата / извлекаемый атрибут outerHTML
 
Исходное значение   Результат (массив)
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
<div>Поиск HTML тегов</div>
<span>Поиск HTML тегов</span>
<tr>Поиск HTML тегов</tr>
 
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
<div>Поиск HTML тегов</div>

Находится не только класс Main, но и NotMain, который удовлетворяет условию *Main

Также в 3 параметре могут быть записаны регулярные выражения. Например:

Действие Параметр Значение
HTML: Поиск тегов Тип элемента Any Tag
Название проверяемого атрибута class
Значение проверяемого атрибута (First|Second)
Тип результата / извлекаемый атрибут outerHTML
 
Исходное значение   Результат (массив)
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
<div>Поиск HTML тегов</div>
<tr>Поиск HTML тегов</tr>
<span>Поиск HTML тегов</span>
<li>Поиск HTML тегов</li>
<div>Поиск HTML тегов</div>
 
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
<div>Поиск HTML тегов</div>
<li>Поиск HTML тегов</li>

Здесь ищутся классы First или Second.

В первый параметр Действия также можно записать поиск нескольких тегов при помощи аналогичного формата, например, (span|div) но это редко используется.

Третий параметр может использоваться отдельно (c пустым вторым)

Действие Параметр Значение
HTML: Поиск тегов Тип элемента Any Tag
Название проверяемого атрибута  
Значение проверяемого атрибута Main
Тип результата / извлекаемый атрибут outerHTML
 
Исходное значение   Результат (массив)
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
<div>Поиск HTML тегов</div>
<span>Поиск HTML тегов</span>
<tr>Поиск HTML тегов</tr>
 
<span>Поиск HTML тегов</span>
<div>Поиск HTML тегов</div>
<tr>Поиск HTML тегов</tr>

Обратите внимание, здесь дополнительно получен тег с id Main.
А вот заполненный второй параметр без третьего работать не будет.

Действие Параметр Значение
HTML: Поиск тегов Тип элемента Any Tag
Название проверяемого атрибута class
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут outerHTML
 
Исходное значение   Результат
<span>Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
<div>Поиск HTML тегов</div>
<span>Поиск HTML тегов</span>
<tr>Поиск HTML тегов</tr>
  (пустая строка)

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

Действие Параметр Значение
HTML: Поиск тегов Тип элемента Any Tag
Название проверяемого атрибута data
Значение проверяемого атрибута (First|Second)
Тип результата / извлекаемый атрибут outerHTML
 
Исходное значение   Результат (массив)
<span data="First">Поиск HTML тегов</span>
<span>Поиск HTML тегов</span>
<div data="First">Поиск HTML тегов</div>
<tr>Поиск HTML тегов</tr>
<span data="Third">Поиск HTML тегов</span>
<li>Поиск HTML тегов</li>
<div>Поиск HTML тегов</div>
 
<span data="First">Поиск HTML тегов</span>
<div data="First">Поиск HTML тегов</div>

Также во втором параметре заслуживает внимания спец. значение AttributesPattern. Кратко его можно охарактеризовать как наличие в атрибутах определенной последовательности символов. Например:

Действие Параметр Значение
HTML: Поиск тегов Тип элемента Any Tag
Название проверяемого атрибута AttributesPattern
Значение проверяемого атрибута data
Тип результата / извлекаемый атрибут outerHTML
 
Исходное значение   Результат (массив)
<span big-data="First">Поиск HTML тегов</span>
<span data-class="Second">Поиск HTML тегов</span>
<div notonlydata="First">Поиск HTML тегов</div>
<tr>Поиск HTML тегов</tr>
<span data="Third">Поиск HTML тегов</span>
<li>Поиск HTML тегов</li>
<div>Поиск HTML тегов</div>
 
<span big-data="First">Поиск HTML тегов</span>
<span data-class="Second">Поиск HTML тегов</span>
<div notonlydata="First">Поиск HTML тегов</div>
<span data="Third">Поиск HTML тегов</span>
<li>Поиск HTML тегов</li>

Здесь находятся все теги, где в атрибутах есть сочетание букв data. Можно было бы задать 3 параметр = «First», тогда нашлось бы всё с таким сочетанием букв в атрибутах.

При наличии в проверяемых атрибутах слов на русском языке Действие может не срабатывать. Попробуйте 2 параметр AttributesPattern

Параметр Тип результата / извлекаемый атрибут

Четвертый параметр имеет нестандартный синтаксис: обязательное первое слово (outerHTML, например), к которому может быть дописано необязательное второе слово или число (join, 5, last, например).

Обязательное первое слово может быть зарезервированным (Тип результата) или произвольным (Извлекаемый атрибут). Зарезервированные слова имеют свои функции, вот они:

  • outerHTML — берет тег целиком
Действие Параметр Значение
HTML: Поиск тегов Тип элемента span
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут outerHTML
 
Исходное значение   Результат
<div><span><a href="/parser">Парсер</a></span></div>
 
<span><a href="/parser">Парсер</a></span>
  • innerHTML — берет содержимое тега
Действие Параметр Значение
HTML: Поиск тегов Тип элемента span
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут innerHTML
 
Исходное значение   Результат
<div><span><a href="/parser">Парсер</a></span></div>
 
<a href="/parser">Парсер</a>
  • ConvertToText — преобразует содержимое тега в текст.
Действие Параметр Значение
HTML: Поиск тегов Тип элемента span
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут ConvertToText
 
Исходное значение   Результат
<div><span><a href="/parser">Парсер</a></span></div>
 
Парсер
  • DeleteTags — удаляет тег
Действие Параметр Значение
HTML: Поиск тегов Тип элемента span
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут DeleteTags
 
Исходное значение   Результат
<div><span><a href="/parser">Парсер</a></span></div>
 
<div></div>
  • ReplaceTagWithItsText — заменяет тег на содержащийся в нем текст
Действие Параметр Значение
HTML: Поиск тегов Тип элемента span
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут ReplaceTagWithItsText
 
Исходное значение   Результат
<div><span><a href="/parser">Парсер</a></span></div>
 
<div>Парсер</div>
  • TagHeaderOnly — берет открывающий тег целиком.
Действие Параметр Значение
HTML: Поиск тегов Тип элемента span
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут TagHeaderOnly
 
Исходное значение   Результат
<div><span><a href="/parser">Парсер</a></span></div>
 
<span>

Все остальные слова относятся к произвольным, они возвращают значение искомого атрибута. Помимо вариантов из выпадающего списка (content, href, src, value, data), могут быть вписаны свои варианты. Например:

Действие Параметр Значение
HTML: Поиск тегов Тип элемента span
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут big-source-photo
 
Исходное значение   Результат
<div><span big-source-photo="/1.jpg"><a href="/parser">Парсер</a></span></div>
 
/1.jpg

К произвольному слову может быть дописано выражение «_with_prefix», которое указывает на то, что к результату надо дописать зарезервированную переменную %WebSiteURL%, попросту говоря, домен сайта, который был загружен в этой же настройке одним из первых действий. Есть возможность выбрать в выпадающем списке готовые варианты href_with_prefix, src_with_prefix. 

Действие Параметр Значение
HTML: Поиск тегов Тип элемента a
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут href_with_prefix
 
Исходное значение   Результат
<div><span><a href="/parser">Парсер</a></span></div>
 
http://excelvba.ru/parser

Выражение «_with_prefix» может быть дописано к любому произвольному слову:

Действие Параметр Значение
HTML: Поиск тегов Тип элемента span
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут big-source-photo_with_prefix
 
Исходное значение   Результат
<div><span big-source-photo="/1.jpg"><a href="/parser">Парсер</a></span></div>
 
http://excelvba.ru/1.jpg

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

  • join — объединяет массив результатов в строку с разделителем равным переводу строки. Обратите внимание, в примере получен не массив значений (тогда бы в скобках стояло «Массив»), а строка.
Действие Параметр Значение
HTML: Поиск тегов Тип элемента span
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут ConvertToText join
 
Исходное значение   Результат
<span>Парсер 1</span>
<span>Парсер 2</span>
<span>Парсер 3</span>
<span>Парсер 4</span>
 
Парсер 1
Парсер 2
Парсер 3
Парсер 4
  • last — последний найденный элемент массив
Действие Параметр Значение
HTML: Поиск тегов Тип элемента span
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут ConvertToText last
 
Исходное значение   Результат
<span>Парсер 1</span>
<span>Парсер 2</span>
<span>Парсер 3</span>
<span>Парсер 4</span>
 
Парсер 4
  • last-1 — предпоследний элемент массива, вместо единицы можно указывать любую цифру
Действие Параметр Значение
HTML: Поиск тегов Тип элемента span
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут ConvertToText last-1
 
Исходное значение   Результат
<span>Парсер 1</span>
<span>Парсер 2</span>
<span>Парсер 3</span>
<span>Парсер 4</span>
 
Парсер 3
  • Если просто указывается число, то берется элемент массива с таким порядковым номером
Действие Параметр Значение
HTML: Поиск тегов Тип элемента span
Название проверяемого атрибута  
Значение проверяемого атрибута  
Тип результата / извлекаемый атрибут ConvertToText 2
 
Исходное значение   Результат
<span>Парсер 1</span>
<span>Парсер 2</span>
<span>Парсер 3</span>
<span>Парсер 4</span>
 
Парсер 2

 

Примечания и рекомендации по использованию

  • Если html-код на странице некорректный, например, количество открывающих тегов не равно количеству закрывающих тегов (например, <div> больше, чем </div>), то Действие может работать некорректно. В этом случае  (это встречается ОЧЕНЬ редко, примерно на 1 сайте из 1000) можно воспользоваться одним из действий категории «Неиспользуемые», например «# HTML: Поиск тегов по имени класса» или «# HTML: Поиск заданных тегов». Они используют другой алгоритм работы и способны находить «незакрытые» теги. Однако постоянное их использование нежелательно ввиду того, что они потребляют оперативную память, что может привести к проблемам с функционированием программы (впрочем, встречается это крайне редко).
     
  • Если страница содержит закомментированные куски кода <!— комментарий —>, то Действие может находить в том числе те теги, которые находятся внутри комментариев, и не отображаются на странице. Это может вызвать сложности в определенных случаях. Чтобы этого избежать вы можете использовать предварительно действие HTML: Удаление тегов / комментов. Однако на большинстве сайтов это не требуется.
     
  • Если страница очень большая, а одинаковых тегов много (например, карта сайта sitemap.xml, содержащая 20 тысяч тегов <loc>, из которых нужно взять ссылки на страницы), то скорость работы Действия существенно снижается. Зачастую вместо этого можно воспользоваться текстовой функцией «Взять блоки текста МЕЖДУ …» (особенно, когда речь про XML карту сайта, где теги без атрибутов), — скорость работы существенно возрастет.

HTML Parser — HTML Parser

Парсер HTML

HTML Parser — это библиотека Java, используемая для линейного или вложенного анализа HTML.
В основном используется для преобразования или извлечения, он включает фильтры, посетителей,
настраиваемые теги и простой в использовании JavaBeans. Это быстрый, надежный и хорошо протестированный пакет.

Добро пожаловать на домашнюю страницу HTMLParser — сверхбыстрой в реальном времени
парсер для реального HTML. Что привлекло большинство разработчиков в HTMLParser, так это
простота дизайна, скорость и способность обрабатывать потоковое видео в реальном мире.
html.

Два основных варианта использования, которые обрабатываются парсером:
извлечение и преобразование

(вариант использования синтезов, когда HTML-страницы создаются с нуля, лучше
обрабатывается другими инструментами ближе к источнику данных). Хотя предыдущие версии
сосредоточено на извлечении данных с веб-страниц, версия 1.4
HTMLParser имеет существенные улучшения в области преобразования Интернета.
страниц с упрощенным созданием и редактированием тегов и дословным методом toHtml ()
выход.

В общем, чтобы использовать HTMLParser, вы должны уметь писать код на
язык программирования Java. Хотя некоторые примеры программ предоставляются
которые могут быть полезны в том виде, в каком они стоят, скорее всего, вам понадобится (или
хотите), чтобы создавать свои собственные программы или изменять те, которые предоставлены, в соответствии с вашими
предполагаемое приложение.

Чтобы использовать библиотеку, вам нужно добавить либо htmllexer.jar, либо
htmlparser.jar в путь к классам при компиляции и запуске.В
htmllexer.jar обеспечивает низкоуровневый доступ к общим узлам строки, примечания и тега на
страницу линейным, плоским, последовательным образом. Htmlparser.jar, который
включает классы, найденные в htmllexer.jar, обеспечивает доступ к странице как
последовательность вложенных дифференцированных тегов, содержащих строку, примечание и другие
узлы тегов. Итак, где вывод вызовов лексеру
nextNode ()
метод может быть:

    
    
    <название>

    "Добро пожаловать"
    
    
    
    и т.п...
     

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

    
        
            <название>
                "Добро пожаловать"
                
            
        

            так далее...
     

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

Добыча

Извлечение включает в себя все программы поиска информации, которые не
предназначен для сохранения исходной страницы.Это охватывает такие виды использования, как:

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

В базе кода HTMLParser есть несколько средств, помогающих с
добыча, в том числе
фильтры,
посетителей и
JavaBeans.

Преобразование

Преобразование включает в себя всю обработку, где вход и выход
являются HTML-страницами. Вот несколько примеров:

  • Перезапись URL, изменение некоторых или всех ссылок на странице
  • захват сайта, перемещение содержимого из Интернета на локальный диск
  • цензура, удаление оскорбительных слов и фраз со страниц
  • Очистка HTML, исправление ошибочных страниц
  • Удаление рекламы, удаление URL-адресов, ссылающихся на рекламу
  • Преобразование

  • в XML, перемещение существующих веб-страниц в XML

Во время или после чтения страницы операции на узлах могут
выполнять многие задачи преобразования «на месте», которые затем могут быть выведены
с методом toHtml ().В зависимости от цели вашего приложения вы, вероятно, захотите посмотреть
в декораторы узлов,
посетителей, или
пользовательские теги

в сочетании с
PrototypicalNodeFactory.

.

Что означает анализ HTML?

Переполнение стека

  1. Около
  2. Продукты

  3. Для команд
  1. Переполнение стека
    Общественные вопросы и ответы

  2. Переполнение стека для команд
    Где разработчики и технологи делятся частными знаниями с коллегами

  3. Вакансии
    Программирование и связанные с ним технические возможности карьерного роста

  4. Талант
    Нанимайте технических специалистов и создавайте свой бренд работодателя

  5. Реклама
    Обратитесь к разработчикам и технологам со всего мира

  6. О компании

.Анализ

— Написание парсера HTML

Переполнение стека

  1. Около
  2. Продукты

  3. Для команд
  1. Переполнение стека
    Общественные вопросы и ответы

  2. Переполнение стека для команд
    Где разработчики и технологи делятся частными знаниями с коллегами

  3. Вакансии
    Программирование и связанные с ним технические возможности карьерного роста

  4. Талант
    Нанимайте технических специалистов и создавайте свой бренд работодателя

  5. Реклама
    Обратитесь к разработчикам и технологам со всего мира

  6. О компании

Загрузка…

  1. Авторизоваться
    зарегистрироваться

  2. текущее сообщество

.

Страница не найдена · GitHub Pages

Страница не найдена · GitHub Pages

Файл не найден

Сайт, настроенный по этому адресу, не
содержать запрошенный файл.

Если это ваш сайт, убедитесь, что регистр имени файла соответствует URL-адресу.
Для корневых URL (например, http://example.com/ ) вы должны предоставить
index.html файл.

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

.

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

Ваш адрес email не будет опубликован.