🎯 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

Web Scraping Python Asynchronous: Mở rộng đến 10.000+ URL với aiohttp và Scrapeless

Ethan Brown
Ethan Brown

Advanced Bot Mitigation Engineer

28-May-2026

Những điểm chính:

  • Async vượt trội hơn sync khoảng ~10–100× trên các scrape phụ thuộc vào I/O. Vòng lặp sự kiện của asyncio cho phép một luồng Python xử lý hàng trăm yêu cầu HTTP đang diễn ra; tương đương sync sẽ bị chặn trên mỗi lần đọc socket và chịu toàn bộ độ trễ cho mỗi URL.
  • aiohttp là client HTTP async chính thức. Một aiohttp.ClientSession duy nhất giữ kết nối pool, keep-alives, cookies, và timeouts — ghép nó với asyncio.gather để phân phối và một asyncio.Semaphore cho giới hạn theo mỗi host.
  • Proxy residential Scrapeless định tuyến các fetch async. Một URL proxy cắm thẳng vào aiohttp.ClientSession(... proxy=...), cung cấp mỗi yêu cầu một địa chỉ IP residential khác nhau, và cố định địa điểm thoát với mã quốc gia được nhúng trong tên người dùng.
  • Trình duyệt Scraping Scrapeless xử lý nhóm thiểu số được render bằng JS. Các trang mà aiohttp trả về dưới dạng shell ứng dụng JS (Next.js, React, Vue) sẽ được nâng cấp lên phiên làm việc của trình duyệt đám mây — kết nối từ Python async thông qua Scrapeless Python SDK cộng với API async của Playwright.
  • Các lỗi sẽ không ở kênh chính. asyncio.gather(return_exceptions=True) giữ cho một URL xấu không hủy bỏ phần còn lại của phân phối; các URL bị lỗi sẽ vào danh sách dead-letter để xem xét riêng, không vào vòng lặp inline.
  • Miễn phí để bắt đầu. Tài khoản Scrapeless mới bao gồm thời gian chạy Scraping Browser miễn phí — đăng ký tại Scrapeless.

Giới thiệu: Tại sao lại là async, và những chi phí của scraping tuần tự

Một trình thu thập dữ liệu Python đồng bộ sử dụng requests sẽ chặn luồng trên mỗi lần đọc socket. Scrape 1.000 trang sản phẩm với 500 ms mỗi yêu cầu và chi phí thời gian là khoảng 500 giây — độ trễ trả trong toàn bộ, một URL mỗi lần.

asyncio đảo ngược điều đó. Vòng lặp sự kiện nhường quyền kiểm soát trong khi một socket đang chuyển động, cho phép coroutine tiếp theo bắt đầu yêu cầu của riêng nó, và kết nối hàng trăm fetch lại trên một luồng duy nhất. Cùng 1.000 trang đó — giới hạn ở 10 yêu cầu đồng thời mỗi host — được xử lý trong khoảng 50 giây. Cùng phần cứng, cùng Python, cùng dữ liệu.

Cái bẫy: scraping async có hai chế độ thất bại mà phiên bản sync không bao giờ gặp. Lỗi pipeline, nơi một ngoại lệ bị ném bên trong một coroutine có thể hủy bỏ toàn bộ gather, và áp lực ở phía mục tiêu, nơi một pool đang chuyển động chặt chẽ trông không khác nào một cuộc tấn công nếu lớp proxy không thể phân tán địa điểm thoát qua các IP.

Hướng dẫn này đi qua cả hai. Tầng HTTP sử dụng aiohttp cộng với proxy residential Scrapeless ở hơn 195 quốc gia. Tầng được render bằng JS nâng cấp lên Trình duyệt Scraping Scrapeless, kết nối từ Python async với Scrapeless Python SDK và API async của Playwright.


Bạn có thể làm gì với nó

  • Crawl các catalog tĩnh ở quy mô lớn. Sách, bài viết, sitemap, bất cứ thứ gì gửi HTML đã render — phân phối async biến những lần crawl kéo dài hàng giờ thành những lần crawl chỉ vài phút.
  • Chạy nhiều lần kéo nguồn đồng thời. RSS, API JSON, chỉ mục sitemap; phân phối qua hàng trăm endpoint với độ đồng thời giới hạn.
  • Giám sát giá qua các vùng. Ghi chép địa điểm Scrapeless vào US, GB, DE, JP và kéo cùng một trang sản phẩm từ nhiều địa điểm khác nhau song song.
  • Kiểm tra audit trang web của bạn. Async quét một sitemap 10k-URL chỉ trong vài phút thay vì hàng giờ và báo cáo lại các liên kết chết và những con đường chậm.
  • Bổ sung cho các pipeline downstream. Tầng async cung cấp HTML hoặc JSON đã render thẳng vào Postgres, Snowflake, hoặc Kafka mà không có nút thắt cổ chai từ pool luồng.
  • Nâng cấp chọn lọc. Giữ aiohttp ở mức HTTP rẻ cho ~70% trang gửi markup đã render; chỉ khởi động các phiên trình duyệt đám mây cho nhóm JS nặng.

Tại Scrapeless, chúng tôi chỉ truy cập dữ liệu công khai sẵn có trong khi tuân thủ nghiêm ngặt các luật lệ, quy định và chính sách quyền riêng tư của trang web. Nội dung trong bài viết này chỉ để mục đích minh họa.


Tại sao chọn Scrapeless cho Scraping Async

Trình duyệt Scraping Scrapeless là một trình duyệt đám mây tùy biến, chống phát hiện, được thiết kế cho các trình thu thập dữ liệu web và các tác nhân AI; proxy residential Scrapeless là lớp proxy bên dưới. Đặc biệt cho các pipeline Python async, sự kết hợp mang đến:

  • Proxy residential ở hơn 195 quốc gia, được hiển thị dưới dạng một URL proxy HTTP duy nhất mà cắm thẳng vào aiohttp.ClientSession(... proxy=...).
  • Ghi chép geo theo yêu cầu thông qua mã quốc gia được nhúng trong thông tin xác thực của proxy — không mất chi phí bắt tay cho từng yêu cầu, không cần tái tạo phiên cho mỗi coroutine.
  • Tùy chọn session dính cho các dòng cần cùng một IP qua nhiều bước đăng nhập hoặc duyệt trang phân trang, và các IP luân phiên cho mọi thứ khác.
  • Render JS bên đám mây khi một trang nặng về React/Vue/Next.js — SDK Python tạo ra một browser_ws_endpoint mà bạn kết nối với API async của Playwright.
  • Một khóa API cho cả hai tầng — proxy và Trình duyệt Scraping tính phí trên cùng một tài khoản Scrapeless.

Lấy khóa API của bạn trong gói miễn phí tại Scrapeless.

Các yêu cầu tiên quyết

  • Python 3.10 hoặc mới hơn
  • Một tài khoản Scrapeless và khóa API — đăng ký tại app.scrapeless.com
  • Sự thoải mái với async/await và mô hình vòng lặp sự kiện
  • Một terminal

Bước 1 — Cài đặt asyncio, aiohttp và Scrapeless SDK

aiohttp đi kèm với hỗ trợ asyncio tích hợp. SDK scrapeless tạo các phiên trình duyệt trên đám mây cho cấp độ tăng cường Bước 6. API async của Playwright là cách chuẩn văn bản Python async để điều khiển Trình duyệt Scraping của Scrapeless:

bash Copy
pip install aiohttp scrapeless playwright
playwright install chromium

playwright install chromium tải xuống một client CDP cục bộ một lần; việc render thực sự vẫn chạy trong đám mây Scrapeless — Chromium cục bộ chỉ là trình điều khiển giao thức.


Bước 2 — Cấu hình thông tin đăng nhập Scrapeless của bạn

Xuất khóa API Scrapeless, ID kênh của bạn và mật khẩu kênh proxy dân cư của bạn dưới dạng biến môi trường. Tất cả ba đều hiển thị trong bảng điều khiển Scrapeless dưới Proxies → Residential tại app.scrapeless.com — nhấp vào Generate và bảng điều khiển in ra một chuỗi phân cách bằng dấu hai chấm dưới dạng <GATEWAY>:<PORT>:<CHANNEL_ID>-proxy-country_US-r_10m-s_<SESSION_ID>:<PASSWORD>:

bash Copy
export SCRAPELESS_API_KEY="your_api_token_here"
export SCRAPELESS_CHANNEL_ID="your_channel_id"          # in ra ở đầu tên người dùng
export SCRAPELESS_PROXY_PASS="your_channel_password"
export SCRAPELESS_PROXY_GATEWAY="gw-us.scrapeless.io"   # xem bên dưới cho các cổng khu vực

Các cổng khu vực: gw-us.scrapeless.io (Châu Mỹ), gw-eu.scrapeless.io (Châu Âu), gw-ap.scrapeless.io (Châu Á-Thái Bình Dương). Chọn cổng gần nhất với thời gian chạy của bạn để giữ cho độ trễ bắt tay thấp; quốc gia xuất vẫn được kiểm soát bởi tham số tên người dùng country_<CC> bất kể bạn kết nối qua cổng nào. Cổng là 8789 cho tất cả.

Tên người dùng proxy dân cư được tạo thành từ bốn tham số:

  • <CHANNEL_ID> — định danh kênh của bạn (in ra ở đầu tên người dùng trên bảng điều khiển).
  • country_<CC> — mã quốc gia ở dạng hai chữ cái. Scrapeless sử dụng country_US, country_UK, country_DE, country_JP, v.v. (lưu ý: UK, không phải ISO GB).
  • r_<duration> — khoảng thời gian quay vòng phiên bám (ví dụ: r_10m giữ cùng một IP trong 10 phút trước khi quay vòng).
  • s_<SESSION_ID> — định danh phiên bám; tái sử dụng cùng một s_<id> qua các yêu cầu để giữ cùng một IP trong khoảng thời gian kéo dài.

Bỏ r_s_ để nhận được các IP quay vòng (một IP dân cư mới cho mỗi yêu cầu). Giữ chúng cho các quy trình cần tính liên tục của phiên, như là duyệt phân trang sau khi đăng nhập.


Bước 3 — Cơ bản: một lần lấy async duy nhất với aiohttp + proxy Scrapeless

Trình thu thập dữ liệu async chức năng nhỏ nhất. Một ClientSession, một GET, một tải trọng HTML được trả về qua proxy dân cư:

python Copy
import asyncio
import os
import aiohttp

PROXY = (
    f"http://{os.environ['SCRAPELESS_CHANNEL_ID']}-proxy-country_US"
    f":{os.environ['SCRAPELESS_PROXY_PASS']}"
    f"@{os.environ['SCRAPELESS_PROXY_GATEWAY']}:8789"
)

async def fetch(session: aiohttp.ClientSession, url: str) -> str:
    timeout = aiohttp.ClientTimeout(total=30)
    async with session.get(url, proxy=PROXY, timeout=timeout) as resp:
        resp.raise_for_status()
        return await resp.text()

async def main() -> None:
    async with aiohttp.ClientSession() as session:
        html = await fetch(session, "https://books.toscrape.com/")
        print(f"Đã lấy {len(html):,} ký tự qua egress dân cư ở Mỹ")

if __name__ == "__main__":
    asyncio.run(main())

Ba điều mà đoạn mã này xác định sớm:

  • ClientSession được tạo một lần và tái sử dụng. Mỗi session.get(...) chia sẻ cùng một bể kết nối — việc tạo lại phiên cho mỗi yêu cầu làm mất ý nghĩa của async.
  • URL proxy được truyền theo từng yêu cầu, chứ không phải theo phiên. Điều này giữ cho cùng một ClientSession tự do định tuyến các yêu cầu khác nhau qua các quốc gia khác nhau.
  • ClientTimeout(total=30) giới hạn mỗi yêu cầu. Một kết nối bị treo không thể chặn phần còn lại của quá trình tập hợp.

Bước 4 — Nâng cao: mở rộng đến các lần lấy đồng thời với asyncio.gather và giới hạn Semaphore

Mở rộng tới 100 URL mà không có giới hạn đồng thời là cách mà một trình thu thập dữ liệu bị chặn trong 10 giây. Mẫu chuẩn là asyncio.Semaphore để giới hạn các yêu cầu đang thực hiện trên mỗi máy chủ:

python Copy
import asyncio
import os
import aiohttp

PROXY = (
    f"http://{os.environ['SCRAPELESS_CHANNEL_ID']}-proxy-country_US"
    f":{os.environ['SCRAPELESS_PROXY_PASS']}"
    f"@{os.environ['SCRAPELESS_PROXY_GATEWAY']}:8789"
)

# Giới hạn 5 yêu cầu đồng thời trên mỗi máy chủ. Điều chỉnh theo mục tiêu — các catalog công khai
# chịu đựng được cao hơn, các nguồn được bảo vệ chống bot muốn thấp hơn.
PER_HOST = asyncio.Semaphore(5)

async def fetch(session: aiohttp.ClientSession, url: str) -> str:
    async with PER_HOST:
        timeout = aiohttp.ClientTimeout(total=30)
        async with session.get(url, proxy=PROXY, timeout=timeout) as resp:
```plaintext
resp.raise_for_status()
            return await resp.text()

async def main() -> None:
    urls = [
        f"https://books.toscrape.com/catalogue/page-{n}.html"
        for n in range(1, 51)  # 50 trang danh mục
    ]
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, url) for url in urls]
        pages = await asyncio.gather(*tasks)
    print(f"Đã lấy {len(pages)} trang, tổng cộng {sum(len(p) for p in pages):,} ký tự")

if __name__ == "__main__":
    asyncio.run(main())

asyncio.Semaphore(5) là dòng chịu tải. Nếu không có nó, asyncio.gather sẽ khởi chạy tất cả 50 coroutine cùng một lúc và cổng sẽ hạn chế tốc độ hoặc từ chối một nửa trong số đó. Với nó, chỉ có 5 yêu cầu được xử lý tại một thời điểm; phần còn lại chờ trong vòng lặp sự kiện cho đến khi có slot trống.

Đối với việc phân tán đa máy chủ, tạo một Semaphore cho mỗi nguồn gốc và khóa nó theo tên máy chủ — như vậy, nếu một nguồn gốc bị tắc nghẽn sẽ không làm nghẽn việc lấy dữ liệu từ những nguồn gốc khác.

Nhận khóa API của bạn tại:

Scrapeless kế hoạch miễn phí


Bước 5 — Xử lý lỗi mà không chặn đường ống

Một raise_for_status() bên trong một coroutine sẽ hủy toàn bộ gather và mất mọi kết quả đang xử lý khác. Hai biện pháp bảo vệ:

Biện pháp 1: return_exceptions=True. Để gather ghi lại các ngoại lệ như các giá trị thay vì phát tán chúng. Đường ống hoàn thành theo bất kỳ cách nào; người gọi quyết định sau đó URL nào cần hành động.

Biện pháp 2: danh sách tử thư. Thu thập các URL thất bại trong một cấu trúc riêng biệt để kiểm tra riêng. Xử lý lỗi không gây tắc nghẽn — các đường ống async vẫn sạch sẽ khi các đường dẫn thành công và thất bại không giao thoa với nhau.

python Copy
import asyncio
import json
import aiohttp

async def fetch_safe(session, url):
    try:
        async with session.get(
            url, timeout=aiohttp.ClientTimeout(total=30)
        ) as resp:
            resp.raise_for_status()
            return {"url": url, "html": await resp.text()}
    except (aiohttp.ClientError, asyncio.TimeoutError) as exc:
        return {"url": url, "error": repr(exc)}

async def main(urls):
    async with aiohttp.ClientSession() as session:
        results = await asyncio.gather(
            *(fetch_safe(session, u) for u in urls)
        )

    ok = [r for r in results if "html" in r]
    failed = [r for r in results if "error" in r]
    print(f"Thành công: {len(ok)}   Thất bại: {len(failed)}")

    # Tệp tử thư để kiểm tra riêng — đường ống không bao giờ chặn do lỗi
    with open("dead_letter.jsonl", "w", encoding="utf-8") as f:
        for r in failed:
            f.write(json.dumps(r) + "\n")

Hai điều cần lưu ý:

  • Bao bọc lỗi ({"url": ..., "error": ...}) có cùng hình dạng như bao bọc thành công, chỉ khác với một khóa khác. Người tiêu dùng ở hạ nguồn phân nhánh dựa trên khóa nào có mặt mà không cần phân tích văn bản ngoại lệ.
  • aiohttp.ClientError bao phủ bề mặt lỗi phổ biến (ngắt kết nối, phản hồi không đúng hình thức, vấn đề DNS); asyncio.TimeoutError được phát sinh bởi ClientTimeout. Bắt cả hai bao phủ ~95% các tác vụ scraping async trong thế giới thực.

Điều mà đoạn mã này cố tình không làm: không có gì trong đường dẫn thành công phát hành lại một URL thất bại. Xử lý tử thư thuộc về một lần chạy riêng biệt — với một quốc gia proxy khác, một giới hạn đồng thời khác, hoặc cấp độ trình duyệt đám mây từ Bước 6. Pha trộn nó inline biến một scraper async thành hai luồng điều khiển giao thoa, và các lỗi rơi vào sự giao thoa đó.


Bước 6 — Tăng cường các trang được kết xuất JS lên Scrapeless Scraping Browser

aiohttp trả về bất kỳ byte nào mà nguồn gửi. Đối với các ứng dụng Next.js, React và Vue, các byte đó là một <div id="root"> trống cộng với một thẻ script — nội dung thực tế được vẽ ở phía client. HTTP thông thường không thể kết xuất điều đó; một trình duyệt đám mây có thể.

Mô hình tăng cường sạch nhất: giữ aiohttp trên ~70% các trang xuất bản HTML đã kết xuất, và tăng cường thiểu số được kết xuất bằng JS lên Scrapeless Scraping Browser. SDK Python tạo ra một phiên trình duyệt đám mây và cung cấp một browser_ws_endpoint; API async của Playwright kết nối với nó qua Giao thức DevTools của Chrome:

python Copy
import asyncio
from scrapeless import Scrapeless
from scrapeless.types import ICreateBrowser
from playwright.async_api import async_playwright

async def render_via_cloud_browser(url: str, country: str = "US") -> str:
    client = Scrapeless()  # đọc SCRAPELESS_API_KEY từ env
    session = client.browser.create(
        ICreateBrowser(proxy_country=country, session_ttl=240)
    )

    async with async_playwright() as p:
        browser = await p.chromium.connect_over_cdp(session.browser_ws_endpoint)
        context = browser.contexts[0] if browser.contexts else await browser.new_context()
        page = context.pages[0] if context.pages else await context.new_page()
        await page.goto(url, wait_until="networkidle", timeout=60_000)
        html = await page.content()
        await browser.close()
        return html

Dịch văn bản tiếng Anh sau sang tiếng Việt:

python Copy
async def main():
    # quotes.toscrape.com/js/ là sandbox "cần JS" chính thống.
    # HTTP đơn giản trả về 0 phần tử trích dẫn; được render trên đám mây trả về 10.
    html = await render_via_cloud_browser("https://quotes.toscrape.com/js/")
    print(f"Đã render {len(html):,} ký tự bao gồm DOM sau khi vẽ")

if __name__ == "__main__":
    asyncio.run(main())

session.browser_ws_endpoint là một URL wss://browser.scrapeless.com/...?token=.... connect_over_cdp của Playwright giao tiếp CDP với endpoint đó; việc render diễn ra trên đám mây của Scrapeless, không phải trên máy cục bộ. Bước playwright install chromium trên máy cục bộ chỉ là client giao thức.

session_ttl=240 giữ cho phiên làm việc kéo dài 4 phút — đủ cho một hành trình nhiều bước trên một trang duy nhất. Đối với các lần quét dài hạn, tạo một phiên mới cho từng URL hoặc cho từng đơn vị công việc logic; phiên trên đám mây dễ dàng được tạo ra.


Bước 7 — Ghép tất cả lại với nhau: một scraper bất đồng bộ theo tầng

Hình dáng thực tế của một pipeline scraping bất đồng bộ là HTTP trước, trình duyệt sau: thử aiohttp, nâng cấp các phản hồi rỗng hoặc bị chặn đến Trình duyệt Scraping của Scrapeless. Hai tầng chia sẻ giới hạn đồng thời nhưng sống trong các Semaphore riêng biệt — các phiên trình duyệt đám mây khan hiếm hơn các yêu cầu HTTP.

python Copy
import asyncio
import os
import aiohttp
from scrapeless import Scrapeless
from scrapeless.types import ICreateBrowser
from playwright.async_api import async_playwright

PROXY = (
    f"http://{os.environ['SCRAPELESS_CHANNEL_ID']}-proxy-country_US"
    f":{os.environ['SCRAPELESS_PROXY_PASS']}"
    f"@{os.environ['SCRAPELESS_PROXY_GATEWAY']}:8789"
)
HTTP_LIMIT = asyncio.Semaphore(10)      # tầng aiohttp
BROWSER_LIMIT = asyncio.Semaphore(3)    # tầng trình duyệt đám mây

async def http_fetch(session: aiohttp.ClientSession, url: str) -> str | None:
    async with HTTP_LIMIT:
        try:
            async with session.get(
                url, proxy=PROXY,
                timeout=aiohttp.ClientTimeout(total=30),
            ) as resp:
                resp.raise_for_status()
                return await resp.text()
        except (aiohttp.ClientError, asyncio.TimeoutError):
            return None

async def browser_fetch(client: Scrapeless, url: str) -> str:
    async with BROWSER_LIMIT:
        session = client.browser.create(
            ICreateBrowser(proxy_country="US", session_ttl=240)
        )
        async with async_playwright() as p:
            browser = await p.chromium.connect_over_cdp(session.browser_ws_endpoint)
            context = (
                browser.contexts[0] if browser.contexts
                else await browser.new_context()
            )
            page = await context.new_page()
            await page.goto(url, wait_until="networkidle", timeout=60_000)
            html = await page.content()
            await browser.close()
            return html

from urllib.parse import urlparse

# (a) Các host nặng JS đã biết luôn nâng cấp — tín hiệu đáng tin cậy nhất.
JS_HEAVY_HOSTS = {"quotes.toscrape.com"}

def should_escalate(url: str, html: str | None) -> bool:
    # (a) Trúng danh sách cho phép — host nặng JS rõ ràng.
    if urlparse(url).hostname in JS_HEAVY_HOSTS:
        return True
    # (b) Tín hiệu sau khi phân tích — thân rỗng hoặc shell ứng dụng có thể nhận biết.
    if html is None or len(html) < 2000 or '<div id="root"></div>' in html:
        return True
    return False

async def scrape_one(http_session, client, url):
    html = await http_fetch(http_session, url)
    tier = "http"
    if should_escalate(url, html):
        tier = "browser"
        html = await browser_fetch(client, url)
    return {"url": url, "tier": tier, "html_len": len(html) if html else 0}

async def main(urls):
    client = Scrapeless()
    async with aiohttp.ClientSession() as http_session:
        results = await asyncio.gather(
            *(scrape_one(http_session, client, u) for u in urls)
        )
    return results

if __name__ == "__main__":
    urls = [
        "https://books.toscrape.com/",       # tĩnh — tầng aiohttp
        "https://quotes.toscrape.com/js/",   # JS — nâng cấp
    ]
    print(asyncio.run(main(urls)))

should_escalate kết hợp cả hai tín hiệu mà văn bản đã đề cập: (a) một danh sách cho phép rõ ràng của các host "nặng JS đã biết", và (b) một tín hiệu sau khi phân tích (thân rỗng / shell ứng dụng). Danh sách cho phép là đòn bẩy đáng tin cậy hơn — một shell Next.js hoặc React thường vượt qua ngưỡng 2,000 byte ngay cả khi thân là rỗng, vì vậy việc kiểm tra <div id="root"></div> một mình có thể bỏ lỡ. Kiểm tra hostname xảy ra trước khi đếm bất kỳ byte nào.


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

Pipeline xuất ra một danh sách các dict có hình dạng như sau:

json Copy
[
  {
    "url": "https://books.toscrape.com/",
    "tier": "http",
    "html_len": 51274
  },
  {
    "url": "https://quotes.toscrape.com/js/",
    "tier": "browser",
    "html_len": 9246
  }
]

Những quan sát trung thực từ việc chạy mẫu này:

  • Chi phí kết nối lạnh là thật. Yêu cầu đầu tiên trên một ClientSession mới phải trả phí TLS + DNS; các yêu cầu tiếp theo trên cùng một phiên sẽ tái sử dụng kết nối. Không tái tạo phiên per yêu cầu.
  • Giới hạn đồng thời phụ thuộc vào mục tiêu, không phải trên aiohttp. Năm yêu cầu cho mỗi máy chủ là một điểm khởi đầu an toàn cho các danh mục công cộng; ba yêu cầu thì an toàn hơn cho các nguồn được bảo vệ chống bot; mười yêu cầu là thực tế cho các API thân thiện.
  • Phiên trình duyệt đám mây sống lâu hơn các tải trang đơn. Nếu một quy trình cần đăng nhập cộng với điều hướng cộng với trích xuất, hãy tạo một phiên cho mỗi đơn vị công việc logic và tái sử dụng nó qua các trang trong đơn vị đó — context.new_page() là rẻ trong cùng một phiên.
  • Giải quyết DNS ở lại bên trong aiohttp. Bộ kết nối lưu cache các địa chỉ IP đã giải quyết cho tuổi thọ của ClientSession. Đối với các trình thu thập dữ liệu chạy lâu, tái sử dụng phiên sau vài giờ để DNS không bị lỗi thời.
  • ClientTimeout(total=30) là cho mỗi yêu cầu, không phải cho gather. Một phân tán 1.000 URL không hết thời gian trong 30 giây — mỗi yêu cầu nhận 30 giây ngân sách riêng của nó.

Kết luận: mở rộng các trình thu thập dữ liệu Python bất đồng bộ của bạn

Mô hình bất đồng bộ giảm thành bốn bước: khởi động một ClientSession, giới hạn độ đồng thời bằng một Semaphore, định tuyến phân tán qua các proxy dân cư Scrapeless, và gia tăng số lượng JS-rendered lên Scrapeless Scraping Browser thông qua SDK Python cộng với API bất đồng bộ của Playwright.

Để tìm hiểu sâu hơn về lớp proxy dân cư mà định tuyến mọi việc lấy dữ liệu bất đồng bộ, xem Proxy SSL là gì?.

Ghim kết nối với hậu tố quốc gia trên tên người dùng proxy, giữ Semaphores cho mỗi máy chủ chặt chẽ, phân nhánh theo hình dạng bao bì thành công so với thất bại thay vì bắt lỗi trong dòng, và coi một phản hồi HTTP trống như tín hiệu để gia tăng — không phải là câu trả lời.


Sẵn sàng xây dựng quy trình dữ liệu AI của bạn?

Tham gia cộng đồng của chúng tôi để nhận gói miễn phí và kết nối với các nhà phát triển đang xây dựng các quy trình thu thập dữ liệu bất đồng bộ: Discord · Telegram.

Đăng ký tại Scrapeless để miễn phí thời gian chạy Scraping Browser và áp dụng các mẫu ở trên cho các danh mục, nguồn cấp dữ liệu và khu vực mà quy trình cần. Thông tin về giá cả tại scrapeless.com/en/pricing; proxy dân cư được tài liệu hóa tại scrapeless.com/en/product/proxy-solutions; tài liệu tham khảo SDK đầy đủ tại docs.scrapeless.com.


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

Q1: Tôi nên chạy bao nhiêu yêu cầu đồng thời cho mỗi máy chủ?

Đối với các danh mục công cộng không có stack chống bot, 10 yêu cầu đang diễn ra cho mỗi máy chủ là mức trần an toàn. Đối với các nguồn bảo vệ chống bot, 3 yêu cầu là thực tế hơn. Semaphore là công cụ; bắt đầu từ mức thấp, theo dõi phản hồi 429, và điều chỉnh từ đó.

Q2: Tôi có cần proxy dân cư Scrapeless nếu mục tiêu của tôi không bị chặn từ trung tâm dữ liệu của tôi không?

Đối với các mục tiêu HTTP không bị chặn, không — aiohttp hoạt động mà không cần proxy. Lớp proxy Scrapeless kiếm tiền khi mục tiêu giới hạn địa lý (bạn cần truy cập từ Mỹ/Anh/Nhật), khi IP trung tâm dữ liệu của bạn bị giới hạn tốc độ hoặc bị chặn, hoặc khi bạn cần một IP dân cư mới cho mỗi yêu cầu để phân phối hồ bơi đang diễn ra qua nhiều nguồn.

Q3: Khi nào tôi nên gia tăng từ aiohttp lên Scrapeless Scraping Browser?

Khi HTML mà aiohttp trả về là một shell ứng dụng JS không có nội dung. Heuristic: đếm số lượng các phần tử bạn quan tâm sau khi lấy dữ liệu tầng đầu tiên; nếu số lượng bằng không hoặc thấp hơn nhiều so với mong đợi, trang sẽ được render ở phía client. Tầng trình duyệt đám mây xử lý những điều đó.

Q4: Thu thập dữ liệu bất đồng bộ có hợp pháp không?

Bất đồng bộ là một mẫu vận chuyển; tính hợp pháp phụ thuộc vào những gì bạn thu thập, từ đâu, và theo điều khoản nào. Dữ liệu có thể nhìn thấy công khai thường có thể truy cập được; các khu vực tài phán khác nhau; các điều khoản dịch vụ của trang web áp dụng; hãy tham khảo luật sư cho các trường hợp sử dụng quy mô lớn. Scrapeless chỉ truy cập dữ liệu công khai có sẵn.

Q5: Tôi có thể sử dụng aiohttp mà không cần Scrapeless Scraping Browser không?

Có. Tầng aiohttp (Các bước 3–5) hoạt động như một trình thu thập dữ liệu bất đồng bộ hoàn chỉnh cho bất kỳ mục tiêu nào gửi HTML đã render. Scrapeless Scraping Browser là tầng gia tăng — chỉ được kích hoạt khi tầng HTTP trả về trống.

Q6: Làm thế nào để tôi cố định kết nối ra một quốc gia cụ thể?

Quốc gia được đưa vào tên người dùng proxy dân cư Scrapeless là country_<CC> (mã hai chữ cái in hoa, ngăn cách bằng dấu gạch dưới): country_US, country_UK, country_DE, country_JP. Thay thế phần trong chuỗi tên người dùng và cổng sẽ định tuyến mọi yêu cầu qua các IP dân cư trong quốc gia đó. Đối với các yêu cầu tầng trình duyệt, truyền proxy_country="US" vào ICreateBrowser(...) khi tạo phiên trình duyệt đám mây.

Q7: Tại sao nên sử dụng API bất đồng bộ của Playwright thay vì một client trình duyệt đồng bộ?
Các client trình duyệt đồng bộ chặn vòng lặp sự kiện. Toàn bộ ý nghĩa của asyncio là giữ cho vòng lặp không bị chiếm dụng; việc gọi một page.goto(...) đồng bộ từ bên trong một coroutine sẽ làm tạm dừng mọi tác vụ đang được thực hiện khác. async_playwright của Playwright là tùy chọn Python chính thống duy nhất giữ cho tầng trình duyệt đám mây thân thiện với coroutine. SDK Scrapeless vẫn tạo ra phiên — Playwright chỉ giao tiếp qua CDP với browser_ws_endpoint.

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