Меню Рубрики

Как сделать парсер маркдовн самому

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

Сам по себе Markdown никак не парсится браузерами и отображается в виде обычного текста, т.к. не является чистым HTML, поэтому для показа Markdown сначала нужно перевести в HTML. Для примера, тот же GitHub автоматически парсит ваш README.md в HTML для более симпатичного отображения. Это очень удобно, т.к. текст приобретает более целостный и однообразный вид.

Для PHP есть огромное количество библиотек для парсинга Markdown. Некоторые из них отличаются итоговым результатом, но в основном между собой они соревнуются в скорости парсинга, т.к. это наиболее важный показатель при переводе Markdown в HTML.

Parsedown — библиотека из одного PHP файла. Наверное, благодаря этому она показала довольно быстрые результаты заняв первое место в бенчмарке. Но за скорость приходится платить. написанная «топроно» эта библиотека состоит всего из одного класса и вообще не поддается какому-либо расширению (наследование никто не отменял, но это не то).

Установить Parsedown можно через composer: «erusev/parsedown»: «dev-master» или просто скачав и подключив единственный файл из GitHub репозитория. Далее все сводится к созданию объекта и вызове единственного метода:

Parsedown не имеет других публичных методов для или каких-либо настроек. Все просто и «топорно».

Если вам нужно больше функционала, можно воспользоваться следующей в списке бенчмарка библиотекой — cebe/markdown

Она немного медленнее предыдущей, но предоставляет куда больше возможностей. Например, оформление Markdown как на GitHub’е, а так же возможность расширения парсера добавлением новых блочных тегов и инлайновых элементов. Так же замечу, что эту библитеку используют разработчики Yii2 для парсинга документации в HTML.

источник

В аську постучал один из читателей этого блога, и заказал универсальный парсер сайтов. Парсер должен был уметь грабить произвольный сайт и выдирать из него всю текстовую информацию. Кроме того, он должен найти все ссылки на сайте и пройти по ним. У парсера должна быть настройка, ограничивающая число страниц, которое он парсит за один раз. Цена была небольшой, но и задание само по себе несложное. Итак, приступим

Выведем форму ввода адреса донора и создадим каркас класса парсера

Парсить будет метод parse. В остальном все просто.

содержит ту самую настройку, для ограничения количества скачанных страниц.

Напишем метод parse. Но перед этим, нам потребуется еще один метод. Он будет получать на вход $url и смотреть, если это локальный относительный адрес (index.php) то добавлять в начало домен, если полный адрес, то запоминать папку в котором происходит парсинг и наконец если это полный адрес другого сайта, то возвращать false, потому как такие ссылки нам не нужны

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

не буду долго вас томить, метод parse прост, как две копейки

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

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

источник

Наконец дошли руки написать обещанный пост про парсер сайтов. Главное условие для нашего парсера, чтобы сайт был открытый и не требовал авторизации (в принципе 98% интернет магазинов).

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

start = textResp.indexOf(‘Код: ‘,end)+5;

end = textResp.indexOf(‘ | ‘,start);

Шаг 2: Кликаем в меню по пункту «Инструменты» затем на «Редактор скриптов», у нас откроется новая вкладка.

Шаг 3: В открытое окно вставляем наш скрипт.

Шаг 4: Запуск скрипта для начала нужно выбрать функцию getcontent. затем нажать кнопку запуска (серая стрелка, станет черной после выбора функции).

После этого в документе мы увидим подобное:

Теперь основные комментарии к коду:

Мы имеем 2 функции getconten и getPageContent , из getconten мы передаем нужные данные и запускаем функцию для getPageContent для парсинга страницы которую мы передали из getconten.

Функция getconten: здесь мы имеем цикл равный количество страниц в данном разделе. За каждый проход цикла мы отправляем ссылку на страницу и кол-во уже обработанных товаров.

Формула 1+10*(j-1) — нужна для того чтобы записи шли дальше,а не перезаписывались в документе, где 10 это количество записей (!внимание! количество записей по умолчанию, для частоты лучше зайти на нужную страницу с другого браузера или с приватной вкладки тогда вы уведите страницу именно так, как видит ее ваш скрипт).

Функция getPageContent: здесь творится основная магия. Я думаю здесь стоит пояснить только основные моменты, более подробнее почитать про каждую из функций можно в гугле если заинтересует.

sheet.getRange(«A1:I5000») — здесь мы выбираем диапазон ячеек, с которыми мы будем работать, рекомендую ставить большой разбег.

отличный парсер, и комментарии интересные

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

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

Объяснения типа «Формула 1+10*(j-1) — нужна для того чтобы записи шли дальше,а не перезаписывались в документе, где 10 это количество записей» нелепы и вредны для новичков, которым нужно изучать теоретические основы, а не магические заклинания.

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

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

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

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

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

К чему тогда этот разбор кода с крайне важными объяснениями типа «Тут просто присваиваем значению в ячейку.»? =) Не надо отвечать на этот вопрос, а то мне станет интересно почему ты пишешь «парсинг» с большой буквы. Ещё раз повторяю: не надо.

полезно, сохраню, на случай, если что)

Ох и не думал, что мой урок с лофтблога перевоплотится на pikabu! Спасибо автору за свой вариант.

А как значение «j» подставить из ячейки?

Спасибо огромное за пост! очень помог. Особенно в заполнении несколько ячеек! Супер!

Можешь поподробней написать про парсинг ссылок товара (ссылки получила, как по ним заходить?) чтобы из внутренней карточки взять инфу и записать в таблицу?

Водная статья о том с чего начать изучение скриптов google.

Сайт: http://G-Apps-Script.COM (учебник по gas на русском)

#gas #google-apps-script #g-apps-script #google-скрипты #google-сценарии

А опции они умеют парсить?

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

Классный парсер, супер. Я раньше оригинал читал Романа Спиридонова, а здесь еще больше пояснений и т. д. Спасибо!

1. как вывести парсинг на карточку товара, чтобы парсить непосредственно с нее, со всем содержимым. Это очень важно, так как в категориях редко бывают какие-то описания?

2. Можно ли сохранять картинки и как?
Буду очень признателен за ответ, Еще раз спасибо.

1 я делал пар но который собирает ссылки на товар. В потом по этому списку бежал другим парсером который парсил описание. Не самый лучший вариант но меня вполне устраиваел. Работал без сбоев.
2 сохранить? Получаешь список ссылок, а потом сохраняешь через любую программу таких программ много.
Есть ещё способ создаёшь просто HTML страницу, там просто вставляешь весь список ссылок, но так чтобы каждый ссылка была в теге. Потом открываешь страницу в браузере и нажимаешь сохранить страницу со всеми файлами. Схема в принципе неплохая поворачивал я её быстро. Минус только если есть изображение с одинаковыми названиями то они будут изменять друг друга.
Правда может реализовать ещё через PHP тогда по скачивание он может изменять название, разрешение и тд но это только если надо понастоящему большой объем информации обработать.

Извиняюсь за ошибки пишу с телефона. Объяснил тоже по детски тупо, но надеюсь понятно и поможет

источник

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

Что же может потребоваться программисту от хорошего парсера маркдауна? Ну конечно же не скорость :). А нужна на самом деле возможность добавлять свои расширения синтаксиса. К сожалению, во всех реализациях парсеров, что я до этого встречал, логика разбора разметки приколочена намертво. Все что остается — ковырять гвоздиком конечный результат и надеяться что конфликтов не случится. Конечно, гарантировать при этом надежный выхлоп невозможно. Можно пойти другим путем — попробовать заслать патч в апстрим. Но тут нет ни каких гарантий, что синтаксис вашего расширения будет нужен кому-то еще кроме вас, и что ваш код будет принят.

Как же быть? К счастью, теперь у нас есть markdown-it!

Чем же markdown-it отличается от других парсеров?

1. Возможность менять правила парсинга. От мнения авторов проекта вы теперь не зависите — делайте свой плагин и будьте счастливы.
2. Строгое следование CommonMark.
3. Поддержка таблиц и перечеркнутого текста, как на гитхабе. В ближайшее время авторы планируют добавить остальные популярные расширения.
4. Всякие бонусные плюшки вроде типографа, правила которого тоже можно дополнять.

Самое забавное, что при всей разухабистой системе плагинов парсер работает очень быстро. Он в 2-3 раза обгоняет референсный парсер, написанный на яваскрипте, а варианту на С по прикидкам должен проигрывать всего раза в два. Видимо сказывается опыт разработчиков. В свое время я уже писал про их порт zlib, показывающий впечатляющую скорость.

Что еще полезного в парсере с практической точки зрения? Полностью отпадает необходимость в использовании встроенного HTML (ведь можно добавить все нужное через плагины). Соответственно, отпадает необходимость в валидаторах для защиты от XSS. Это очень удобно, особенно для браузеров, куда не затащить развесистые серверные пакеты вроде OWASP.

Читайте также:  Сделай сам своими руками ручной инструмент

В общем, результат очень впечатлает, потому что построение конфигурируемого парсера задача сама по себе непростая, даже если не думать о скорости. Ну и практическая польза очевидна.

источник

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

Просмотрев это видео вы узнаете как создать компанию парсинга нужного вам магазина всего за 10 минут. Мастер создания компании и инструменты автоматической настройки помогут справится даже без знаний языков программирования или основ html. Воспроизвести настройку, продемонстрированную на видео, можно на данном сайте.

Напомним, что в Datacol Вы так-же найдете уже готовые парсера:

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

Задаем входные данные. Чаще всего это ссылки на каталог или категории сайта, информацию с которого мы собираем. Заметим, что Datacol начинает обход сайта в поиске нужных данных именно с этих ссылок .

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

Для этого мы будем использовать Xpath выражения. Xpath выражения — это адреса различных частей вебдокумента. Благодаря им Datacol находит нужные ссылки и данные. Для быстрого подбора Xpath выражений мы запускаем Datacol Picker.

Теперь нам нужно определиться по каким ссылкам Datacol должен будет проследовать, чтобы добраться до полной информации о каждом конкретном товаре. Естественно, в первую очередь, это ссылки на товары.

Чтобы подобрать Xpath для сбора всех этих ссылок, просто кликаем по одной из них левой кнопкой мышки. Моментально в блоке Подбор Xpath появляется подобранное Xpath выражение. Оно автоматически сохраняется в список Варианты Xpath. Именно этот список будет использоваться при работе программы. Справа, в блоке ссылки, можно увидеть набор ссылок, которые соберет Datacol используя текущий Xpath.

Хорошо, теперь Datacol знает как найти ссылки на товары. Но так мы соберем товары только с первой страницы каталога. Поэтому нам нужно показать Datacol как переходить на другие страницы выдачи товаров.

Отметим, что ссылки на другие страницы каталога (даже визуально) расположены совершенно иным образом, чем ссылки на товары. Поэтому для них мы подбираем отдельное Xpath выражение. Для этого добавим новый вариант Xpath.

Теперь кликаем на одну из ссылок и Datacol Picker опять же автоматически подбирает нужный Xpath.

Вот так просто, всего в несколько кликов мыши, мы настроили проход Datacol по сайту. Осталось нажать кнопку Сохранить, чтобы подобранные Xpath выражения сохранились в конфигурации нашей новой кампании.

Теперь, когда Datacol знает как добраться до нужных данных, ему необходимо пояснить что именно требуется собирать. Для начала задаем перечень полей данных, которые мы хотим сохранять.

Для поиска полей данных мы также задаем Xpath выражения. Для этого снова запускаем Picker.

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

Обратите внимание, когда Picker открыт в режиме подбора Xpath для поля данных, в нем присутствует блок Поле данных. В этом блоке отображается название поля, которое сейчас настраивается.

Итак, нам нужно подобрать Xpath выражение для сбора наименования товара. Для этого кликаем на наименовании левой кнопкой мышки. В блоке Подбор Xpath сразу же появляется подобранное Xpath выражение, которое автоматически сохраняется в список варианты Xpath. При нажатии кнопки Сохранить или при переходе к настройке следующего поля данных этот список будет автоматически сохранен в конфигурации текущей кампании Datacol. Заметим, что наименование товара автоматически выделяется красной рамкой. Правильноcть подбора Xpath подтверждает исходный Html код найденного блока. Он отображается в поле “Найденные соответствия”.

По аналогии с наименованием товара можно подобрать Xpath выражения для сохранения остальных полей данных.

Для поля фото лучше использовать специальную опцию контекстного меню.

В ряде случаев сохранение изображений имеет свою специфику.

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

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

После завершении работы кампании все выгруженные данные будут сохранены в Excel файл. По умолчанию он генерируется в папке Мои документы.

Название файла соответствует названию новой кампании.

Заметим, что формат сохранения собранной информации можно переопределить. Об этом мы расскажем в последующих видео.

источник

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

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

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

Итак начнём. Для начала давайте выберем «жертву», пусть это будет какая ни будь отдельная рубрика Яндекс.каталога (о том, как разделять спаршенный контент, расскажу в слудующей статье, пока у нас будет одна категория).

Скачиваем рубрику «как есть» прогой Teleport Pro (бесплатная, делает дубликаты сайтов). качаем только контент без сохранения структуры и картинок. Это просто.

Далее выбираем движок. Предлагаю использовать DLE, устанавливаем его на денвер или на хостинг. Заходим в используемую базу, откываем таблицу где храняться все записи (в DLE это таблица dle_post в других движках другие)

В DLE нужно заполнить как минимум четыре поля:
Заголовок:title
Автор:autor
Короткий текст:short_story
Полный текст:full_story

Составляем заготовку slq запроса (для тех, кто не вкурсе — это написанная на языке sql инструкция, которую можно скопировать во вкладку slq в phpmyadmin и она что то там сделает с базой. При помощи sql запросов можно работать с базой напрямую, без всяких навороченых админок с визуальными редакторами)

Где вы её найдёте, думайте сами. Но в демоверсии ограничение максимум на 100 обработанных файлов.

Открываем, сразу запускаем мастер фильтров

Выбираем самый верхний фильтр «Поиск и замена по схеме».

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

Открываем наш яндекс каталог в виде html и копируем кусок html кода который содержит заголовок и описание (собсно то. что нам и нужно)

Теперь нужную нам текстовую информацию заменяем вот таким образом

(.*?) — на языке регулярных выражений означает вытащить максимальное количество символов после того, что слева от скобки до того что справа от закрывающей скобки. Проще говоря — то что надо. Обратите внимание на слэши перед «нормальными» скобками, их нужно экранировать обязательно иначе прога решит, что это инструкции для неё.

Скидываем это всё в поле «найти схему», предварительно в выпадающем списке выбрав тип поиска — Схема perl, а внизу поставить галку «Извлечь соответсвия»

В поле замена на пишем наш sql запрос

Цифры $1 и $2 означают, что в это место будет вставляться содержимое первого «(.*?)» и второго «(.*?)» соответсвенно. Как видим полное и краткое описание у меня будет одинаковым.

у вас должно быть что то типа такого:

На вкладке «Зона учебного прогона», в левое поле копируем поностью html код страницы каталога-донора (откуда выдрали кусок с вхождением названия и описания сайта). Жмём «Тестовый прогон», если получилось что то типа этого, значит всё ок.

Возвращаемся на первую вкладку, Файл вывода ставим «выводить в один файл».

На вкладке «файлов в обработке», указываем папку куда скачали сайт через teleport pro. Запускаем!

Если всё ок, то в указанной нами файле будет сохранён дамп со всеми найденными соответствиями схеме. Теперь просто импортируем через phpmyadmin (вкладка импорт) этот файл в базу. Готово!

Миниатюры

источник

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

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

Работать мы будем с CURL, но для начала давайте разберёмся, что эта аббревиатура обозначает. CURL – это программа командной строки, позволяющая нам общаться с серверами используя для этого различные протоколы, в нашем случаи HTTP и HTTPS. Для работы с CURL в PHP есть библиотека libcurl, функции которой мы и будем использовать для отправки запросов и получения ответов от сервера.

Двигаемся дальше и определяемся с нашей целью. Для примера я выбрал наверняка всем известный магазин svyaznoy . Для того, чтобы спарсить категории этого магазина, предлагаю перейти на страницу каталога:

Как можно увидеть из скриншота все категории находятся в ненумерованном списке, а подкатегории:

Внутри отельного элемента списка в таком же ненумерованном. Структура несложная, осталось только её получить. Товары мы возьмем из раздела «Все телефоны»:

На странице получается 24 товара, у каждого мы вытянем: картинку, название, ссылку на товар, характеристики и цену.

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

  1. Нужно получить HTML код страницы, которой нам необходим;
  2. Разбор полученного кода с сохранением данных и дальнейшей обработки их (как и в первой статье по парсингу мы будем использовать phpQuery, в ней же вы найдете, как установить её через composer).

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

Основной метод, который у нас будет – это getPage() и у него всего один обязательный параметр URL страницы, которой мы будем парсить. Что ещё будет уметь наш замечательный метод, и какие значения мы будем обрабатывать в нем:

  • $useragent – нам важно иметь возможность устанавливать заголовок User-Agent, так мы сможем сделать наши обращения к серверу похожими на обращения из браузера;
  • $timeout – будет отвечать за время выполнения запроса на сервер;
  • $connecttimeout – так же важно указывать время ожидания соединения;
  • $head – если нам потребуется проверить только заголовки, которые отдаёт сервер на наш запрос этот параметр нам просто будет необходим;
  • $cookie_file – тут всё просто: файл, в который будут записывать куки нашего донора контента и при обращении передаваться;
  • $cookie_session – иногда может быть необходимо, запрещать передачу сессионных кук;
  • $proxy_ip – параметр говорящий, IP прокси-сервера, мы сегодня спарсим пару страниц, но если необходимо несколько тысяч, то без проксей никак;
  • $proxy_port – соответственно порт прокси-сервера;
  • $proxy_type – тип прокси CURLPROXY_HTTP, CURLPROXY_SOCKS4, CURLPROXY_SOCKS5, CURLPROXY_SOCKS4A или CURLPROXY_SOCKS5_HOSTNAME;
  • $headers – выше мы указали параметр, отвечающий за заголовок User-Agent, но иногда нужно передать помимо его и другие, для это нам потребуется массив заголовков;
  • $post – для отправки POST запроса.
Читайте также:  Комбинезоны для йорка сделай сам

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

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

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

Для работы с CURL нам необходимо вначале инициализировать сеанс, а по завершению работы его закрыть, также при работе важно учесть возможные ошибки, которые наверняка появятся, а при успешном получении ответа вернуть результат, сделаем мы это таким образам:

Первое, что вы могли заметить – это статическое свойство $error_codes, к которому мы обращаемся, но при этом его ещё не описали. Это массив с расшифровкой кодов функции curl_errno(), давайте его добавим, а потом разберем, что происходит выше.

После того, как мы инициализировали соединения через функцию curl_setopt(), установим несколько параметров для текущего сеанса:

  • CURLOPT_URL – первый и обязательный — это адрес, на который мы обращаемся;
  • CURLINFO_HEADER_OUT –массив с информацией о текущем соединении.

Используя функцию curl_exec(), мы осуществляем непосредственно запрос при помощи CURL, а результат сохраняем в переменную $content, по умолчанию после успешной отработки результат отобразиться на экране, а в $content упадет true. Отследить попутную информацию при запросе нам поможет функция curl_getinfo(). Также важно, если произойдет ошибка — результат общения будет false, поэтому, ниже по коду мы используем строгое равенство с учетом типов. Осталось рассмотреть ещё две функции это curl_error() – вернёт сообщение об ошибке, и curl_errno() – код ошибки. Результатом работы метода getPage() будет массив, а чтобы его увидеть давайте им воспользуемся, а для теста сделаем запрос на сервис httpbin для получения своего IP.

Кстати очень удобный сервис, позволяющий отладить обращения к серверу. Так как, например, для того что бы узнать свой IP или заголовки отправляемые через CURL, нам бы пришлось бы писать костыль.

Если вывести на экран, то у вас должна быть похожая картина:

Если произойдет ошибка, то результат будет выглядеть так:

При успешном запросе мы получаем заполненную ячейку массива data с контентом и информацией о запросе, при ошибке заполняется ячейка error. Из первого скриншота вы могли заметить первую неприятность, о которой я выше писал контент сохранился не в переменную, а отрисовался на странице. Чтобы решить это, нам нужно добавить ещё один параметр сеанса CURLOPT_RETURNTRANSFER.

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

Теперь можно увидеть более приятную картину:

Двигаемся далее, мы описали переменные $useragent, $timeout и $connecttimeout. Добавляем их в наш скрипт:

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

Мы отключили вывод тела документа и включили вывод шапки в результате:

Для работы со ссылками с SSL сертификатом, добавляем:

Уже получается весьма неплохой скрипт парсера контента, мы добрались до кук и тут стоит отметить — частая проблема, когда они не сохраняются. Одной из основных причин может быть указание относительного пути, поэтому нам стоит это учесть и написать следующие строки:

Предлагаю проверить, а для этого я попробую вытянуть куки со своего сайта:

Всё получилось, двигаемся дальше и нам осталось добавить в параметры сеанса: прокси, заголовки и возможность отправки запросов POST:

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

Теперь, при помощи нашего класса Parser, мы можем сделать запрос и получить страницу с контентом. Давайте и поступим:

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

Чуть более подробно работу с phpQuery я разобрал в первой статье по парсингу контента. Если вкратце, то мы пробегаемся по DOM дереву и вытягиваем нужные нам данные, их я решил протримить, чтобы убрать лишние пробелы. А теперь выведем категории на экран:

В результате мы получили все ссылки на категории. Для получения товаров используем тот же принцип:

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

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

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

Полный пример с библеотекай phpQuery вы найдете на github .

источник

Разделим парсинг (скраппинг) сайтов на две подзадачи.

  1. Собственно сам парсинг – поиск данных, которые нам интересны на страницах.
  2. Осмысливание полученных данных.

Вначале опишем приложения:

  1. Парсер «постоянной» информации о товарах с сайта. Этот парсер будет запускаться редко (исключительно для проверки наличия новых товаров), будет разбирать страницы и извлекать из них информацию о товаре: наименование, фотографии, свойства.
  2. Парсер условно переменной информации. Это приложение будет запускаться часто и автоматически, будет разбирать страницы сайта для поиска цен и наличия на складе для обновления этой информации в БД (мы его рассматривать не будем, тут нет ничего необычного).
  3. Админка, структурирование полученных данных. Это приложения будет запускаться после парсера «постоянной» информации и позволяет админу разобрать/структурировать полученные данные.

Методов парсинга много, это и регулярные выражения и банальный поиск подстроки. Все эти способы имеют один большой недостаток – при небольших изменениях на сайте необходимо править сам парсер.
Для себя лично (пишу под .net на c#) остановился на библиотеке HtmlAgilityPack, описание например на Хабре.
Что она дает – она читает HTML (даже многие не валидные документы) и строит DOM дерево. А дальше вступает в дело вся мощь XPATH запросов. При правильно написанных XPATH запросах нет необходимости править парсер при изменениях на сайте.

Пример:
Для ориентации в DOM часто используются классы, но еще чаще минорные изменения в дизайне сайта выполняются добавлением соответствующих классов к элементам (было >
вместо

Да, это может сказаться на производительности, но не сильно. Универсальность кода – важнее.

Точно также при ориентации в дереве при помощи id элементов я, как правило, использую «//» (т.е. поиск по всему поддереву), вместо «/» (поиск только среди дочерних элементов). Это спасает в ситуациях, когда дизайнер обертывает какие-либо тэги (как правило, для фикса какого-нибудь бага отображения):

Парсить нам нужно основную информацию о товарах: наименование, фотография и, самое главное, список свойств. Полученные данные мы будем хранить в БД с примитивной структурой:

Т.е. для каждого товара будет список пар значений: название свойства (propertyName) и ее значение (propertyValue).
Допустим мы написали парсер, разобрали все данные с сайта и хотим теперь создать БД и сайт для поиска товаров по параметрам. Для этого нам нужно структурировать данные.

Создадим еще пару таблиц в БД для хранения структурированных данных.

Dict_Property – справочник свойств (цвет, размер, вес и т.д., т.е. все свойства по которым мы потом будем искать)
Product_Property – значения этих свойств у конкретного товара.

Маленькая «хитрость» — поле FloatValue – для числовых свойств, формируется при помощи попытки конвертации поля Value во float:

Оно будет нужно для поиска (например: поле «вес», запрос от 100 до 300 грамм, поиск по текстовому полю «Value» будет медленный и не правильный, а по floatValue – быстрый и корректный).

Теперь все готово для того чтобы начать структурировать данные.

Практика показала, что даже самые плохо оформленные Китайские магазины стараются унифицировать описания товаров.
Пример: сайт dx.com, распарсено 1267 товаров. Всего у них 49398 свойств. Если сгруппируем по названию получим всего 580 значений, что в принципе не много.

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

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

  • Первые 100 строк таблицы (наиболее встречаемые значения свойств) покрывают порядка 35-40% всех значений свойств.
  • Очень много свойств и значений, отличающихся друг от друга только регистром или/и пробелами/опечатками.
  • Цифровые данные – как правило в одном формате – например вес, габариты, объем оперативной памяти.

Для структурирования данных напишем приложение для создания «правил парсинга». Введем 2 типа правил:

  • Точное совпадение. Например: свойство «Color», значение «Black»
  • Совпадение по регулярному выражению. Например: свойство Weight, значение
    (?\d*\.?\d+)g

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

источник

В этой статье даются практические советы по написанию парсера для языка разметки Markdown. На сегодняшний день информации в интернете по этому вопросу крайне мало.

Статья будет полезна тем, кто занимается созданием собственных CMS и фреймворков с нуля.

Разработчики Маркдауна ставили своей целью создать язык, код которого будет визуально схож с результатом его выполнения. За основу были взяты принятые правила оформления e-mail сообщений.

Нумерованные списки:
1. Первый пункт
2. Второй пункт
3. Третий пункт

> Комментарий
> > Комментарий в комментарии

Можно **выделять часть** текста.

Такой код будет преобразован в правильный xHTML.

Синтаксис Маркдауна является с одной стороны более легким в освоении для технически неквалифицированных пользователей(в отличие, например, от BB кодов), а, с другой стороны, производит качественный выходной xHTML код, чего не скажешь о различных WYSIWYG редакторах. Эти преимущества делают Маркдаун хорошим выбором для форумных движков и CMS, где требуется возможность редактирования контента пользователями.

Читайте также:  Как самому сделать складную лавку

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

Маркдаун нельзя разобрать контекстно-свободными грамматиками. Он содержит контекстно-зависимые лексические элементы. Например, вложенность конструкций определяется выравниванием строк как в Пайтоне. Так что воспользоваться в явном виде YACCом и ANTLRом не получится. Среди решений этой проблемы я встречал следующие:

    Отказаться от использования генератора парсеров и написать парсер в ручную, используя местами регулярные выражения.

Именно так был создан оригинальный парсер Маркдауна на Перле и большинство других реализаций. Недостаток решения в низкой производительности: во-первых, из-за использования регулярных выражений, во-вторых, потому что оптимизировать парсер в ручную до уровня, который обеспечивает автоматически сгенерированный, как правило очень сложная задача. Кроме того, если вы пишете на императивных языках(PHP, Java, C++), то реализовать и отлаживать самописный парсер будет очень трудно.

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

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

Рекурсивное применение парсера контекстно-свободной грамматики.

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

Возможно, это будет самым простым в реализации решением.

Предварительно в ручную обработать входные данные.

Можно в ручную разбить код на строки, и циклом пройтись по ним, заменяя пробелы в начале каждой строки на символ указывающий ее сдвиг(влево или вправо) относительно предыдущей. Точно также можно обработать вложенность комментариев. Затем полученный массив строк можно склеить обратно, и уже разбирать его контекстно-свободной грамматикой. Полученный после фильтрации язык будет контекстно-свободным.

Это решение по сложности сопоставимо с предыдущим. По производительности должно в общем случае быть более эффективным.

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

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

источник

На данный вопрос уже ответили:

Пытаюсь завернуть слово, как это делается в Markdown, но не получается до конца. При использовании такой конструкции: str.value.replace(/(^|\b|\s)#(.*?)#(\b|\s)/gm, «

Символы, которые обычно рассматриваются в Markdown как специальные, могут быть экранированы с помощью обратного слеша. Например, последовательность «\*» выведет символ «*», а не будет являться признаком начала выделенного текста.

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

PS. Просьба не кидать линки для громоздкие Markdown-библиотеки. Интересно знать самому.

Отмечен как дубликат участниками Visman, Vladimir Glinskikh, Nick Volynkin ♦ , tutankhamun, aleksandr barakin 13 сен ’15 в 8:18 .

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

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

«Правильно» — это анализ документа, построение дерева встречающихся в документе боков и преобразование этого дерева в новый текстовый документ. Сначала необходимо разбить документ на отдельные токены (в случае > *text* получится четыре токена — символ цитаты > , символ начала выделенного текста * , произвольный текстовый токен text и еще один * ), после чего нужно проанализировать эти токены и объединить их в дерево, состоящее из блоков (в том же примере получится дерево из одной ветви: цитата — выделенние — произвольный текст), и, наконец, по полученному дереву построить готовый документ (с html это очень просто, потому что необходимо просто идти по дереву и открывать и закрывать теги при начале и конце узла).

Существуют автоматические генераторы парсеров для регулярных языков (bison, yacc — правда, они совсем не для яваскрипта), но здесь, боюсь, я уже ничего не подскажу.

источник

Для меня всегда было некоей магией то, как Getpocket, Readability и Вконтакте парсят ссылки на страницы и предлагают готовые статьи к просмотру без рекламы, сайдбаров и меню. При этом они практически никогда не ошибаются. А недавно подобная задача назрела и в нашем проекте, и я решил копнуть поглубже. Сразу скажу, что это «белый» парсинг, вебмастеры сами добровольно пользуются нашим сервисом.

В идеальном мире вся информация на страницах должна быть семантически размечена. Умные люди придумали много полезных штук типа Microdata, OpenGraph, тэги Article, Nav …etc, но полагаться на сознательность вебмастеров в плане семантики я бы не спешил. Достаточно самим посмотреть код страниц популярных сайтов. Open Graph кстати самый востребованный формат, всем хочется красиво выглядеть в соц. сетях

Вычленение заголовка статьи и картинки остается за рамками моего поста, так как заголовок обычно берется из title или og, а картинка если она не берется из og:image – это отдельный рассказ.

Переходим к самому интересному – вычленению тела статьи.
Оказывается, есть вполне себе научные paper’ы посвященные этой проблеме (в том числе от сотрудников Гугла). Есть даже соревнование CleanEval с набором тестовых страниц из которых надо извлечь данные, и алгоритмы соревнуются в том кто сделает это точнее.

Выделяются следующие подходы:

  • Извлечение данных пользуясь только html документом (DOM и текстовый уровень). Именно эту технику мы обсудим ниже
  • Извлечение данных используя отрендеренный документ с помощью computer vision. Это очень точный алгоритм, но и самый сложный и прожорливый. Посмотреть как работает можно например вот здесь: www.diffbot.com (проект ребят из Стэнфорда).
  • Извлечение данных на уровне сайта целиком, сравнивая однотипные страницы и находя различия между ними (различающиеся блоки это по сути и есть нужный контент). Этим занимаются большие поисковики.

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

Берем все элементы разметки структуры страницы (для простоты — div) и текст который в них содержится (если он есть). Наша задача получить плоский список DIV элемент –> текст в нем

Например блок меню на Хабре:

Дает нам элемент содержащий текст «посты q&a события хабы компании»

При наличии вложенных div элементов, их содержание отбрасывается. Дочерние div будут обработаны в свою очередь. Пример:

Мы получим два элемента, в одном текст ©habrahabr.ru, а во втором Служба поддержки Мобильная версия

Мы предполагаем что в 21 веке элементы которые семантически предназначены для разметки структуры (div), не используют для разметки параграфов в тексте, и это на топ 100 новостных сайтов действительно так.

В итоге из дерева у нас получается плоский набор:

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

DOM дерево мы не выкидываем, оно нам понадобится в алгоритмах.

Во всех элементах DOM дерева мы находим элементы с повторяющимися паттернами в атрибутах (class, id..). Например если приглядится к комментариям:

Становится понятно, что такое повторяющийся паттерн:

  • Одинаковый набор классов у элементов
  • Одинаковая текстовая подстрока в id

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

Идея понятна – в меню и в колонках мы видим сплошные ссылки, что явно не похоже на статью. Пробегаемся по элементам из нашего набора и каждому проставляем коффициент.
Например, текст в элементах в блоке Фрилансим (он у нас уже получили минус за повторяющийся класс), получают минус в догонку за некрасивое соотношение ссылок к тексту равное единице. Понятно, что чем меньше этот коэффициент, тем больше текст похож на осмысленную статью:

Чем больше в блоке всякой разметки (списки, переносы, span. ), тем меньше шанс, что это статья. Например, реклама вероятно уважаемой SEO компании, не очень похожа на статью, так как целиком представляет собой список. Чем ниже значение соотношения разметки к тексту тем лучше.

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

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

Много блоков с текстом примерно одной длины это плохой признак, особенно если текст короткий. Мы такие блоки пессимизируем. Идея хорошо сработает на подобной верстке:

В примере не Хабр, так как данный алгоритм лучше работает на более строгих сетках. На комментариях на Хабре сработает к примеру не очень хорошо.

Здесь прямая зависимость – чем длиннее текст в элементе, тем больше шансов на то, что это статья.

Причем вклад этого параметра в итоговую оценку элемента очень существенен. 90% случаев парсинга статьи можно решить одним этим методом. Все предыдущие изыскания поднимут этот шанс до 95%, но при этом скушают львиную долю процессорного времени.

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

Или еще один случай — увесистое выпадающее меню сделанное с применением

Готовые алгоритмы для вашего языка можно найти по запросам «boilerplate algorithm», «readability algorithm»

источник