{
    "version": "https:\/\/jsonfeed.org\/version\/1",
    "title": "Блог об аналитике, визуализации данных, data science и BI, заметки с тегом: selenium",
    "home_page_url": "http:\/\/test.leftjoin.ru\/tags\/selenium\/",
    "feed_url": "http:\/\/test.leftjoin.ru\/tags\/selenium\/json\/",
    "icon": "http:\/\/test.leftjoin.ru\/user\/userpic@2x.jpg",
    "author": {
        "name": "Николай Валиотти",
        "url": "http:\/\/test.leftjoin.ru\/",
        "avatar": "http:\/\/test.leftjoin.ru\/user\/userpic@2x.jpg"
    },
    "items": [
        {
            "id": "92",
            "url": "http:\/\/test.leftjoin.ru\/all\/instagram-python-selenium-bot\/",
            "title": "Робот для автоматизированного просмотра Instagram на Python и Selenium",
            "content_html": "<p class=\"note\">Недавно мы начали вести Instagram — <a href=\"https:\/\/www.instagram.com\/leftjoin.ru\/\">подписывайтесь<\/a>, чтобы не пропустить контент, которого нет в блоге и Telegram!<\/p>\n<p>Многие из нас ежедневно заходят в Instagram, чтобы посмотреть истории друзей и полистать ленту постов и рекомендаций. Предлагаем действенный способ сохранить своё время — напишем на Python и Selenium робота, который возьмёт на себя рутинную задачу проверки свежих новостей друзей и подсчитает число новых историй и входящих сообщений.<\/p>\n<h2>Авторизация в аккаунт<\/h2>\n<p>При переходе в браузерную версию сайта, нас встречает такое окно:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/1-22.png\" width=\"827\" height=\"619\" alt=\"\" \/>\n<\/div>\n<p>Но просто вставить логин, пароль и нажать на кнопку «Войти» недостаточно: впереди будет ещё два окна. Во-первых, предложение сохранить данные — здесь мы тактично жмём «Не сейчас». Instagram тщательно следит за каждым нашим действием и малейшие аномалии в поведении приводят к блокировке, поэтому любые предложения по сохранению данных будем на всякий случай пропускать.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/2-21.png\" width=\"414\" height=\"344\" alt=\"\" \/>\n<\/div>\n<p>Следующим препятствием будет предложение включить уведомление, которое мы тоже пропустим:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/3-19.png\" width=\"449\" height=\"381\" alt=\"\" \/>\n<\/div>\n<p>Первым делом импортируем библиотеки:<\/p>\n<pre class=\"e2-text-code\"><code>from selenium import webdriver\r\nfrom webdriver_manager.chrome import ChromeDriverManager\r\nfrom bs4 import BeautifulSoup as bs\r\nimport time\r\nimport random<\/code><\/pre><p>И описываем функцию authorize — она будет принимать driver в качестве аргумента, отправлять в нужные поля логин и пароль, нажимать на кнопку «Войти», затем ждать десять секунд на загрузку страницы, нажимать на кнопку «Не сейчас», снова ждать загрузки страницы и пропускать уведомления:<\/p>\n<pre class=\"e2-text-code\"><code>def authorize(driver):\r\n    username = 'login'\r\n    password = 'password'\r\n    driver.get('https:\/\/www.instagram.com')\r\n    time.sleep(5)\r\n    driver.find_element_by_name(&quot;username&quot;).send_keys(username)\r\n    driver.find_element_by_name(&quot;password&quot;).send_keys(password)\r\n    driver.execute_script(&quot;document.getElementsByClassName('sqdOP  L3NKy   y3zKF     ')[0].click()&quot;)\r\n    time.sleep(10)\r\n    driver.execute_script(&quot;document.getElementsByClassName('sqdOP  L3NKy   y3zKF     ')[0].click()&quot;)\r\n    time.sleep(10)\r\n    driver.execute_script(&quot;document.getElementsByClassName('aOOlW   HoLwm ')[0].click()&quot;)<\/code><\/pre><h2>Новые сообщения<\/h2>\n<p>В Instagram могут прийти сообщения двух видов. В случае, если вы не подписаны на отправителя — придёт запрос на диалог. Если подписаны — придёт входящее сообщения. Оба случая обрабатываются по-разному. Число входящих сообщений можно получить с главной страницы — это число над иконкой бумажного самолётика:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/--2021-01-25--15.19.31.png\" width=\"231\" height=\"70\" alt=\"\" \/>\n<\/div>\n<p>А число запросов можно забрать текстом заголовка h5 из раздела «Сообщения». Сперва перейдём в этот раздел и попробуем найти строку с запросами на сообщение. Затем вернёмся на главную страницу и возьмём то самое число новых сообщений.<\/p>\n<pre class=\"e2-text-code\"><code>def messages_count(driver):\r\n    driver.get('https:\/\/www.instagram.com\/direct\/inbox\/')\r\n    time.sleep(2)\r\n    inbox = bs(driver.page_source)\r\n    try:\r\n        queries_text = inbox.find_all('h5')[0].text\r\n    except Exception:\r\n        queries_text = None\r\n    driver.get('https:\/\/www.instagram.com')\r\n    time.sleep(2)\r\n    content = bs(driver.page_source)\r\n    try:\r\n        messages_count = int(content.find_all('div', attrs={'class':'KdEwV'})[0].text)\r\n    except Exception:\r\n        messages_count = 0\r\n    return queries_text, messages_count<\/code><\/pre><h2>Подсчёт числа новых сторис<\/h2>\n<p>Все истории хранятся в одном блоке:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/--2021-01-25--15.02.05.png\" width=\"637\" height=\"201\" alt=\"\" \/>\n<\/div>\n<p>Это список с одинаковым классом, но в каждом элементе списка лежит ещё один div-блок. У новых историй это класс eebAO  h_uhZ, у просмотренных — eebAO.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/--2021-01-25--15.03.48.png\" width=\"200\" height=\"132\" alt=\"\" \/>\n<\/div>\n<p>Ещё есть такая кнопка, которая показывает следующую пачку историй:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/--2021-01-25--15.05.14.png\" width=\"269\" height=\"135\" alt=\"\" \/>\n<\/div>\n<p>При этом Instagram динамически прогружает код страницы, и в нём не найти те элементы, которые вы не видите своими глазами. Поэтому мы возьмём первые 8 видимых новых историй, добавим в список, нажмём на кнопку «Показать следующие истории» и будем продолжать так, пока кнопка ещё отображается. А затем подсчитаем число уникальных элементов, чтобы избежать возможных дубликатов.<\/p>\n<pre class=\"e2-text-code\"><code>def get_stories_count(driver):\r\n    stories_divs = []\r\n    scroll = True\r\n    while scroll:\r\n        try:\r\n            content = bs(driver.page_source)\r\n            stories_divs.extend(content.find_all('div', attrs={'class':'eebAO h_uhZ'}))\r\n            driver.execute_script(&quot;document.getElementsByClassName('  _6CZji oevZr  ')[0].click()&quot;)\r\n            time.sleep(1)\r\n        except Exception as E:\r\n            scroll = False\r\n    return len(set(stories_divs))<\/code><\/pre><h2>Просмотр сторис<\/h2>\n<p>Следующее, чем может заняться реальный пользователь после авторизации — просмотр свежих историй. Для того, чтобы зайти в блок историй, нужно просто нажать на кнопку класса OE3OK:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/4-12.png\" width=\"285\" height=\"164\" alt=\"\" \/>\n<\/div>\n<p>Есть еще две кнопки, о которых мы должны знать. Это кнопка для переключения на следующую историю — она в классе FhutL и кнопка закрытия блока историй — класс wpO6b. Пускай одна история будет отнимать у нас от 10 до 15 секунд, и с вероятностью 1\/5 мы переключим на следующую. При этом зададим переменные counter и limit — пусть сейчас мы хотим посмотреть случайное число историй от 5 до 45, и если мы уже посмотрели столько, то выходим из функции и историй.<\/p>\n<pre class=\"e2-text-code\"><code>def watch_stories(driver):\r\n    watching = True\r\n    counter = 0\r\n    limit = random.randint(5, 45)\r\n    driver.execute_script(&quot;document.getElementsByClassName('OE3OK ')[0].click()&quot;)\r\n    try:\r\n        while watching:\r\n            time.sleep(random.randint(10, 15))\r\n            if random.randint(1, 5) == 5:\r\n                driver.execute_script(&quot;document.getElementsByClassName('FhutL')[0].click()&quot;)\r\n            counter += 1\r\n            if counter &gt; limit:\r\n                driver.execute_script(&quot;document.getElementsByClassName('wpO6b ')[1].click()&quot;)\r\n                watching = False\r\n    except Exception as E:\r\n        print(E)\r\n        watching = False<\/code><\/pre><h2>Скроллинг ленты<\/h2>\n<p>После просмотра актуальных историй можно поскроллить ленту — это действие ничем не отличается от классического скроллинга страниц в Selenium. Запоминаем последнюю доступную длину страницы, скроллим до неё, ожидаем прогрузки, получаем новую. Прекратим просматривать ленту в двух случаях — если в random.randint() сгенерировалась единица или если лента кончилась.<\/p>\n<pre class=\"e2-text-code\"><code>def scroll_feed(driver):\r\n    scrolling = True\r\n    last_height = driver.execute_script(&quot;return document.body.scrollHeight&quot;)\r\n    while scrolling:\r\n        driver.execute_script(&quot;window.scrollTo(0, document.body.scrollHeight);&quot;)\r\n        time.sleep(random.randint(4,10))\r\n        new_height = driver.execute_script(&quot;return document.body.scrollHeight&quot;)\r\n        if new_height == last_height or random.randint(1, 10) == 1:\r\n            scrolling = False\r\n        last_height = new_height<\/code><\/pre><h2>Просмотр рекомендуемых аккаунтов<\/h2>\n<p>Instagram в заглавной странице сам рекомендует нам для подписки некоторые аккаунты. Выглядит она так:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/5-12.png\" width=\"645\" height=\"573\" alt=\"\" \/>\n<\/div>\n<p>И на ней тоже придётся скроллить, чтобы дойти до конца. Заходим на страницу и ожидаем 5 секунд прогрузки, затем снова получаем длину страницы и скроллим вниз. Выходим тоже с вероятностью 1\/10 или если страница кончилась, но ещё с вероятностью 1\/2 подписываемся на некоторые из первых 100 аккаунтов рекомендаций:<\/p>\n<pre class=\"e2-text-code\"><code>def scroll_recomendations(driver):\r\n   driver.get('https:\/\/www.instagram.com\/explore\/people\/suggested\/')\r\n    time.sleep(5)\r\n    scrolling = True\r\n    last_height = driver.execute_script(&quot;return document.body.scrollHeight&quot;)\r\n    while scrolling:\r\n        driver.execute_script(&quot;window.scrollTo(0, document.body.scrollHeight);&quot;)\r\n        time.sleep(random.randint(4,10))\r\n        new_height = driver.execute_script(&quot;return document.body.scrollHeight&quot;)\r\n        if new_height == last_height or random.randint(1, 10) == 1:\r\n            scrolling = False\r\n        last_height = new_height\r\n        if random.randint(0, 1):\r\n            try:\r\n                driver.execute_script(f&quot;document.getElementsByClassName('sqdOP  L3NKy   y3zKF     ')[{random.randint(1,100)}].click()&quot;)\r\n            except Exception as E:\r\n                print(E)<\/code><\/pre><h2>Просмотр рекомендуемых постов<\/h2>\n<p>Помимо ленты, которая сформирована из наших подписок, Instagram собирает ленту рекомендаций. Туда входят все посты, которые потенциально могут вам понравиться — мы просто пройдём вниз по этой ленте. Выйдем с вероятностью 1\/5 или когда кончится, чтобы долго не засиживаться.<\/p>\n<pre class=\"e2-text-code\"><code>def scroll_explore(driver):\r\n    driver.get('https:\/\/www.instagram.com\/explore')\r\n    time.sleep(3)\r\n    scrolling = True\r\n    last_height = driver.execute_script(&quot;return document.body.scrollHeight&quot;)\r\n    while scrolling:\r\n        driver.execute_script(&quot;window.scrollTo(0, document.body.scrollHeight);&quot;)\r\n        time.sleep(random.randint(4,10))\r\n        new_height = driver.execute_script(&quot;return document.body.scrollHeight&quot;)\r\n        if new_height == last_height or random.randint(1, 5) == 1:\r\n            scrolling = False\r\n        last_height = new_height<\/code><\/pre><h2>Итог<\/h2>\n<p>Теперь можно собрать все функции вместе — создаём новый driver, проводим авторизацию, считаем число новых сторис и сообщений, просматриваем сторис, переходим в рекомендуемые подписки и листаем ленту. В конце печатаем полученные данные — число новых сообщений, запросов и историй друзей.<\/p>\n<pre class=\"e2-text-code\"><code>driver = webdriver.Chrome(ChromeDriverManager().install())\r\nauthorize(driver)\r\nqueries_text, messages_count = messages_count(driver)\r\nstories_count = get_stories_count(driver)\r\nwatch_stories(driver)\r\nscroll_recomendations(driver)\r\nscroll_feed(driver)\r\nscroll_explore(driver)\r\n\r\nif queries_text is not None:\r\n    print(queries_text)\r\nelse:\r\n    print('Нет новых запросов на диалог')\r\nprint('Новых сообщений:', messages_count)\r\n\r\nprint('Новых историй:', stories_count)<\/code><\/pre>",
            "date_published": "2021-01-25T16:49:42+03:00",
            "date_modified": "2021-01-25T16:34:11+03:00",
            "image": "http:\/\/test.leftjoin.ru\/pictures\/6-12.png",
            "_date_published_rfc2822": "Mon, 25 Jan 2021 16:49:42 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "92",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": [
                    "http:\/\/test.leftjoin.ru\/pictures\/6-12.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/7-7.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/8-8.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/--2021-01-25--15.19.08.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/1-22.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/2-21.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/3-19.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/--2021-01-25--15.19.31.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/--2021-01-25--15.02.05.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/--2021-01-25--15.03.48.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/--2021-01-25--15.05.14.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/4-12.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/5-12.png"
                ]
            }
        },
        {
            "id": "50",
            "url": "http:\/\/test.leftjoin.ru\/all\/selenium-proxy\/",
            "title": "Пишем парсер свежих прокси на Python для Selenium",
            "content_html": "<p>Случается такое, что во время парсинга страниц через Selenium можно словить бан по IP-адресу. Чтобы этого избежать, лучше использовать прокси. Сегодня напишем скрипт, который сам спарсит новые прокси, проверит их и в случае успеха передаст в Selenium.<\/p>\n<h2>Парсинг новых прокси<\/h2>\n<p>Начнём с импортирования библиотек — нам понадобятся модули для отправления запросов, для парсинга и хранения данных.<\/p>\n<pre class=\"e2-text-code\"><code>import requests_html\r\nfrom bs4 import BeautifulSoup\r\nimport pickle\r\nimport requests<\/code><\/pre><p>Все прокси будем хранить в множестве <span class=\"inline-code\">px_list<\/span>, а также отправлять в pickle-файл <span class=\"inline-code\">proxis.pickle<\/span>. В случае, если он не будет пустым, попробуем взять из него данные.<\/p>\n<pre class=\"e2-text-code\"><code>px_list = set()\r\ntry:\r\n    with open('proxis.pickle', 'rb') as f:\r\n            px_list = pickle.load(f)\r\nexcept:\r\n    pass<\/code><\/pre><p>Функция <span class=\"inline-code\">scrap_proxy()<\/span> будет заходить на сайт free-proxy-list.net и собирать оттуда 20 последних прокси. На сайте новые адреса появляются ежеминутно. Вот, как выглядит интересующая нас область сайта:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/1-8.png\" width=\"1190\" height=\"513\" alt=\"\" \/>\n<\/div>\n<p>Из всего этого будем собирать ID Address и Port. Посмотрим, как элементы расположены в коде страницы:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"http:\/\/test.leftjoin.ru\/pictures\/2-8.png\" width=\"671\" height=\"260\" alt=\"\" \/>\n<\/div>\n<p>Все нужные данные являются ячейками таблицы. В цикле будем брать первые 20 строк, обращаясь к IP-адресу и порту по <span class=\"inline-code\">xpath<\/span>. В конце функция будет отправлять свежие прокси в pickle-файл и возвращать список прокси.<\/p>\n<pre class=\"e2-text-code\"><code>def scrap_proxy():  \r\n    global px_list\r\n    px_list = set()\r\n\r\n    session = requests_html.HTMLSession()\r\n    r = session.get('https:\/\/free-proxy-list.net\/')\r\n    r.html.render()\r\n    for i in range(1, 21):\r\n        add=r.html.xpath('\/html\/body\/section[1]\/div\/div[2]\/div\/div[2]\/div\/table\/tbody\/tr[{}]\/td[1]\/text()'.format(i))[0]\r\n        port=r.html.xpath('\/html\/body\/section[1]\/div\/div[2]\/div\/div[2]\/div\/table\/tbody\/tr[{}]\/td[2]\/text()'.format(i))[0]\r\n        px_list.add(':'.join([add, port]))\r\n\r\n    print(&quot;---New proxy scraped, left: &quot; + str(len(px_list)))\r\n    with open('proxis.pickle', 'wb') as f:\r\n        pickle.dump(px_list, f)\r\n    return px_list<\/code><\/pre><h2>Проверка полученных прокси<\/h2>\n<p>Не всегда свежие прокси оказываются рабочими: мы напишем функцию, которая сама отправит get-запрос к сайту Google с прокси и в случае появления любой ошибки будет возвращать <span class=\"inline-code\">False<\/span>. В случае, если прокси оказался рабочим, функция вернёт <span class=\"inline-code\">True<\/span>.<\/p>\n<pre class=\"e2-text-code\"><code>def check_proxy(px):\r\n    try:\r\n        requests.get(&quot;https:\/\/www.google.com\/&quot;, proxies = {&quot;https&quot;: &quot;https:\/\/&quot; + px}, timeout = 3)\r\n    except Exception as x:\r\n        print('--'+px + ' is dead: '+ x.__class__.__name__)\r\n        return False\r\n    return True<\/code><\/pre><h2>Основная функция<\/h2>\n<p>Главная функция скрипта будет принимать в аргумент переменную scrap, по умолчанию принимающую <span class=\"inline-code\">False<\/span>. Мы будем собирать новые прокси только в том случае, если <span class=\"inline-code\">scrap == True<\/span> или длина списка прокси менее 6. Затем в цикле <span class=\"inline-code\">while True<\/span> собираем новые прокси, берём последний, проверяем его и в случае, если <span class=\"inline-code\">check_proxy<\/span> вернёт <span class=\"inline-code\">True<\/span>, отправляем прочие прокси в pickle-файл и возвращаем рабочий адрес и порт.<\/p>\n<pre class=\"e2-text-code\"><code>def get_proxy(scrap = False):\r\n    global px_list\r\n    if scrap or len(px_list) &lt; 6:\r\n            px_list = scrap_proxy()\r\n    while True:\r\n        if len(px_list) &lt; 6:\r\n            px_list = scrap_proxy()\r\n        px = px_list.pop()\r\n        if check_proxy(px):\r\n            break\r\n    print('-'+px+' is alive. ({} left)'.format(str(len(px_list))))\r\n    with open('proxis.pickle', 'wb') as f:\r\n            pickle.dump(px_list, f)\r\n    return px<\/code><\/pre><h2>Используем скрипт с Selenium<\/h2>\n<p class=\"note\">А ещё мы писали, как через Selenium <a href=\"http:\/\/test.leftjoin.ru\/all\/selenium-button\/\">имитировать нажатие кнопки<\/a> и <a href=\"http:\/\/test.leftjoin.ru\/all\/parsim-dannye-kataloga-sayta-ispolzuya-beautiful-soup-i-selenium\/\">скроллинг каталога интернет-магазина<\/a><\/p>\n<p>Чтобы к скрипту Selenium подключить прокси, импортируем функцию <span class=\"inline-code\">get_proxy<\/span>. Заходим в бесконечный цикл, в переменную <span class=\"inline-code\">PROXY<\/span> запишем свежие полученные прокси и, используя опции браузера, добавим наши прокси и инициируем новый webdriver с обновленными опциями. Затем пробуем зайти на сайт, добавить свои cookie и в случае успеха выходим из цикла оператором <span class=\"inline-code\">break<\/span>. Если новый прокси всё равно оказался нерабочим или вылезла капча, в цикле получим новые прокси и повторим, пока не получится.<\/p>\n<pre class=\"e2-text-code\"><code>from px_scrap import get_proxy\r\n\r\nwhile True:\r\n    PROXY = get_proxy(scrap=True)\r\n    options.add_argument('--proxy-server=%s' % PROXY)\r\n    driver = webdriver.Chrome(chrome_options=options, executable_path=os.path.abspath(&quot;chromedriver&quot;))\r\n    try:\r\n        driver.get('https:\/\/google.com')\r\n        driver.add_cookie(cookies)\r\n    except:\r\n        print('Captcha!')<\/code><\/pre>",
            "date_published": "2020-07-03T17:16:54+03:00",
            "date_modified": "2020-07-03T16:22:47+03:00",
            "image": "http:\/\/test.leftjoin.ru\/pictures\/1-8.png",
            "_date_published_rfc2822": "Fri, 03 Jul 2020 17:16:54 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "50",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": [
                    "http:\/\/test.leftjoin.ru\/pictures\/1-8.png",
                    "http:\/\/test.leftjoin.ru\/pictures\/2-8.png"
                ]
            }
        }
    ],
    "_e2_version": 3365,
    "_e2_ua_string": "E2 (v3365; Aegea)"
}