Внешние скрипты, порядок исполнения
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Более новая информация по этой теме находится на странице https://learn.javascript.ru/script-async-defer.
Если JavaScript-кода много – его выносят в отдельный файл, который подключается в HTML:
Здесь /path/to/script.js – это абсолютный путь к файлу, содержащему скрипт (из корня сайта).
Браузер сам скачает скрипт и выполнит.
Можно указать и полный URL, например:
Вы также можете использовать путь относительно текущей страницы. Например, src=»https://learn.javascript.ru/lodash.js» обозначает файл из текущей директории.
Чтобы подключить несколько скриптов, используйте несколько тегов:
На заметку:
Как правило, в HTML пишут только самые простые скрипты, а сложные выносят в отдельный файл.
Браузер скачает его только первый раз и в дальнейшем, при правильной настройке сервера, будет брать из своего кеша.
Благодаря этому один и тот же большой скрипт, содержащий, к примеру, библиотеку функций, может использоваться на разных страницах без полной перезагрузки с сервера.
Если указан атрибут src , то содержимое тега игнорируется.
В одном теге SCRIPT нельзя одновременно подключить внешний скрипт и указать код.
Вот так не сработает:
Нужно выбрать: либо SCRIPT идёт с src , либо содержит код. Тег выше следует разбить на два: один – с src , другой – с кодом, вот так:
Асинхронные скрипты: defer/async
Браузер загружает и отображает HTML постепенно. Особенно это заметно при медленном интернет-соединении: браузер не ждёт, пока страница загрузится целиком, а показывает ту часть, которую успел загрузить.
Если браузер видит тег , то он по стандарту обязан сначала выполнить его, а потом показать оставшуюся часть страницы.
Например, в примере ниже – пока все кролики не будут посчитаны – нижний
не будет показан:
Начинаем считать:
Кролики посчитаны!
Такое поведение называют «синхронным». Как правило, оно вполне нормально, но есть важное следствие.
Если скрипт – внешний, то пока браузер не выполнит его, он не покажет часть страницы под ним.
То есть, в таком документе, пока не загрузится и не выполнится big.js , содержимое будет скрыто:
Этот текст не будет показан, пока браузер не выполнит big.js.
И здесь вопрос – действительно ли мы этого хотим? То есть, действительно ли оставшуюся часть страницы нельзя показывать до загрузки скрипта?
Есть ситуации, когда мы не только НЕ хотим такой задержки, но она даже опасна.
Например, если мы подключаем внешний скрипт, который показывает рекламу или вставляет счётчик посещений, а затем идёт наша страница. Конечно, неправильно, что пока счётчик или реклама не подгрузятся – оставшаяся часть страницы не показывается. Счётчик посещений не должен никак задерживать отображение страницы сайта. Реклама тоже не должна тормозить сайт и нарушать его функциональность.
А что, если сервер, с которого загружается внешний скрипт, перегружен? Посетитель в этом случае может ждать очень долго!
Вот пример, с подобным скриптом (стоит искусственная задержка загрузки):
Важная информация не покажется, пока не загрузится скрипт.
. Важная информация!
Можно поставить все подобные скрипты в конец страницы – это уменьшит проблему, но не избавит от неё полностью, если скриптов несколько. Допустим, в конце страницы 3 скрипта, и первый из них тормозит – получается, другие два его будут ждать – тоже нехорошо.
Кроме того, браузер дойдёт до скриптов, расположенных в конце страницы, они начнут грузиться только тогда, когда вся страница загрузится. А это не всегда правильно. Например, счётчик посещений наиболее точно сработает, если загрузить его пораньше.
Поэтому «расположить скрипты внизу» – не лучший выход.
Кардинально решить эту проблему помогут атрибуты async или defer :
Поддерживается всеми браузерами, кроме IE9-. Скрипт выполняется полностью асинхронно. То есть, при обнаружении браузер не останавливает обработку страницы, а спокойно работает дальше. Когда скрипт будет загружен – он выполнится.
Поддерживается всеми браузерами, включая самые старые IE. Скрипт также выполняется асинхронно, не заставляет ждать страницу, но есть два отличия от async .
Первое – браузер гарантирует, что относительный порядок скриптов с defer будет сохранён.
То есть, в таком коде (с async ) первым сработает тот скрипт, который раньше загрузится:
А в таком коде (с defer ) первым сработает всегда 1.js , а скрипт 2.js , даже если загрузился раньше, будет его ждать.
Поэтому атрибут defer используют в тех случаях, когда второй скрипт 2.js зависит от первого 1.js , к примеру – использует что-то, описанное первым скриптом.
Второе отличие – скрипт с defer сработает, когда весь HTML-документ будет обработан браузером.
Например, если документ достаточно большой…
Много много много букв
…То скрипт async.js выполнится, как только загрузится – возможно, до того, как весь документ готов. А defer.js подождёт готовности всего документа.
Это бывает удобно, когда мы в скрипте хотим работать с документом, и должны быть уверены, что он полностью получен.
async вместе с defer
При одновременном указании async и defer в современных браузерах будет использован только async , в IE9- – только defer (не понимает async ).
Атрибуты async/defer – только для внешних скриптов
Атрибуты async/defer работают только в том случае, если назначены на внешние скрипты, т.е. имеющие src .
При попытке назначить их на обычные скрипты , они будут проигнорированы.
Тот же пример с async :
Важная информация теперь не ждёт, пока загрузится скрипт.
. Важная информация!
При запуске вы увидите, что вся страница отобразилась тут же, а alert из внешнего скрипта появится позже, когда загрузится скрипт.
Эти атрибуты давно «в ходу»
Большинство современных систем рекламы и счётчиков знают про эти атрибуты и используют их.
Перед вставкой внешнего тега понимающий программист всегда проверит, есть ли у него подобный атрибут. Иначе медленный скрипт может задержать загрузку страницы.
Забегая вперёд
Для продвинутого читателя, который знает, что теги можно добавлять на страницу в любой момент при помощи самого javascript, заметим, что скрипты, добавленные таким образом, ведут себя так же, как async . То есть, выполняются как только загрузятся, без сохранения относительного порядка.
Если же нужно сохранить порядок выполнения, то есть добавить несколько скриптов, которые выполнятся строго один за другим, то используется свойство script.async = false .
Выглядит это примерно так:
function addScript(src) < var script = document.createElement('script'); script.src = src; script.async = false; // чтобы гарантировать порядок document.head.appendChild(script); >addScript('1.js'); // загружаться эти скрипты начнут сразу addScript('2.js'); // выполнятся, как только загрузятся addScript('3.js'); // но, гарантированно, в порядке 1 -> 2 -> 3
Более подробно работу со страницей мы разберём во второй части учебника.
Итого
- Скрипты вставляются на страницу как текст в теге , либо как внешний файл через
- Специальные атрибуты async и defer используются для того, чтобы пока грузится внешний скрипт – браузер показал остальную (следующую за ним) часть страницы. Без них этого не происходит.
- Разница между async и defer : атрибут defer сохраняет относительную последовательность скриптов, а async – нет. Кроме того, defer всегда ждёт, пока весь HTML-документ будет готов, а async – нет.
Очень важно не только читать учебник, но делать что-то самостоятельно.
Решите задачки, чтобы удостовериться, что вы всё правильно поняли.
Задачи
Какой скрипт выполнится первым?
важность: 4
В примере ниже подключены два скрипта small.js и big.js .
Если предположить, что small.js загружается гораздо быстрее, чем big.js – какой выполнится первым?
Как сделать создание блока с надписью по нажатию?
Как сделать чтобы по нажатию на кнопку создавался блок с надписью в определенном месте ?
Это точно я смог сделать, но оно добавляет текст в блок, а не создает новый блок с текстом в блоки !
Document
function klaz()
- Вопрос задан более трёх лет назад
- 72 просмотра
1 комментарий
Простой 1 комментарий
Дима Долготер @SpiderPigAndCat
блок на тексте надо или текст в блоке который в блоке на блоке с текстом?
Решения вопроса 1

Ragtime Kitty @Ragtime_Kitty
Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать
Ответы на вопрос 1

alekseyHunter @alekseyHunter
Android developer
Создание нового блока на JS — «дорогая» операция, поэтому даже ошибки выводят в заготовленные, пустые блоки.
Можешь сделать скрытый блок заранее, вставить в него через JS данные и добавить класс, который будет отображать твой блок.
Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать
Ваш ответ на вопрос
Войдите, чтобы написать ответ

- JavaScript
- +1 ещё
Как объеденить круговой слайдер(диапозон) с полем ввода и кнопками + и -?
- 1 подписчик
- 2 часа назад
- 21 просмотр
Как спарсить любой сайт?

Меня зовут Даниил Охлопков, и я расскажу про свой подход к написанию скриптов, извлекающих данные из интернета: с чего начать, куда смотреть и что использовать.
Написав тонну парсеров, я придумал алгоритм действий, который не только минимизирует затраченное время на разработку, но и увеличивает их живучесть, робастность, масштабируемость.
TL;DR
Чтобы спарсить данные с вебсайта, пробуйте подходы именно в таком порядке:
- Найдите официальное API,
- Найдите XHR запросы в консоли разработчика вашего браузера,
- Найдите сырые JSON в html странице,
- Отрендерите код страницы через автоматизацию браузера,
- Если ничего не подошло — пишите парсеры HTML кода.
Совет профессионалов: не начинайте с BS4/Scrapy
BeautifulSoup4 и Scrapy — популярные инструменты парсинга HTML страниц (и не только!) для Python.
Крутые вебсайты с крутыми продактами делают тонну A/B тестов, чтобы повышать конверсии, вовлеченности и другие бизнес-метрики. Для нас это значит одно: элементы на вебстранице будут меняться и переставляться. В идеальном мире, наш написанный парсер не должен требовать доработки каждую неделю из-за изменений на сайте.
Приходим к выводу, что не надо извлекать данные из HTML тегов раньше времени: разметка страницы может сильно поменяться, а CSS-селекторы и XPath могут не помочь. Используйте другие методы, о которых ниже. ⬇️
Используйте официальный API
Ого? Это не очевидно ? Конечно, очевидно! Но сколько раз было: сидите пилите парсер сайта, а потом БАЦ — нашли поддержку древней RSS-ленты, обширный sitemap.xml или другие интерфейсы для разработчиков. Становится обидно, что поленились и потратили время не туда. Даже если API платный, иногда дешевле договориться с владельцами сайта, чем тратить время на разработку и поддержку.
Sitemap.xml — список страниц сайта, которые точно нужно проиндексировать гуглу. Полезно, если нужно найти все объекты на сайте. Пример: http://techcrunch.com/sitemap.xml
RSS-лента — API, который выдает вам последние посты или новости с сайта. Было раньше популярно, сейчас все реже, но где-то еще есть! Пример: https://habr.com/ru/rss/hubs/all/
Поищите XHR запросы в консоли разработчика

Все современные вебсайты (но не в дарк вебе, лол) используют Javascript, чтобы догружать данные с бекенда. Это позволяет сайтам открываться плавно и скачивать контент постепенно после получения структуры страницы (HTML, скелетон страницы).

Обычно, эти данные запрашиваются джаваскриптом через простые GET/POST запросы. А значит, можно подсмотреть эти запросы, их параметры и заголовки — а потом повторить их у себя в коде! Это делается через консоль разработчика вашего браузера (developer tools).
В итоге, даже не имея официального API, можно воспользоваться красивым и удобным закрытым API. ☺️
Даже если фронт поменяется полностью, этот API с большой вероятностью будет работать. Да, добавятся новые поля, да, возможно, некоторые данные уберут из выдачи. Но структура ответа останется, а значит, ваш парсер почти не изменится.
Алгорим действий такой:

- Открывайте вебстраницу, которую хотите спарсить
- Правой кнопкой -> Inspect (или открыть dev tools как на скрине выше)
- Открывайте вкладку Network и кликайте на фильтр XHR запросов
- Обновляйте страницу, чтобы в логах стали появляться запросы
- Найдите запрос, который запрашивает данные, которые вам нужны
- Копируйте запрос как cURL и переносите его в свой язык программирования для дальнейшей автоматизации.
Вы заметите, что иногда эти XHR запросы включают в себя огромные строки — токены, куки, сессии, которые генерируются фронтендом или бекендом. Не тратьте время на ревёрс фронта, чтобы научить свой парсер генерировать их тоже.
Вместо этого попробуйте просто скопипастить и захардкодить их в своем парсере: очень часто эти строчки валидны 7-30 дней, что может быть окей для ваших задач, а иногда и вообще несколько лет. Или поищите другие XHR запросы, в ответе которых бекенд присылает эти строчки на фронт (обычно это происходит в момент логина на сайт). Если не получилось и без куки/сессий никак, — советую переходить на автоматизацию браузера (Selenium, Puppeteer, Splash — Headless browsers) — об этом ниже.
Поищите JSON в HTML коде страницы
Как было удобно с XHR запросами, да? Ощущение, что ты используешь официальное API. Приходит много данных, ты все сохраняешь в базу. Ты счастлив. Ты бог парсинга.
Но тут надо парсить другой сайт, а там нет нужных GET/POST запросов! Ну вот нет и все. И ты думаешь: неужели расчехлять XPath/CSS-selectors? ♀️ Нет! ♂️
Чтобы страница хорошо проиндексировалась поисковиками, необходимо, чтобы в HTML коде уже содержалась вся полезная информация: поисковики не рендерят Javascript, довольствуясь только HTML. А значит, где-то в коде должны быть все данные.
Современные SSR-движки (server-side-rendering) оставляют внизу страницы JSON со всеми данные, добавленный бекендом при генерации страницы. Стоп, это же и есть ответ API, который нам нужен!
Вот несколько примеров, где такой клад может быть зарыт (не баньте, плиз):


Алгоритм действий такой:
- В dev tools берете самый первый запрос, где браузер запрашивает HTML страницу (не код текущий уже отрендеренной страницы, а именно ответ GET запроса).
- Внизу ищите длинную длинную строчку с данными.
- Если нашли — повторяете у себя в парсере этот GET запрос страницы (без рендеринга headless браузерами). Просто requests.get .
- Вырезаете JSON из HTML любыми костылямии (я использую html.find(«= <") ).
Отрендерите JS через Headless Browsers
Если XHR запросы требуют актуальных tokens, sessions, cookies. Если вы нарываетесь на защиту Cloudflare. Если вам обязательно нужно логиниться на сайте. Если вы просто решили рендерить все, что движется загружается, чтобы минимизировать вероятность бана. Во всех случаях — добро пожаловать в мир автоматизации браузеров!
Если коротко, то есть инструменты, которые позволяют управлять браузером: открывать страницы, вводить текст, скроллить, кликать. Конечно же, это все было сделано для того, чтобы автоматизировать тесты веб интерфейса. I’m something of a web QA myself.
После того, как вы открыли страницу, чуть подождали (пока JS сделает все свои 100500 запросов), можно смотреть на HTML страницу опять и поискать там тот заветный JSON со всеми данными.
driver.get(url_to_open) html = driver.page_source
Selenoid — open-source remote Selenium cluster
Для масштабируемости и простоты, я советую использовать удалённые браузерные кластеры (remote Selenium grid).
Недавно я нашел офигенный опенсорсный микросервис Selenoid, который по факту позволяет вам запускать браузеры не у себя на компе, а на удаленном сервере, подключаясь к нему по API. Несмотря на то, что Support team у них состоит из токсичных разработчиков, их микросервис довольно просто развернуть (советую это делать под VPN, так как по умолчанию никакой authentication в сервис не встроено). Я запускаю их сервис через DigitalOcean 1-Click apps: 1 клик — и у вас уже создался сервер, на котором настроен и запущен кластер Headless браузеров, готовых запускать джаваскрипт!
Вот так я подключаюсь к Selenoid из своего кода: по факту нужно просто указать адрес запущенного Selenoid, но я еще зачем-то передаю кучу параметров бразеру, вдруг вы тоже захотите. На выходе этой функции у меня обычный Selenium driver, который я использую также, как если бы я запускал браузер локально (через файлик chromedriver).
def get_selenoid_driver( enable_vnc=False, browser_name="firefox" ): capabilities = < "browserName": browser_name, "version": "", "enableVNC": enable_vnc, "enableVideo": False, "screenResolution": "1280x1024x24", "sessionTimeout": "3m", # Someone used these params too, let's have them as well "goog:chromeOptions": , "prefs": < "credentials_enable_service": False, "profile.password_manager_enabled": False >, > driver = webdriver.Remote( command_executor=SELENOID_URL, desired_capabilities=capabilities, ) driver.implicitly_wait(10) # wait for the page load no matter what if enable_vnc: print(f"You can view VNC here: ") return driver
Заметьте фложок enableVNC . Верно, вы сможете смотреть видосик с тем, что происходит на удалённом браузере. Всегда приятно наблюдать, как ваш скрипт самостоятельно логинится в Linkedin: он такой молодой, но уже хочет познакомиться с крутыми разработчиками.
Парсите HTML теги
Мой единственный совет: постараться минимизировать число фильтров и условий, чтобы меньше переобучаться на текущей структуре HTML страницы, которая может измениться в следующем A/B тесте.

Даниил Охлопков — Data Lead @ Runa Capital
Подписывайтесь на мой Телеграм канал, где я рассказываю свои истории из парсинга и сливаю датасеты.
Надеюсь, что-то из этого было полезно! Я считаю, что в парсинге важно, с чего ты начинаешь. С чего начать — я рассказал, а дальше ваш ход
Примеры полезных JS-скриптов
С помощью блока «вставка HTML кода» (T123, категория Другое) на страницу можно добавить абсолютно любой скрипт. Мы собрали примеры кода, который вы можете использовать, чтобы добавить некоторые функции.
о достижении цели при клике на ссылку / кнопку
о клике на кнопку
об открытии попапа
после отправки на приемщик данных Тильды
перед переходом из корзины на сайт платежной системы
который срабатывает на кнопки/ссылки с определённым классом
в Facebook Pixel
Примите во внимание, что ниже приведены образцы кода, которые вам нужно будет модифицировать самостоятельно, и эти действия требуют понимания того, как работает Javascript. К сожалению, мы не осуществляем поддержку по вопросам, связанным с работой стороннего кода.
Перехват различных событий на странице
Перехват может понадобиться, если мы хотим отследить открытие попапа, переход по ссылке, отправки данных на сторонний сервис после успешной отправки формы, встраивание в форму своих контролов и много чего еще, на что хватает фантазии и в чем есть потребность.
Перехват клика по ссылке
Перехват клика по ссылке в конкретном блоке
Перехватываем клик по ссылке в блоке #rec123456789
где #rec123456789 — номер блока, в который добавится виджет с погодой;
Номер блока можно посмотреть в Настройках блока
Отправка события в Яндекс.Метрику о достижении цели при клике на ссылку/кнопку
Указанный скрипт отслеживает клик по любой ссылке/кнопке, у которой адрес совпадает с «ссылка». Если такой клик произошел, то будет отправлено событие «цель» в метрику.
где XXXXXX — номер вашего счетчика;
Отправка события в Яндекс.Метрику о достижении цели при клике на внешнюю ссылку/кнопку
Указанный скрипт отслеживает клик по любой внешней ссылке/кнопке, у которой адрес совпадает с «ссылка». Если такой клик произошел, то будет отправлено событие «цель» в метрику.
где XXXXXX — номер вашего счетчика;
Пример отправки событий при клике на кнопки
Есть две кнопки, одна ведет на блок с текстом размещенный на этой же странице, а вторая на другую страницу. У первой кнопки прописан якорь на блок #rec12345678, а у второй ссылка на внешнюю страницу http://help-ru.tilda.cc/
где yaCounterXXXXXX — номер вашего счетчика;
Отправка события в Яндекс. Метрику об открытии попапа
Отлавливаем все клики и если, ссылка на которую кликнули, указывает на «#popup. «, то отправляем в метрику событие — просмотр страницы, ведь попап это тоже страница, да и просмотр страницы легче отследить или построить составную цель (например: открытие страницы, открытие попапа, отправка формы)
Чтобы код ниже заработал, его нужно поместить в HTML-блок, который должен быть в самом верху
Отправка события в Яндекс. Метрику о добавлении товара в Корзину
Указанный скрипт отслеживает клик по кнопке добавления в Корзину. Если такой клик произошел, то будет отправлена цель «AddToCart» в метрику.
где yaCounterXXXXXX — номер счетчика;
AddToCart — произвольное имя цели в Яндекс.Метрике;
Отправка информации в Google Analytics о клике на ссылку / кнопку
Скрипт отслеживает клик по любой ссылке/кнопке, в адресе которой содержится «значение в url». Если такой клик произошел, то будет отправлена информация о клике. Ниже образец кода. Значения, которые нужно заменить выделены прописными.
ЗНАЧЕНИЕ В URL — здесь нужно поставить любое слово, которое есть в ссылке. Например, при клике на кнопку, посетитель попадает на страницу регистрации по адресу: http://mysite.com/registration. В этом случае вместо ЗНАЧЕНИЕ В URL укажите registration.
НАЗВАНИЕ ВИРТУАЛЬНОЙ СТРАНИЦЫ. Информация о клике на кнопке в Google Analitycs появится в виде статистики просмотра виртуальной страницы. Страница виртуальная, поэтому здесь может быть что угодно.
ССЫЛКА — ссылка, которая стоит на кнопке. Например, http://mysite.com/registration
Чтобы отслеживать клик на кнопку, как достижение цели, создайте в Google Analitycs цель: Собственная цель → Целевая страница → Начинается с /click/
Отправка формы на свой ресурс после отправки на приемщик данных Тильды
Проходим все формы и прописываем в них название функции, которую форма сама вызовет после успешной отправки данных
Отправка данных из формы Zero блока на свой ресурс
Выполнение своей функции перед переходом из корзины на сайт платежной системы
Если нам нужно, добавить в cookie информацию о содержимом корзины, или отправить события типа ecommerce в GA или Метрику, то используя вышеуказанный скрипт это можно сделать. Скрипт вызывается прямо перед переходом к платежной системе или вызова виджета оплаты.
Сторонний сервис, который срабатывает на кнопки/ссылки с определённым классом
Например, если необходимый сервис при клике на кнопку открывает специальный диалог, то важно соблюдать порядок работы со скриптом сервиса. Чтобы избежать проблем, сначала происходит добавление классов для кнопок, а потом вставка скрипта:
Запуск разных виджетов для мобильных и десктопных клиентов
Иногда нужно вставить громоздкий виджет для десктопа, при этом небольшой виджет для мобильного варианта. Для этого нам на помощь придет переменная window.isMobile
Пример вставки смешанного виджета
Вместо условия window.isMobile можно использовать размеры экрана, например, window.innerWidth < 960
Bnovo '; > else < /* код для десктопных клиентов */ html = ''; > var widgetBox = document.querySelector('#widgetbox'); if (widgetBox) widgetBox.insertAdjacentHTML('beforeend', html); >
Как сделать меню в Zero блоке
Данная опция появилась теперь встроена в редактор Zero Block. Чтобы включить фиксирование блока, перейдите в настройки артборда → Position and Overflow и поставьте значение Fixed. Подробнее о настройках фиксации →
Запрет автоматической передачи данных о лидах в Facebook Pixel
Если установить Facebook Pixel, то на странице появится объект fbq, который при отправке формы в Facebook отправляет событие Lead. Если требуется собственная настройка пикселя Facebook, запретить это поведение можно с помощью кода:
Компания Meta Platforms Inc., владеющая социальными сетями Facebook и Instagram, по решению суда от 21.03.2022 признана экстремистской организацией, ее деятельность на территории России запрещена.
Примите во внимание, что выше приведены образцы кода, которые вам нужно будет модифицировать самостоятельно, и эти действия требуют понимания того, как работает Javascript. К сожалению, мы не осуществляем поддержку по вопросам, связанным с работой стороннего кода.
