На поиск решения для данной статьи меня натолкнул вот этот вопрос пользователя (Статья - Немного об IPTV или проверка m3u с помощью Python. Часть 01). Изначально я подумал, что он просто не может найти ссылку, которая улетает в запросах для загрузки файла. Но, как оказалось, ему нужно не совсем это. А необходимо получать ссылку, в его случае это ссылка на загрузку плейлиста, в автоматическом режиме. Таким образом, использование инструментов разработчика автоматически отпало. Я покопался в интернете и нашел ответ на этот вопрос, который и послужил толчком для написания этого кода на Python.
А дело здесь вот в чем. Имеется определенный сайт с онлайн-трансляциями различных каналов. Но, сервера постоянно меняют ссылки на потоки. А соответственно, так как пользователь хотел получить свежую ссылку, ее надо было постоянно забирать с сайта. Однако, в html-коде этой ссылки, как и ожидалось, не обнаружилось. Ее получение инициирует js-плеер, расположенный на странице. И в инструментах разработчика данная ссылка видна. Но забрать ее оттуда просто так не получиться. Дело в том, что браузер и python, это собственно два разных объекта, если так можно выразиться. Браузер и его среда исполнения ничего не знает о python, равно, как и python, ничего не знает о среде выполнения браузера. Тем более, что запросы выполняются там в JS. Получается, что надо каким-то образом сообщить одному о другом. Такой способ есть, это использование selenium. Однако, даже после работы selenium ссылки все равно достать не получалось, так как в коде она нигде не фигурировала.
Следовательно, нужно сделать следующее, создать собственный прокси-сервер, через который пропускать все запросы и ответы браузера и уже оттуда забирать ссылки на файлы и прочие объекты, которые он делает. Писать собственный прокси мы не будем. Достаточно уже готового решения. Итак, давайте приступим к написанию кода.
Что потребуется?
Для начала нужно скачать прокси-сервер вот по этой ссылке (
Сервер лежит в диретории: driver → browsermob-proxy-2.1.4 → bin → browsermob-proxy
Двигаемся дальше. Установим selenium. Для этого пишем в терминале команду:
Ну и соответственно необходимо установить browsermob-proxy, некую обертку над командами прокси-сервера.
К сожалению, автор данного проекта не оставил описания. Пишем в терминале команду для установки:
Также установим библиотеку validators. Ее мы будем использовать для проверки соответствия ссылок ссылкам. Чтобы избежать неправильного ввода. Для ее установки пишем в терминале:
И еще одно небольшое, но существенное дополнение. Для того, чтобы прокси-сервер заработал, необходима Java. Поэтому, если у вас она не установлена, то для установки в ОС Linux выполните команду:
Для установки Java в ОС Windows скачайте и установите исполняемый файл вот с этой страницы:
Теперь, когда все библиотеки установлены и выполнены необходимые приготовления, импортируем все, что нам необходимо в скрипт:
Также определим, в зависимости от операционной системы путь к драйверу браузера Chrome, а также путь к к серверу, уже вне зависимости от операционной системы.
Данные параметры я определяю глобально, чтобы не вводить все это вручную при каждом запуске прокси-сервера и браузера. Ну и мало ли что, вдруг данный код будет использоваться в другом модуле.
Создание класса для запуска прокси, браузера и установки их параметров
Для удобства доступа к запуску браузера и прокси-сервера давайте создадим класс class SelenProxy. Инициализируем необходимые переменные в функции __init__(self, url: str, har: str, driver_path: str, ser_path: str). На вход наш класс принимает ссылку на страницу, запросы с которой мы будем перехватывать, ключ для словаря, в который будут складываться все перехваченные запросы от страницы. Ключ необходим для того, чтобы избежать дублирования. Ведь через прокси-сервер может одновременно проходить несколько запросов к разным страницам. И, для того, чтобы складывать полученные значения именно туда, куда требуется, и нужен ключ. Путь к драйверу браузера, а также путь к прокси-серверу.
Здесь же определим опции, которые мы будем передавать браузеру. Это его безголовость, игнорирование ошибок сертификатов, А также параметр прокси. Здесь же создаем сервер на порту 8090. Порт, по сути, может быть любой свободный. В него же передаем путь к приложению. После создания он должен быть запущен. Создаем прокси, передаем его значение в опции с инициализируем драйвер браузера, в который передаем установленные опции, путь для вывода логов, путь к драйверу браузера. И создаем новый har с полученным в класс ключом.
Запуск браузера и получение запросов
Создадим функцию класса driver_get(self) -> (list, bool). Возвращает она список, в данном случае с полученными ссылками из запросов. У вас же это могут быть какие-то другие значения. И в случае, если ссылок получено не было, возвращается False. Создаем список, в который будут добавляться ссылки. Запускаем браузер, в который передаем ссылку на страницу, на которой нужно перехватывать запросы. С помощью time ждем 10 секунд. Данный параметр можно изменить. Все зависит от скорости вашего соединения и загрузки страницы браузера. В нашем же случае, так как на странице содержится мультимедийный контент, лучше подождать чуть-чуть подольше. Затем в цикле итерируемся по полученным значениям, которые представляют из себя json. Забираем оттуда ссылки и добавляем в список. После чего, завершаем работу браузера, останавливаем сервер. И возвращаем заполненный список, если в нем есть значения из функции. Если же список пуст, возвращаем False. Ну и обернем весь наш код в блок try — except, для того, чтобы поймать ошибки, если таковые возникнут в процессе работы.
Создание класса, запуск перехвата и обработка полученных значений
Создадим функцию main. В ней для начала запросим у пользователя ссылку на страницу для перехвата запросов. Проверим ее в валидаторе. Если она не соответствует ссылке, выводим сообщение об этом пользователю и выходим из скрипта. Если же все в порядке, двигаемся дальше. Создаем экземпляр нашего класса, передаем в него запрошенную у пользователя ссылку, из ссылки забираем хост и передаем в качестве ключа для словаря, передаем путь к драйверу браузера и прокси-серверу, которые определены глобально.
Обрабатываем полученные значения. Если вернулся False, Сообщаем пользователю, что ничего перехвачено не было. Если же полученный список содержит значения, итерируемся по полученному списку и выводим то, что получили в терминал. Тут уже с этими ссылками можно делать все, что вам нужно. Так как изначально вопрос был о получении плейлистов на каналы, я добавил небольшой фильтр, с помощью которого будем фильтровать нужные нам значения.
Вот в принципе и все. Такой небольшой локальный прокси-сервер с использованием selenium у нас получился. В принципе, работает довольно исправно, главное, чтобы браузер смог загрузить нужную страницу. Не все страницы открываются в безголовом режиме. Но, тут уже надо экспериментировать и добавлять или удалять параметр «безголовости» в зависимости от потребностей.
Для эксперимента был выбран сайт, который указал пользователь, с онлайн трансляциями TV-каналов:
Как видим, все прошло удачно и ссылки на плейлисты были получены. Причем, некоторые были получены даже с сессионными ключами.
А на этом, пожалуй, все.
Спасибо за внимание. Надеюсь, данная информация была для вас полезна
А дело здесь вот в чем. Имеется определенный сайт с онлайн-трансляциями различных каналов. Но, сервера постоянно меняют ссылки на потоки. А соответственно, так как пользователь хотел получить свежую ссылку, ее надо было постоянно забирать с сайта. Однако, в html-коде этой ссылки, как и ожидалось, не обнаружилось. Ее получение инициирует js-плеер, расположенный на странице. И в инструментах разработчика данная ссылка видна. Но забрать ее оттуда просто так не получиться. Дело в том, что браузер и python, это собственно два разных объекта, если так можно выразиться. Браузер и его среда исполнения ничего не знает о python, равно, как и python, ничего не знает о среде выполнения браузера. Тем более, что запросы выполняются там в JS. Получается, что надо каким-то образом сообщить одному о другом. Такой способ есть, это использование selenium. Однако, даже после работы selenium ссылки все равно достать не получалось, так как в коде она нигде не фигурировала.
Следовательно, нужно сделать следующее, создать собственный прокси-сервер, через который пропускать все запросы и ответы браузера и уже оттуда забирать ссылки на файлы и прочие объекты, которые он делает. Писать собственный прокси мы не будем. Достаточно уже готового решения. Итак, давайте приступим к написанию кода.
Что потребуется?
Для начала нужно скачать прокси-сервер вот по этой ссылке (
Ссылка скрыта от гостей
). Распаковать содержимое архива где-нибудь в директории со скриптом. Я создал для этих целей папку driver, в которую распаковал сервер. Также в эту папку, поскольку мы будем использовать selenium, я скачал и распаковал драйвера для браузера Google Chrome. Драйвера можно взять вот на этой странице:
Ссылка скрыта от гостей
. Посмотрите вашу версию браузера и скачайте нужный драйвер. Ну и понятное дело, раз мы будем использовать браузер, нужно его установить, если он еще не установлен. Таким образом структура моей папки driver получилась следующей:Сервер лежит в диретории: driver → browsermob-proxy-2.1.4 → bin → browsermob-proxy
Двигаемся дальше. Установим selenium. Для этого пишем в терминале команду:
pip install selenium
Ну и соответственно необходимо установить browsermob-proxy, некую обертку над командами прокси-сервера.
К сожалению, автор данного проекта не оставил описания. Пишем в терминале команду для установки:
pip install browsermob-proxy
Также установим библиотеку validators. Ее мы будем использовать для проверки соответствия ссылок ссылкам. Чтобы избежать неправильного ввода. Для ее установки пишем в терминале:
pip install validators
И еще одно небольшое, но существенное дополнение. Для того, чтобы прокси-сервер заработал, необходима Java. Поэтому, если у вас она не установлена, то для установки в ОС Linux выполните команду:
sudo apt install default-jre
Для установки Java в ОС Windows скачайте и установите исполняемый файл вот с этой страницы:
Ссылка скрыта от гостей
Теперь, когда все библиотеки установлены и выполнены необходимые приготовления, импортируем все, что нам необходимо в скрипт:
Python:
import os
import time
from pathlib import Path
from platform import system
from urllib.parse import urlparse
import validators
from browsermobproxy import Server
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
Также определим, в зависимости от операционной системы путь к драйверу браузера Chrome, а также путь к к серверу, уже вне зависимости от операционной системы.
Python:
if system() == "Windows":
exec_path = str(Path.cwd() / 'driver' / 'chromedriver.exe')
elif system() == "Linux":
exec_path = str(Path.cwd() / 'driver' / 'chromedriver')
serv_path = str(Path.cwd() / 'driver' / 'browsermob-proxy-2.1.4' / 'bin' / 'browsermob-proxy')
Данные параметры я определяю глобально, чтобы не вводить все это вручную при каждом запуске прокси-сервера и браузера. Ну и мало ли что, вдруг данный код будет использоваться в другом модуле.
Создание класса для запуска прокси, браузера и установки их параметров
Для удобства доступа к запуску браузера и прокси-сервера давайте создадим класс class SelenProxy. Инициализируем необходимые переменные в функции __init__(self, url: str, har: str, driver_path: str, ser_path: str). На вход наш класс принимает ссылку на страницу, запросы с которой мы будем перехватывать, ключ для словаря, в который будут складываться все перехваченные запросы от страницы. Ключ необходим для того, чтобы избежать дублирования. Ведь через прокси-сервер может одновременно проходить несколько запросов к разным страницам. И, для того, чтобы складывать полученные значения именно туда, куда требуется, и нужен ключ. Путь к драйверу браузера, а также путь к прокси-серверу.
Здесь же определим опции, которые мы будем передавать браузеру. Это его безголовость, игнорирование ошибок сертификатов, А также параметр прокси. Здесь же создаем сервер на порту 8090. Порт, по сути, может быть любой свободный. В него же передаем путь к приложению. После создания он должен быть запущен. Создаем прокси, передаем его значение в опции с инициализируем драйвер браузера, в который передаем установленные опции, путь для вывода логов, путь к драйверу браузера. И создаем новый har с полученным в класс ключом.
Python:
class SelenProxy:
def __init__(self, url: str, har: str, driver_path: str, ser_path: str):
self.url = url
self.options = webdriver.ChromeOptions()
self.options.add_argument('headless')
self.options.add_argument("--ignore-certificate-errors")
self.server = Server(ser_path, options={'port': 8090})
self.server.start()
self.proxy = self.server.create_proxy(params={"trustAllServers": "true"})
self.options.add_argument("--proxy-server={0}".format(self.proxy.proxy))
self.driver = webdriver.Chrome(options=self.options, service=Service(log_path=os.devnull,
executable_path=driver_path))
self.proxy.new_har(har)
Запуск браузера и получение запросов
Создадим функцию класса driver_get(self) -> (list, bool). Возвращает она список, в данном случае с полученными ссылками из запросов. У вас же это могут быть какие-то другие значения. И в случае, если ссылок получено не было, возвращается False. Создаем список, в который будут добавляться ссылки. Запускаем браузер, в который передаем ссылку на страницу, на которой нужно перехватывать запросы. С помощью time ждем 10 секунд. Данный параметр можно изменить. Все зависит от скорости вашего соединения и загрузки страницы браузера. В нашем же случае, так как на странице содержится мультимедийный контент, лучше подождать чуть-чуть подольше. Затем в цикле итерируемся по полученным значениям, которые представляют из себя json. Забираем оттуда ссылки и добавляем в список. После чего, завершаем работу браузера, останавливаем сервер. И возвращаем заполненный список, если в нем есть значения из функции. Если же список пуст, возвращаем False. Ну и обернем весь наш код в блок try — except, для того, чтобы поймать ошибки, если таковые возникнут в процессе работы.
Python:
def driver_get(self) -> (list, bool):
try:
url_list = []
self.driver.get(self.url)
time.sleep(10)
for item in self.proxy.har['log']['entries']:
if url := item['request'].get('url'):
url_list.append(url)
self.driver.quit()
self.server.stop()
return url_list if url_list else False
except Exception:
return False
Создание класса, запуск перехвата и обработка полученных значений
Создадим функцию main. В ней для начала запросим у пользователя ссылку на страницу для перехвата запросов. Проверим ее в валидаторе. Если она не соответствует ссылке, выводим сообщение об этом пользователю и выходим из скрипта. Если же все в порядке, двигаемся дальше. Создаем экземпляр нашего класса, передаем в него запрошенную у пользователя ссылку, из ссылки забираем хост и передаем в качестве ключа для словаря, передаем путь к драйверу браузера и прокси-серверу, которые определены глобально.
Обрабатываем полученные значения. Если вернулся False, Сообщаем пользователю, что ничего перехвачено не было. Если же полученный список содержит значения, итерируемся по полученному списку и выводим то, что получили в терминал. Тут уже с этими ссылками можно делать все, что вам нужно. Так как изначально вопрос был о получении плейлистов на каналы, я добавил небольшой фильтр, с помощью которого будем фильтровать нужные нам значения.
Python:
def main():
# http://2tv.one/1hd
global exec_path, serv_path
url_input = input("Введите страницу для перехвата: ")
if validators.url(url_input):
print("\nЗапуск сервера. Загрузка страницы")
driver = SelenProxy(url=url_input, har=f'{urlparse(url_input).hostname}/', driver_path=exec_path,
ser_path=serv_path)
if urls := driver.driver_get():
print(f"\nНайдены ссылки\n{'-'*25}")
for url in urls:
if Path(str(urlparse(url).path.split("/")[-1])).suffix in [".m3u", ".m3u8", ".mpd"]:
print(url)
else:
print(f"\nСсылок не найдено. Список пуст\n{'-'*25}")
else:
print(f"\nВведенная строка не содержит ссылку\n{'-'*25}")
if __name__ == "__main__":
main()
Вот в принципе и все. Такой небольшой локальный прокси-сервер с использованием selenium у нас получился. В принципе, работает довольно исправно, главное, чтобы браузер смог загрузить нужную страницу. Не все страницы открываются в безголовом режиме. Но, тут уже надо экспериментировать и добавлять или удалять параметр «безголовости» в зависимости от потребностей.
Для эксперимента был выбран сайт, который указал пользователь, с онлайн трансляциями TV-каналов:
Ссылка скрыта от гостей
. Это ссылка на первый канал. Давайте запустим скрипт и посмотрим, найдет ли он ссылки на плейлист. Ниже представлен скриншот выполнения скрипта:Как видим, все прошло удачно и ссылки на плейлисты были получены. Причем, некоторые были получены даже с сессионными ключами.
Python:
import os
import time
from pathlib import Path
from platform import system
from urllib.parse import urlparse
import validators
from browsermobproxy import Server
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
if system() == "Windows":
exec_path = str(Path.cwd() / 'driver' / 'chromedriver.exe')
elif system() == "Linux":
exec_path = str(Path.cwd() / 'driver' / 'chromedriver')
serv_path = str(Path.cwd() / 'driver' / 'browsermob-proxy-2.1.4' / 'bin' / 'browsermob-proxy')
class SelenProxy:
def __init__(self, url: str, har: str, driver_path: str, ser_path: str):
self.url = url
self.options = webdriver.ChromeOptions()
self.options.add_argument('headless')
self.options.add_argument("--ignore-certificate-errors")
self.server = Server(ser_path, options={'port': 8090})
self.server.start()
self.proxy = self.server.create_proxy(params={"trustAllServers": "true"})
self.options.add_argument("--proxy-server={0}".format(self.proxy.proxy))
self.driver = webdriver.Chrome(options=self.options, service=Service(log_path=os.devnull,
executable_path=driver_path))
self.proxy.new_har(har)
def driver_get(self) -> (list, bool):
try:
url_list = []
self.driver.get(self.url)
time.sleep(10)
for item in self.proxy.har['log']['entries']:
if url := item['request'].get('url'):
url_list.append(url)
self.driver.quit()
self.server.stop()
return url_list if url_list else False
except Exception:
return False
def main():
# http://2tv.one/1hd
global exec_path, serv_path
url_input = input("Введите страницу для перехвата: ")
if validators.url(url_input):
print("\nЗапуск сервера. Загрузка страницы")
driver = SelenProxy(url=url_input, har=f'{urlparse(url_input).hostname}/', driver_path=exec_path,
ser_path=serv_path)
if urls := driver.driver_get():
print(f"\nНайдены ссылки\n{'-'*25}")
for url in urls:
if Path(str(urlparse(url).path.split("/")[-1])).suffix in [".m3u", ".m3u8", ".mpd"]:
print(url)
else:
print(f"\nСсылок не найдено. Список пуст\n{'-'*25}")
else:
print(f"\nВведенная строка не содержит ссылку\n{'-'*25}")
if __name__ == "__main__":
main()
А на этом, пожалуй, все.
Спасибо за внимание. Надеюсь, данная информация была для вас полезна
Вложения
Последнее редактирование: