Введение
Как инженер-краулер, я часто сталкиваюсь с необходимостью сканировать данные в реальном времени в своей работе, такие как данные о спортивных событиях в реальном времени, данные о фондовом рынке в реальном времени или изменения в валютном круге в реальном времени. Как показано ниже:
В веб-домене существует два метода реализации обновления данных в режиме реального времени, а именно опрос и WebSocket. Опрос означает, что клиент обращается к интерфейсу сервера через определенный интервал времени (например, 1 секунду), чтобы добиться эффекта «реального времени».Хотя кажется, что данные обновляются в реальном времени, на самом деле они имеют определенный временной интервал и не очень живые обновления. Опрос обычно использует режим извлечения, когда клиент активно извлекает данные с сервера.
WebSocket использует режим push, и сервер активно отправляет данные клиенту, что является реальным обновлением в реальном времени.
2. Что такое веб-сокет
WebSocket — это протокол для полнодуплексной связи по одному TCP-соединению. Это упрощает обмен данными между клиентом и сервером, позволяя серверу активно передавать данные клиенту. В API WebSocket браузеру и серверу нужно выполнить только одно рукопожатие, и между ними может быть создано постоянное соединение, и может выполняться двусторонняя передача данных.
Преимущества веб-сокета
- Меньше накладных расходов на управление: требуется только одно рукопожатие и требуется только одна информация заголовка запроса, а затем передаются только данные.По сравнению с HTTP, который переносит заголовки запроса в каждом запросе, WebSocket очень экономит ресурсы.
- Сильнее в режиме реального времени: поскольку сервер может активно отправлять сообщения, что делает задержку незначительной по сравнению с временным интервалом опроса HTTP, WebSocket может выполнять несколько передач за одно и то же время.
- Двоичная поддержка: WebSocket поддерживает двоичные кадры, что означает меньшую передачу.
- ...
Сканеры сталкиваются с HTTP и WebSocket
В Python есть много библиотек сетевых запросов, Requests — одна из наиболее часто используемых библиотек запросов, которая может имитировать отправку сетевых запросов. Но все эти запросы основаны на протоколе HTTP. Перед лицом WebSocket запросы играют неожиданную роль, и необходимо использовать библиотеку, которая может подключаться к WebSocket.
Три, ползающие идеи
Вот пример данных в реальном времени с официального сайта Litecoin http://www.laiteb.com/. Рукопожатие WebSocket происходит только один раз, поэтому, если вам нужно наблюдать за сетевым запросом с помощью инструментов разработчика браузера, вам нужно открыть инструменты разработчика браузера, перейти на вкладку NewWork и войти или обновить текущую страницу при открытии страницы. Наблюдайте за запросом рукопожатия WebSocket и передачей данных. Вот пример браузера Chrome:
Фильтрация предоставляется в инструментах разработчика, где параметр WS представляет только сетевые запросы для соединений WebSocket.В это время вы можете видеть, что в списке записей запросов есть запись с именем realTime. После нажатия левой кнопки мыши инструменты разработчика будут разделены на две колонки, в правой части указана подробная информация об этой записи запроса. :
В отличие от HTTP-запросов, адреса подключения WebSocket начинаются с ws или wss. Код состояния успешного подключения не 200, а 101.
На вкладке «Заголовки» записывается информация о запросе и ответе, а на вкладке «Кадры» записываются данные, передаваемые двумя сторонами, которые также являются данными, которые нам необходимо сканировать:
Данные с зеленой стрелкой вверх на диаграмме кадров — это данные, отправленные клиентом на сервер, а данные с оранжевой стрелкой вниз — это данные, переданные сервером клиенту.
Как видно из последовательности данных, клиент отправляет первым:
{"action":"subscribe","args":["QuoteBin5m:14"]}
Затем сервер отправит информацию (всегда нажимает):
{"group":"QuoteBin5m:14","data":[{"low":"55.42","high":"55.63","open":"55.42","close":"55.59","last_price":"55.59","avg_price":"55.5111587372932781077","volume":"40078","timestamp":1551941701,"rise_fall_rate":"0.0030674846625766871","rise_fall_value":"0.17","base_coin_volume":"400.78","quote_coin_volume":"22247.7621987324"}]}
Итак, весь процесс от инициации рукопожатия до получения данных:
Итак, теперь возникает вопрос:
- Как сделать рукопожатие?
- Как сохранить связь?
- Как отправлять и получать сообщения?
- Есть ли какая-нибудь библиотека, чтобы сделать это легко?
В-четвертых, aiowebsocket
Существует множество библиотек Python для подключения к WebSocket, но простые в использовании и стабильные из них включают websocket-client (неасинхронный), websockets (асинхронный) и aiowebsocket (асинхронный).
Вы можете выбрать один из трех в соответствии с требованиями проекта.Сегодня представлен клиент асинхронного подключения WebSocket aiowebsocket. Его адрес на Github:https://github.com/asyncins/aiowebsocket
.
Представлено в ReadMe: AioWebSocket — это асинхронный клиент WebSocket, соответствующий спецификации WebSocket, которая легче и быстрее других библиотек.
Его установка так же проста, как и другие библиотеки, используяpip install aiowebsocket
Вот и все. После установки мы можем протестировать пример кода, представленный в ReadMe:
import asyncio
import logging
from datetime import datetime
from aiowebsocket.converses import AioWebSocket
async def startup(uri):
async with AioWebSocket(uri) as aws:
converse = aws.manipulator
message = b'AioWebSocket - Async WebSocket Client'
while True:
await converse.send(message)
print('{time}-Client send: {message}'
.format(time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'), message=message))
mes = await converse.receive()
print('{time}-Client receive: {rec}'
.format(time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'), rec=mes))
if __name__ == '__main__':
remote = 'ws://echo.websocket.org'
try:
asyncio.get_event_loop().run_until_complete(startup(remote))
except KeyboardInterrupt as exc:
logging.info('Quit.')
Результат после запуска:
2019-03-07 15:43:55-Client send: b'AioWebSocket - Async WebSocket Client'
2019-03-07 15:43:55-Client receive: b'AioWebSocket - Async WebSocket Client'
2019-03-07 15:43:55-Client send: b'AioWebSocket - Async WebSocket Client'
2019-03-07 15:43:56-Client receive: b'AioWebSocket - Async WebSocket Client'
2019-03-07 15:43:56-Client send: b'AioWebSocket - Async WebSocket Client'
……
send представляет сообщение, отправленное клиентом на сервер
получить представляет сообщение, переданное сервером клиенту
5. Кодирование для получения данных
Возвращаясь к требованиям сканирования на этот раз, целевым веб-сайтом является официальный веб-сайт Litecoin:
Из записи сетевого запроса мы знаем, что адрес WebSocket целевого веб-сайта:wss://api.bbxapp.vip/v1/ifcontract/realTime
, По адресу видно, что целевой веб-сайт использует wss, который является безопасной версией ws, и их взаимосвязь такая же, как у HTTP/HTTPS. aiowebsocket автоматически обработает и распознает ssl, поэтому нам не нужно выполнять дополнительные операции, просто присвойте целевой адрес uri подключения:
import asyncio
import logging
from datetime import datetime
from aiowebsocket.converses import AioWebSocket
async def startup(uri):
async with AioWebSocket(uri) as aws:
converse = aws.manipulator
while True:
mes = await converse.receive()
print('{time}-Client receive: {rec}'
.format(time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'), rec=mes))
if __name__ == '__main__':
remote = 'wss://api.bbxapp.vip/v1/ifcontract/realTime'
try:
asyncio.get_event_loop().run_until_complete(startup(remote))
except KeyboardInterrupt as exc:
logging.info('Quit.')
Наблюдайте за выводом после запуска кода, и вы увидите, что ничего не происходит. Нет ни вывода контента, ни отключения, программа продолжает работать, но ничего:
Почему это?
Другая сторона не принимает наш запрос?
Или есть какие-то ограничения против рептилий?
На самом деле блок-схема только сейчас может объяснить проблему:
Один шаг во всем процессе заключается в том, что клиенту необходимо отправить указанное сообщение на сервер, и сервер будет непрерывно передавать данные после проверки. Поэтому код отправки сообщения нужно добавить до того, как сообщение будет прочитано, и после рукопожатия:
import asyncio
import logging
from datetime import datetime
from aiowebsocket.converses import AioWebSocket
async def startup(uri):
async with AioWebSocket(uri) as aws:
converse = aws.manipulator
# 客户端给服务端发送消息
await converse.send('{"action":"subscribe","args":["QuoteBin5m:14"]}')
while True:
mes = await converse.receive()
print('{time}-Client receive: {rec}'
.format(time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'), rec=mes))
if __name__ == '__main__':
remote = 'wss://api.bbxapp.vip/v1/ifcontract/realTime'
try:
asyncio.get_event_loop().run_until_complete(startup(remote))
except KeyboardInterrupt as exc:
logging.info('Quit.')
После сохранения и запуска вы увидите, что данные постоянно передаются:
На этом этапе сканер может получить нужные данные.
что делает aiowebsocket
Код не длинный, при его использовании нужно только заполнить WebSocket-адрес целевого веб-сайта, а затем отправить данные в соответствии с процессом.Так что же делает aiowebsocket в этом процессе?
- Сначала aiowebsocket отправляет запрос на установление связи на указанный сервер в соответствии с адресом WebSocket и проверяет результат установления связи.
- Затем, после подтверждения успешного рукопожатия, данные отправляются на сервер.
- Чтобы соединение не разрывалось в течение всего процесса, aiowebsocket автоматически отвечает на пинг-понг с сервером.
- Наконец, aiowebsocket читает сообщение, отправленное сервером.
[Куинн:] Если вы думаете, что aiowebsocket поможет вам, перейдите на Github.https://github.com/asyncins/aiowebsocket
Дайте ему Звезду. Если вы обнаружите проблемы в использовании или хотите предложить aiowebsocket, вы также можете отправить их на Github. Пока вы вносите предложения, это определенно поможет aiowebsocket стать лучше, и aiowebsocket может продолжать служить вам.