🎯 Trình duyệt đám mây tùy chỉnh, chống phát hiện được hỗ trợ bởi Chromium tự phát triển, thiết kế dành cho trình thu thập dữ liệu webtác nhân AI. 👉Dùng thử ngay
Quay lại blog

Lấy dữ liệu từ các luồng Sự kiện do máy chủ gửi (SSE) bằng Scrapeless

Michael Lee
Michael Lee

Expert Network Defense Engineer

05-Aug-2026

Một bộ đếm bình luận của blog trực tiếp, chỉ báo "đại lý đang gõ" của tiện ích hỗ trợ và một phản hồi trò chuyện AI gõ từng từ một đều có một đặc điểm chung: trình duyệt đã mở kết nối một lần, và máy chủ đã liên tục đẩy mọi cập nhật thông qua phản hồi mở đó kể từ đó. Không có yêu cầu thứ hai cho bộ đếm bình luận, không có vòng lặp truy vấn cho chỉ báo gõ — một HTTP GET, giữ mở, với Content-Type: text/event-stream, và máy chủ viết data: {...}\n\n vào đó mỗi khi có gì thay đổi. Một công cụ chỉ lấy trang một lần và chạy tiếp không bao giờ thấy bất kỳ điều đó, vì dữ liệu đến sau các tiêu đề phản hồi ban đầu, trên một kết nối không bao giờ đóng.

Kết nối Playwright với Scrapeless Scraping Browser qua wss://browser.scrapeless.com/api/v2/browser, và phiên CDP dưới đây cung cấp cho bạn hai cách riêng biệt để đọc các khung được đẩy đến khi chúng đến: trình đọc phản hồi streaming riêng của Playwright, và sự kiện Network.eventSourceMessageReceived thô từ chính Giao thức Công cụ Phát triển Chrome. Hướng dẫn này kết nối với trình duyệt đám mây đó, mở một luồng Sự kiện Gửi từ Máy chủ (SSE) thực sự và ghi lại các khung theo cả hai cách, với mọi đường dẫn mã chạy chống lại một luồng công khai trực tiếp.

Tại sao SSE cần một đường dẫn ghi lại khác

page.goto() theo sau là một lần đọc DOM chỉ hiển thị bất kỳ nội dung nào trong mã HTML của trang tại thời điểm đó. Một tiện ích được tiếp tế bởi SSE không bao giờ làm mới toàn bộ trang — nó thêm hoặc thay thế một phần mỗi khi một dòng data: mới đến, vì vậy một bức tranh snapshot DOM chỉ bắt được bất kỳ cập nhật nào xảy ra tại thời điểm bạn nhìn vào đó. Các bản cập nhật đó hoàn toàn không chạm vào DOM nếu không có gì trên trang làm phiền việc hiển thị chúng; nơi đáng tin cậy duy nhất để đọc chúng là luồng tự thân.

SSE cũng là một trường hợp hẹp hơn so với hai giao thức truyền tải thời gian thực còn lại mà một trình duyệt có thể mở. Một điểm cuối JSON ẩn trả lời một yêu cầu với một phản hồi — đọc nó với page.expect_response() và bạn đã xong. Một WebSocket cần một bắt tay Upgrade: websocket trước khi bất kỳ bên nào có thể gửi một khung, và một khi mở, nó có tính hai chiều — bất kỳ bên nào cũng có thể viết vào bất kỳ thời điểm nào. SSE không cần điều đó: specification của WHATWG về Sự kiện Gửi từ Máy chủ định nghĩa nó như một phản hồi HTTP đơn giản mà nội dung của nó không bao giờ kết thúc, được gửi để trả lời một GET thông thường, có thể đọc với không gì khác kỳ lạ hơn một trình đọc nội dung streaming. Máy chủ ghi vào đó; khách hàng chỉ bao giờ đọc.

Giao thức Công cụ Phát triển Chrome phơi bày luồng đó trực tiếp, theo cách giống như nó phơi bày các khung WebSocket và các phản hồi HTTP bị chặn. Miền Network của nó bắn ra một sự kiện riêng biệt eventSourceMessageReceived cho mỗi tin nhắn mà kết nối EventSource của trang nhận được, tách biệt khỏi các sự kiện phản hồi thân thiện với người sử dụng mà được kích hoạt cho một lần truy cập thông thường. Scrapeless Scraping Browser là một phiên Chromium đám mây chỉ có thể tiếp cận qua CDP — không có điểm cuối WebDriver/Selenium nào để điều khiển nó — vì vậy bất kỳ khách hàng nào có khả năng CDP, Playwright ở đây, có thể đọc cả hai lớp: thân của trình duyệt được stream, hoặc sự kiện giao thức bên dưới nó.

Điều kiện tiên quyết

Bạn cần Python 3.9 trở lên — playwright 1.59.0 khai báo Requires-Python >=3.9 trên PyPI — gói playwright, và một khóa API Scrapeless từ kế hoạch miễn phí tại app.scrapeless.com. Không cần một nhị phân Chrome cục bộ: connect_over_cdp kết nối tới một trình duyệt đã tồn tại trong đám mây Scrapeless.

Các ví dụ bên dưới kết nối với luồng công khai recentchange của Wikimedia Foundation, được tài liệu hóa tại trang dịch vụ EventStreams của chính Wikimedia. Nó không cần khóa API và không cần tài khoản — mọi chỉnh sửa trên mọi dự án Wikimedia đều công khai theo thiết kế, và luồng tồn tại đặc biệt để các công cụ có thể tiêu thụ nó. Cả hai ví dụ đều tự dừng lại sau năm khung thực tế, vì vậy không một lần chạy nào giữ kết nối mở lâu hơn cần thiết để chứng minh việc ghi lại hoạt động.

Cài đặt

bash Copy
pip install playwright
bash Copy
export SCRAPELESS_API_KEY="your_scrapeless_api_key"

Kết nối qua CDP

Tái sử dụng cùng một mẫu tạo URL mà bất kỳ script Playwright-to-Scraping-Browser nào sử dụng: ba tham số truy vấn trên một điểm cuối WSS.

python Copy
import os
from urllib.parse import urlencode

API_KEY = os.environ["SCRAPELESS_API_KEY"]

def scraping_browser_url(proxy_country="US", session_ttl=60):
    params = urlencode({"token": API_KEY, "sessionTTL": session_ttl, "proxyCountry": proxy_country})
    return f"wss://browser.scrapeless.com/api/v2/browser?{params}"

Không giống như một socket dữ liệu thị trường được geofenced, luồng công khai của Wikimedia chấp nhận kết nối từ bất kỳ khu vực nào: cả proxyCountry="US"proxyCountry="DE" đều hoàn thành quá trình bắt tay và bắt đầu truyền khung trong các phiên trực tiếp của phiên này, mà không có mã đóng hay lỗi kết nối theo bất kỳ cách nào. proxyCountry vẫn quan trọng đối với nhiều mục tiêu thực — một luồng bị khóa cho một thị trường cụ thể là một chế độ thất bại thực sự ở nơi khác trong loạt này — nó chỉ đơn giản là không phải là rào cản cho luồng công khai cụ thể này. Xác nhận điều đó với mục tiêu của riêng bạn thay vì giả định bất kỳ kết quả nào.

Ghi Lại Các Khung Với Luồng Phản Hồi Của Playwright

API sự kiện phản hồi của Playwright gọi page.on("response") ngay khi tiêu đề của phản hồi đến, mà không cần chờ cho nội dung hoàn thành — điều này quan trọng ở đây, vì phản hồi SSE không bao giờ hoàn thành tự nó. Kết hợp điều đó với fetch() của trang và một trình đọc ReadableStream, bạn có thể đọc nội dung khi các khối dữ liệu đến thay vì chờ đợi một sự kiện hoàn thành mà không bao giờ xuất hiện:

python Copy
import json
import os
from urllib.parse import urlencode

from playwright.sync_api import sync_playwright

API_KEY = os.environ["SCRAPELESS_API_KEY"]
FRAME_LIMIT = 5
STREAM_URL = "https://stream.wikimedia.org/v2/stream/recentchange"

def scraping_browser_url(proxy_country="US", session_ttl=60):
    params = urlencode({"token": API_KEY, "sessionTTL": session_ttl, "proxyCountry": proxy_country})
    return f"wss://browser.scrapeless.com/api/v2/browser?{params}"

responses_seen = []

def handle_response(response):
    if response.url == STREAM_URL:
        responses_seen.append((response.status, response.headers.get("content-type")))

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(scraping_browser_url())
    page = browser.new_page()
    page.on("response", handle_response)

    page.goto("about:blank")
    frames = page.evaluate(
        f"""async () => {{
            const resp = await fetch("{STREAM_URL}", {{ headers: {{ "Accept": "text/event-stream" }} }});
            const reader = resp.body.getReader();
            const decoder = new TextDecoder();
            let buffer = "";
            const out = [];
            while (out.length < {FRAME_LIMIT}) {{
                const {{ done, value }} = await reader.read();
                if (done) break;
                buffer += decoder.decode(value, {{ stream: true }});
                let idx;
                while ((idx = buffer.indexOf("\\n\\n")) !== -1 && out.length < {FRAME_LIMIT}) {{
                    const rawEvent = buffer.slice(0, idx);
                    buffer = buffer.slice(idx + 2);
                    const dataLine = rawEvent.split("\\n").find(l => l.startsWith("data:"));
                    if (dataLine) out.push(dataLine.slice(5).trim());
                }}
            }}
            await reader.cancel();
            return out;
        }}"""
    )
    browser.close()

print(f"phản hồi đã thấy qua page.on('response'): trạng thái={responses_seen[0][0]}, loại-nội dung={responses_seen[0][1]}")
print(f"ghi lại {len(frames)} khung qua trình đọc luồng fetch() trong trang")
print(json.dumps(json.loads(frames[0]), indent=2))

Chạy nó trên luồng trực tiếp in ra một sự kiện chỉnh sửa thực sự của Wikimedia, cùng với phản hồi mà Playwright chính nó quan sát:

text Copy
phản hồi đã thấy qua page.on('response'): trạng thái=200, loại-nội dung=text/event-stream; charset=utf-8
ghi lại 5 khung qua trình đọc luồng fetch() trong trang
{
  "$schema": "/mediawiki/recentchange/1.0.0",
  "meta": {
    "uri": "https://de.wikipedia.org/wiki/Liste_der_Kulturdenkmale_in_Oschatz",
    "domain": "de.wikipedia.org",
    "stream": "mediawiki.recentchange",
    "dt": "2026-07-28T14:16:13.757Z"
  },
  "id": 382817780,
  "type": "edit"
}

page.on("response") xác nhận rằng lớp mạng của Playwright đã thấy một 200 với loại nội dung SSE trên phản hồi HTTP bên ngoài — bằng chứng đây là một kết nối, chứ không phải năm yêu cầu riêng biệt. Vòng lặp trong trang sau đó đọc nội dung của kết nối cùng một lúc, tách riêng trên dòng trắng mà định dạng luồng sự kiện sử dụng để tách các bản ghi, và lấy dòng data: ra từ mỗi một bản ghi. reader.cancel() đóng kết nối cơ sở ngay khi năm khung được lấy, do đó không gì ở đây giữ luồng của Wikimedia mở vượt quá những gì mà bằng chứng yêu cầu.

Ghi Lại Các Khung Thô Từ Miền Mạng CDP

Đọc một luồng fetch() bằng tay hoạt động, nhưng nó không khiến ngăn xếp mạng của Chrome nhận diện kết nối như một EventSource — sự nhận diện đó là điều kích hoạt sự kiện eventSourceMessageReceived của CDP, và nó chỉ xảy ra khi trang mở luồng bằng đối tượng EventSource bản địa của trình duyệt thay vì một cuộc gọi fetch() thông thường. Hãy truy cập sự kiện CDP thô khi bạn muốn có kế toán của trình duyệt về luồng thay vì một trình phân tích tự chế: nó trả lại eventName, eventId, và data dưới dạng các trường riêng biệt thay vì văn bản thô mà bạn phải tách ra.

python Copy
import json
import os
from urllib.parse import urlencode

from playwright.sync_api import sync_playwright

API_KEY = os.environ["SCRAPELESS_API_KEY"]
FRAME_LIMIT = 5
STREAM_URL = "https://stream.wikimedia.org/v2/stream/recentchange"

def scraping_browser_url(proxy_country="US", session_ttl=60):
    params = urlencode({"token": API_KEY, "sessionTTL": session_ttl, "proxyCountry": proxy_country})
    return f"wss://browser.scrapeless.com/api/v2/browser?{params}"

cdp_events = []

def on_sse_message(event):
    cdp_events.append(event)

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(scraping_browser_url())
    page = browser.new_page()

    cdp = page.context.new_cdp_session(page)
    cdp.send("Network.enable")
    cdp.on("Network.eventSourceMessageReceived", on_sse_message)

    page.goto("about:blank")
    page.evaluate(
        f"""() => {{
            window.__count = 0;
            const es = new EventSource("{STREAM_URL}");
            window.__es = es;
            es.onmessage = () => {{
                window.__count += 1;
                if (window.__count >= {FRAME_LIMIT}) {{ es.close(); }}
            }};
        }}"""
    )
    page.wait_for_function(f"window.__count >= {FRAME_LIMIT}", timeout=20000)
    page.wait_for_timeout(300)
    browser.close()

print(f"đã ghi lại {len(cdp_events)} sự kiện raw CDP eventSourceMessageReceived")
event = cdp_events[0]
print(f"eventName={event['eventName']}")
print(f"eventId={event['eventId']}")
print(json.dumps(json.loads(event["data"]), indent=2))

Sự kiện giao thức thô mang cùng payload chỉnh sửa, cộng với các trường mà trình phân tích dựa trên fetch đã phải bỏ qua:

text Copy
đã ghi lại 5 sự kiện raw CDP eventSourceMessageReceived
eventName=message
eventId=[{"topic":"eqiad.mediawiki.recentchange","partition":0,"timestamp":1785248186774},{"topic":"codfw.mediawiki.recentchange","partition":0,"offset":-1}]
{
  "$schema": "/mediawiki/recentchange/1.0.0",
  "meta": {
    "uri": "https://www.wikidata.org/wiki/Q100886493",
    "domain": "www.wikidata.org",
    "stream": "mediawiki.recentchange",
    "dt": "2026-07-28T14:16:26.773Z"
  },
  "id": 2602974671,
  "type": "edit"
}

page.context.new_cdp_session(page) mở một phiên làm việc mà giao diện CDPSession tiết lộ send() cho các lệnh giao thức và on() cho các sự kiện giao thức; Network.enable bật chế độ báo cáo sự kiện, và mọi sự kiện eventSourceMessageReceived tiếp theo đều xảy ra với đúng hình dạng eventName/eventId/data mà bảng Mạng DevTools đọc cho một hàng EventSource. eventId không phải là một bộ đếm đơn giản — Wikimedia mã hóa metadata topic Kafka, phân vùng, và offset vào, vì giá trị đó cũng đóng vai trò như một con trỏ tiếp tục: kết nối lại với nó dưới dạng tiêu đề yêu cầu Last-Event-ID, và dịch vụ sẽ tiếp tục từ vị trí chính xác đó thay vì phát lại từ đầu.

Những gì bạn nhận được

Cả hai con đường đều trả về cùng một sự kiện chỉnh sửa cơ bản cho luồng này, vì cả hai đều đọc các bản ghi được đẩy của cùng một kết nối mở — một thông qua một trình phân tích tự chế qua fetch thông thường, một trực tiếp từ kế toán SSE của giao thức.

Trường Nguồn Ý nghĩa
event / eventName khung SSE Loại sự kiện; "message" cho mọi bản ghi trên luồng này
id / eventId khung SSE Con trỏ tiếp tục — gửi lại dưới dạng Last-Event-ID khi kết nối lại
data khung SSE Payload JSON thực tế
$schema payload URI lược đồ cho hình dạng của bản ghi này
meta.domain payload Dự án Wikimedia mà chỉnh sửa đã xảy ra
meta.dt payload Dấu thời gian ISO 8601 của sự thay đổi
type payload edit, new, log, hoặc categorize

Tài liệu của Wikimedia khuyến nghị loại bỏ các bản ghi mà meta.domain bằng "canary" — các sự kiện heartbeat tổng hợp mà dịch vụ tiêm cho việc giám sát của chính nó, không phải là các chỉnh sửa thực. Bất kỳ người tiêu dùng nào của luồng này cũng nên loại bỏ những thứ đó trước khi coi bản ghi như hoạt động của người dùng, giống như bạn sẽ loại bỏ một dòng bình luận keep-alive (: keepalive\n\n) mà một số máy chủ SSE gửi để giữ các kết nối nhàn rỗi mở; định dạng cho phép một dòng SSE bắt đầu bằng : trở thành một bình luận mà không có trường data: nào cả, và cả hai con đường capture ở trên đã bỏ qua nó một cách tự nhiên vì không bên nào tìm kiếm nội dung ở đó.
Lấy khóa API của bạn trên gói miễn phí: app.scrapeless.com

SSE và WebSocket trên Thực tế

Hai giao thức giải quyết các vấn đề chồng chéo với những đánh đổi khác nhau, và việc chọn sai giao thức để tìm kiếm sẽ tốn thời gian gỡ lỗi thực sự. Một WebSocket cần một "101 Switching Protocols" để bắt tay trước khi bất kỳ frame nào di chuyển và luôn duy trì kết nối hai chiều; theo hướng dẫn bắt WebSocket trong loạt bài này, không có gì tự động kết nối lại một WebSocket bị mất kết nối. SSE trả lời một GET thông thường với mã 200Content-Type: text/event-stream, chỉ có máy chủ mới ghi dữ liệu, và đối tượng EventSource gốc của trình duyệt tự động kết nối lại. Theo đặc tả WHATWG, nếu kết nối đóng, tác nhân người dùng sẽ chờ một khoảng thời gian được định nghĩa bởi triển khai (thường là vài giây, có thể điều chỉnh theo luồng thông qua một trường thời gian kết nối lại mà định dạng xác định), sau đó mở lại yêu cầu, tự động đính kèm Last-Event-ID để máy chủ có thể tiếp tục thay vì phát lại mọi thứ.

Hành vi kết nối lại đó lý giải tại sao sự phân biệt cấp độ CDP trong hướng dẫn này thực sự quan trọng: một bộ đọc fetch() thô phải tự triển khai việc kết nối lại và theo dõi Last-Event-ID bằng tay, trong khi một đối tượng EventSource thực sự nhận được điều đó miễn phí từ trình duyệt — với cái giá là mất kiểm soát trực tiếp về đúng thời điểm mà một kết nối mới mở ra. Đọc lưu lượng từ một mục tiêu với một EventSource thực khi bạn muốn trình duyệt quản lý việc kết nối lại; đọc nó với fetch() cộng với một bộ đọc luồng khi bạn cần kiểm soát vòng đời kết nối của chính mình, như hủy bỏ sau một số bản ghi giới hạn theo cách mà cả hai ví dụ trên đã làm.

Đọc một Kết Nối SSE từ một Trang Thực Đã Mở

Cả hai phương pháp bắt ở trên đều mở kết nối từ một trang trắng, vì điều đó giữ cho mục tiêu nhỏ và công khai. Một bảng điều khiển trực tiếp, một giao diện trò chuyện, hoặc một nguồn thông báo mở EventSource của riêng nó hoặc fetch() được phát luồng theo cùng một cách, từ mã JavaScript gói của nó, ngay khi thành phần liên quan lắp ghép — và page.on("response") cùng với miền CDP Network sẽ kích hoạt giống nhau theo cả hai cách. Gán cùng một trình xử lý trước khi gọi page.goto() trên mục tiêu thực thay vì trên about:blank, và các frame sẽ đến khi script của trang nhận chúng; không có gì về logic bắt thay đổi vì kết nối xảy ra thuộc về trang thay vì từ một cuộc gọi page.evaluate(). Điều gì thay đổi là việc phát hiện — mở bảng mạng của mục tiêu một lần, lọc theo EventSource hoặc Fetch/XHR, và xác nhận điểm cuối và Content-Type của nó trước khi viết một trình xử lý xung quanh nó, thay vì đoán trước một URL luồng.

Kết luận

Một kết nối SSE là phương thức truyền tải thời gian thực đơn giản nhất mà một trình duyệt có thể mở — một GET, một phản hồi mở, không có bắt tay — và sự đơn giản đó chính là lý do tại sao một công cụ chỉ đọc DOM hoặc chờ phản hồi hoàn tất sẽ không bao giờ thấy được nó. page.on("response") của Playwright với một bộ đọc luồng trong trang và sự kiện Network.eventSourceMessageReceived thô cả hai đều đọc dữ liệu được đẩy tương tự, một qua một bộ phân tích thủ công và một ngay từ giao thức, và cả hai đều làm việc giống hệt nhau với một luồng chỉnh sửa công khai thực trên CDP của Scrapeless Scraping Browser. Giới hạn số lượng bản ghi bạn nắm bắt trước khi đóng kết nối, tôn trọng con trỏ tiếp tục mà trường id: của luồng mang nếu bạn kết nối lại, và phần còn lại của script là một vài cuộc gọi Playwright mà hướng dẫn này đã đi qua. Đọc giới hạn phiên hiện tại và giới hạn thoát trên trang sản phẩm Scraping Browser và kiểm tra giới hạn gói trên trang định giá. Để tìm hiểu về cơ chế kết nối mà hướng dẫn này dựa vào, giải thích về Chrome DevTools Protocol sẽ đi qua những gì CDP tiết lộ ngoài miền Mạng.

Tham gia cộng đồng của chúng tôi để yêu cầu một gói miễn phí và so sánh ghi chú với các nhà phát triển khác đang xây dựng tự động hóa trình duyệt: Discord · Telegram.

Câu hỏi thường gặp

Q: Tôi có cần Selenium hoặc WebDriver để bắt các frame SSE theo cách này không?
Xin vui lòng xem bản dịch dưới đây:

Không. Trình Duyệt Tách Vết Không Có Rác chỉ có thể được truy cập qua Giao Thức Chrome DevTools, vì vậy bất kỳ khách hàng nào nói chuyện với CDP — như Playwright ở đây, hoặc Puppeteer — có thể kết nối và đọc luồng dữ liệu. Không có điểm cuối WebDriver, vì vậy Selenium không thể điều khiển kết nối này.

H: Tại sao một trình đọc fetch() thông thường không kích hoạt sự kiện eventSourceMessageReceived của CDP?

Ngăn xếp mạng của Chrome chỉ phân loại một kết nối là EventSource, và báo cáo qua sự kiện dành riêng đó, khi trang mở nó với đối tượng EventSource gốc. Một cuộc gọi fetch() truyền tải các byte theo cách tương tự ở cấp độ vận chuyển, nhưng Chrome không phân tích hoặc gán thẻ nó là SSE, vì vậy việc đọc nó yêu cầu bạn phải phân tích định dạng text/event-stream bằng cách tự mình làm, giống như ví dụ streaming phản hồi trong hướng dẫn này.

H: Kết nối SSE có tự động kết nối lại nếu nó bị ngắt không?

Chỉ khi được mở với đối tượng EventSource gốc. Theo đặc tả của WHATWG, trình duyệt chờ một khoảng thời gian được xác định bởi triển khai và sau đó mở lại yêu cầu với tiêu đề Last-Event-ID được đặt là giá trị id: cuối cùng mà nó đã thấy, vì vậy một máy chủ hoạt động tốt có thể tiếp tục thay vì phát lại từ đầu. Một trình đọc dựa trên fetch() không tự động nhận được điều này — việc kết nối lại và theo dõi Last-Event-ID phải được viết thủ công.

H: Sự khác biệt giữa điều này và kỹ thuật ngăn chặn yêu cầu mạng trong chuỗi này là gì?

Ngăn chặn đọc cặp yêu cầu/phản hồi riêng biệt — một trang gửi một yêu cầu HTTP mới mỗi khi nó cần dữ liệu mới, và bạn bắt mỗi yêu cầu đó. Một kết nối SSE là một yêu cầu duy nhất mà phần thân phản hồi không bao giờ hoàn thành; không có gì để chặn lại nhiều lần, vì máy chủ tiếp tục viết vào một phản hồi mà nó đã gửi.

H: Điều gì xảy ra với các dòng : comment hoặc các sự kiện canary trên luồng của Wikimedia?

Một dòng bắt đầu bằng : trong định dạng SSE là một bình luận không có trường data:, được gửi bởi một số máy chủ để giữ cho một kết nối nhàn rỗi tồn tại; cả hai đường dẫn ghi lại trong hướng dẫn này chỉ tìm kiếm các dòng data:, vì vậy một bình luận sẽ bị bỏ qua tự động. Wikimedia cũng tiêm các bản ghi tổng hợp meta.domain: "canary" cho việc giám sát của chính nó — hãy lọc chúng ra trước khi coi một bản ghi là một chỉnh sửa thực sự.

H: Liệu có an toàn khi chạy điều này chống lại bất kỳ điểm cuối SSE nào tôi tìm thấy không?

Chỉ chống lại các điểm cuối công khai, không cần xác thực mà bạn được phép đọc, và chỉ ở một khối lượng mà tài liệu của điểm cuối đó cho phép. Ví dụ ở đây nhắm vào luồng chỉnh sửa công khai được tài liệu của Wikimedia mô tả, không cần khóa, và đóng kết nối sau năm bản ghi thay vì giữ nó mở vô thời hạn.

H: Kết nối SSE có thể mở trong bao lâu?

Tham số truy vấn sessionTTL giới hạn phiên trình duyệt trong giây. Một giá trị ngắn là đủ cho một phiên ghi lại có giới hạn như cái ở trong hướng dẫn này; một giá trị dài hơn giữ cho phiên — và bất kỳ kết nối luồng nào đang mở — tồn tại lâu hơn cho một người tiêu dùng chạy lâu.

H: Tôi có thể đọc một luồng SSE mà không cần trình duyệt không?

Có, đối với một điểm cuối công khai không cần xác thực như cái này — một khách hàng HTTP thông thường hỗ trợ đọc thành từng khối có thể phân tích cùng định dạng text/event-stream trực tiếp. Phiên trình duyệt trong hướng dẫn này là đáng giá khi mục tiêu yêu cầu một dấu vân tay Chromium thực sự để thiết lập kết nối ngay từ đầu, hoặc khi một trang mở luồng tự nó như là một tác dụng phụ của JavaScript của chính nó thay vì phơi bày một điểm cuối độc lập được tài liệu hóa.

Tại Scrapless, chúng tôi chỉ truy cập dữ liệu có sẵn công khai trong khi tuân thủ nghiêm ngặt các luật, quy định và chính sách bảo mật trang web hiện hành. Nội dung trong blog này chỉ nhằm mục đích trình diễn và không liên quan đến bất kỳ hoạt động bất hợp pháp hoặc vi phạm nào. Chúng tôi không đảm bảo và từ chối mọi trách nhiệm đối với việc sử dụng thông tin từ blog này hoặc các liên kết của bên thứ ba. Trước khi tham gia vào bất kỳ hoạt động cạo nào, hãy tham khảo ý kiến ​​cố vấn pháp lý của bạn và xem xét các điều khoản dịch vụ của trang web mục tiêu hoặc có được các quyền cần thiết.

Bài viết phổ biến nhất

Danh mục