🎯 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

Cách Xây Dựng Một Công Cụ Lấy Dữ Liệu Web: Hướng Dẫn Python Từ Đầu

Emily Chen
Emily Chen

Advanced Data Extraction Specialist

29-Jun-2026

Tóm tắt:

  • Một trình thu thập dữ liệu web làm ba điều: lấy một trang, lấy các trường từ HTML, lặp lại cho trang tiếp theo. Khi ba bước này hoạt động trơn tru, mọi trình thu thập mà bạn xây dựng sau đó đều là biến thể của cùng một vòng lặp.
  • requests kết hợp với BeautifulSoup xử lý web tĩnh trong chưa đến 30 dòng. Trên trang thực hành books.toscrape.com, một vòng lặp đi qua tất cả 50 trang danh sách và trả về 1.000 bản ghi sách có cấu trúc.
  • Phân trang chỉ là theo liên kết "tiếp theo" cho đến khi nó không còn xuất hiện. Bạn đọc liên kết trang tiếp theo trên mỗi trang, giải quyết nó thành một URL tuyệt đối và tiếp tục cho đến khi liên kết biến mất.
  • HTTP thông thường không thể thấy nội dung được render bằng JavaScript. Trang thực hành quotes.toscrape.com/js/ trả về không có phần tử nào trên requests, vì mã đánh dấu được vẽ phía khách hàng sau khi trang tải.
  • Scrapeless Scraping Browser render những trang đó ở phía đám mây và trả về DOM đã được vẽ. Trang JavaScript tương tự trả về 10 phần tử trích dẫn khi một trình duyệt đám mây thực thi nó, vì vậy việc phân tích BeautifulSoup hiện tại của bạn vẫn tiếp tục hoạt động không thay đổi.
  • 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 app.scrapeless.com.

Giới thiệu: xây dựng một trình thu thập thực sự, sau đó xử lý các trang chống lại

Mỗi trình thu thập dữ liệu web đều làm ba điều giống nhau: lấy một trang, trích xuất các trường bạn muốn từ HTML, và chuyển sang trang tiếp theo. Thư viện thay đổi, các trang thay đổi, nhưng vòng lặp đó không thay đổi. Hãy học nó một lần trên một trang an toàn để truy cập, và mẫu sẽ chuyển giao cho hầu như bất kỳ thứ gì bạn thu thập sau này.

Sự ma sát xuất hiện sau đó. Trình thu thập đầu tiên mà hầu hết mọi người viết hoạt động hoàn hảo trên một trang HTML tĩnh và sau đó trả về một shell rỗng trên trang web tiếp theo mà họ thử, vì trang web đó render nội dung của nó bằng JavaScript sau phản hồi ban đầu. HTTP thông thường tải xuống các byte mà máy chủ gửi; nó không chạy trang. Vì vậy, dữ liệu bạn có thể thấy trong trình duyệt của bạn không có trong phản hồi mà trình thu thập của bạn nhận được.

Hướng dẫn này xây dựng toàn bộ từ đầu bằng Python. Phần tĩnh sử dụng requests và BeautifulSoup để đối diện với một sandbox thu thập thông tin danh mục sáchmột sandbox thu thập thông tin trích dẫn — hai trang web tồn tại đặc biệt để được thu thập. Sau đó, nó chuyển sang giới hạn thực sự: khi HTTP thông thường trả về một trang rỗng, công việc tăng lên Scrapeless Scraping Browser, một trình duyệt đám mây render trang và trả về cùng một DOM mà bạn sẽ phân tích cục bộ. Nếu bạn muốn làm việc bằng JavaScript, sự phân chia tĩnh và động tương tự được đề cập trong hướng dẫn Cheerio và Puppeteer.


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

  • Thu thập danh mục sản phẩm. Đi qua một danh sách phân trang và lấy tiêu đề, giá và trạng thái kho vào một tập tin CSV hoặc JSON.
  • Theo dõi giá theo thời gian. Chạy lại cùng một trình thu thập theo lịch và so sánh các số để theo dõi sự giảm giá.
  • Xây dựng tập dữ liệu cho phân tích hoặc AI. Biến các trang HTML không cấu trúc thành các hàng sạch mà notebook hoặc mô hình của bạn có thể đọc.
  • Giám sát tình trạng hàng hóa. Kiểm tra xem các mặt hàng có sẵn trên nhiều trang mà không phải nhấp qua chúng bằng tay.
  • Cung cấp cho một quy trình nghiên cứu. Lấy trích dẫn, bài viết hoặc đánh giá vào một cửa hàng có cấu trúc để xử lý hạ nguồn.
  • Truy cập các trang được render bằng JavaScript. Tăng cường các trang trả về một shell rỗng qua HTTP thông thường lên một trình duyệt đám mây và giữ nguyên mã phân tích.

Tại sao lại là Scrapeless Scraping Browser

Scrapeless Scraping Browser là một trình duyệt đám mây tùy chỉnh, 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. Đối với một trình thu thập được xây dựng từ đầu đặc biệt, nó giải quyết vấn đề mà requests không thể — chạy trang — và mang lại:

  • Render JavaScript ở phía đám mây. Các trang vẽ nội dung của chúng ở phía khách hàng trả về một DOM đã được render hoàn chỉnh, vì vậy BeautifulSoup phân tích kết quả chính xác như nó sẽ làm với một trang tĩnh.
  • Proxy dân cư ở hơn 195 quốc gia. Gán địa lý ra ngoài với mã quốc gia để một trang trả về nội dung giống như một khách truy cập địa phương sẽ thấy.
  • Chống phát hiện nhận dạng. Trình duyệt đám mây trình bày một bề mặt trình duyệt giống như con người nhất quán thay vì một chữ ký khách hàng HTTP trống.
  • Một khóa API cho toàn bộ. SDK Python tạo ra một browser_ws_endpoint mà bạn kết nối với Playwright; cùng một khóa覆盖 thời gian chạy.

Lấy khóa API của bạn ở gói miễn phí tại app.scrapeless.com.


Các yêu cầu

  • Python 3.10 hoặc mới hơn
  • requestsbeautifulsoup4 cho phần tĩnh
  • SDK scrapelessplaywright cho phần render bằng JavaScript
  • Một tài khoản và khóa API Scrapeless — đăng ký tại app.scrapeless.com
  • Kiến thức cơ bản về terminal

Cài đặt

Trước tiên, cài đặt hai thư viện tĩnh:

bash Copy
pip install requests beautifulsoup4

requests lấy trang qua HTTP; beautifulsoup4 phân tích HTML trả về — markup được định nghĩa bởi tiêu chuẩn HTML — thành một cây mà bạn có thể truy vấn bằng các bộ chọn CSS. Cặp này là đủ cho mỗi trang tĩnh trong Bước 1 đến 4. Cấp độ được render bằng JavaScript ở Bước 5 sẽ thêm hai gói nữa, được cài đặt ở đó.


Bước 1 — Lấy một trang và xác nhận bạn đã nhận được HTML thực

Một trình thu thập dữ liệu bắt đầu với một yêu cầu. Gửi một GET đến URL mục tiêu theo ngữ nghĩa HTTP, kiểm tra mã trạng thái và xác nhận HTML thực sự chứa các bản ghi mà bạn mong đợi trước khi bạn viết bất kỳ bộ chọn nào.

python Copy
import requests
from bs4 import BeautifulSoup

url = "http://books.toscrape.com/"
resp = requests.get(url, headers={"User-Agent": "Mozilla/5.0 (tutorial-scraper)"}, timeout=30)
print("trạng thái:", resp.status_code, "bytes:", len(resp.text))

soup = BeautifulSoup(resp.text, "html.parser")
books = soup.select("article.product_pod")
print("thẻ sách trên trang này:", len(books))

Trên books.toscrape.com, điều này in ra trạng thái: 200thẻ sách trên trang này: 20. Header User-Agent xác định khách hàng của bạn; nhiều máy chủ từ chối các yêu cầu không gửi. Nếu số lượng trở về bằng không trên một trang thực tế, đó là tín hiệu sớm rằng trang được render bằng JavaScript — tình huống mà Bước 5 sẽ xử lý.


Bước 2 — Khám phá bản ghi, sau đó trích xuất các trường của nó

Chọn container lặp lại trước, sau đó đọc các trường bên trong nó. Ưu tiên một gói ổn định — một thẻ ngữ nghĩa, một thuộc tính data-*, hoặc một lớp mô tả dữ liệu — hơn là một lớp băm mà bị gãy trong thiết kế tiếp theo. Trên books.toscrape.com, mỗi cuốn sách là một article.product_pod, và các trường treo off các bộ chọn con có thể dự đoán.

python Copy
import requests
from bs4 import BeautifulSoup

resp = requests.get(
    "http://books.toscrape.com/",
    headers={"User-Agent": "Mozilla/5.0 (tutorial-scraper)"},
    timeout=30,
)
resp.encoding = resp.apparent_encoding  # danh mục sử dụng £; cho phép requests phát hiện
soup = BeautifulSoup(resp.text, "html.parser")

pod = soup.select_one("article.product_pod")
title = pod.h3.a["title"]
price = pod.select_one("p.price_color").get_text(strip=True)
in_stock = "In stock" in pod.select_one("p.instock.availability").get_text()
print(title, "|", price, "|", "còn hàng" if in_stock else "hết hàng")

Điều này in ra A Light in the Attic | £51.77 | còn hàng. Dòng resp.encoding = resp.apparent_encoding rất quan trọng: nếu không có nó, ký hiệu bảng Anh được giải mã thành mojibake, bởi vì tiêu đề phản hồi và mã hóa thực của tài liệu không tương đồng. Đọc trường từ phần tử đã chứa nó — tiêu đề sống trong thuộc tính title của liên kết, vì vậy một bộ chọn thực hiện cả khám phá và trích xuất.


Bước 3 — Theo dõi phân trang cho đến khi liên kết "tiếp theo" biến mất

Một danh sách hiếm khi vừa một trang. Mô hình đáng tin cậy là đọc liên kết trang tiếp theo trên mỗi trang, giải quyết nó dựa trên URL hiện tại, và lặp cho đến khi không còn liên kết tiếp theo. Không có bộ đếm trang để đoán, không có khoảng cách cứng để duy trì.

python Copy
import requests
from urllib.parse import urljoin
from bs4 import BeautifulSoup

session = requests.Session()
session.headers.update({"User-Agent": "Mozilla/5.0 (tutorial-scraper)"})

records = []
url = "http://books.toscrape.com/catalogue/page-1.html"
pages = 0
while url:
    resp = session.get(url, timeout=30)
    resp.encoding = resp.apparent_encoding
    soup = BeautifulSoup(resp.text, "html.parser")
    for pod in soup.select("article.product_pod"):
        records.append({
            "title": pod.h3.a["title"],
            "price": pod.select_one("p.price_color").get_text(strip=True),
            "in_stock": "In stock" in pod.select_one("p.instock.availability").get_text(),
        })
    pages += 1
    next_link = soup.select_one("li.next > a")
    url = urljoin(url, next_link["href"]) if next_link else None

print("các trang đã thu thập:", pages, "| số bản ghi đã thu thập:", len(records))

Trên books.toscrape.com, điều này đi qua tất cả 50 trang danh sách và thu thập 1,000 bản ghi. Một requests.Session tái sử dụng kết nối cơ sở trên các yêu cầu, nhanh hơn so với một requests.get mới mỗi lần. urljoin biến href tương đối (như page-2.html) thành một URL tuyệt đối để yêu cầu tiếp theo được giải quyết chính xác.

Nhận khóa API của bạn trên gói miễn phí: app.scrapeless.com


Bước 4 — Viết đầu ra có cấu trúc

Dữ liệu thu thập chỉ hữu ích khi nó được cấu trúc. Danh sách records từ Bước 3 đã là một danh sách các từ điển với các khóa nhất quán, vì vậy việc ghi nó ra định dạng CSV hoặc JSON chỉ cần vài dòng. Quyết định sơ đồ của bạn trước — các khóa giống nhau trên mỗi hàng — và các trường không có sẽ trở thành None, không bao giờ gặp lỗi.

python Copy
import csv
import json

# records là danh sách các từ điển được xây dựng trong Bước 3.
with open("books.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["title", "price", "in_stock"])
    writer.writeheader()
    writer.writerows(records)

with open("books.json", "w", encoding="utf-8") as f:
    json.dump(records, f, ensure_ascii=False, indent=2)

print("đã ghi", len(records), "hàng vào books.csv và books.json")

Đó là một trình thu thập hoàn chỉnh, hoạt động: lấy dữ liệu, khám phá, trích xuất, phân trang, lưu trữ. Nó sẽ xử lý bất kỳ trang HTML tĩnh nào với các bộ chọn được thay thế bởi đánh dấu của trang đó.


Nơi HTTP đơn giản dừng lại: Các trang được render bằng JavaScript

Trình thu thập ở trên sẽ bị hỏng ngay khi một trang web render nội dung của nó bằng JavaScript. Trang thực hành quotes.toscrape.com/js/ được xây dựng cho đúng bài học này — các câu trích dẫn được tiêm bởi một kịch bản sau khi trang tải, không có trong HTML ban đầu.

python Copy
import requests
from bs4 import BeautifulSoup

resp = requests.get("https://quotes.toscrape.com/js/",
                    headers={"User-Agent": "Mozilla/5.0"}, timeout=30)
soup = BeautifulSoup(resp.text, "html.parser")
print("bytes:", len(resp.text), "| số phần tử trích dẫn:", len(soup.select("div.quote")))

Điều này trả về bytes: 5806số phần tử trích dẫn: 0. Yêu cầu đã thành công — trạng thái 200, thực sự có byte — nhưng trang đã phân tích không có câu trích dẫn nào, vì requests không bao giờ thực thi JavaScript tạo ra chúng. Không có thay đổi bộ chọn nào sửa được điều này; dữ liệu thực sự không có trong phản hồi. Trang phải được chạy bởi một trình duyệt.


Bước 5 — Render trang với Scrapeless Scraping Browser

Chạy một trình duyệt hoàn chỉnh cục bộ cho mỗi trang là nặng nề và nhanh chóng bị chặn. Con đường sạch hơn là một trình duyệt đám mây: Scrapeless tạo một phiên, render trang ở bên của nó, và trả lại DOM hoàn chỉnh — mà bạn phân tích bằng cùng mã BeautifulSoup mà bạn đã viết. Cài đặt hai gói bổ sung, sau đó kết nối với Playwright qua Giao thức DevTools của Chrome.

bash Copy
pip install scrapeless playwright
playwright install chromium

playwright install chromium tải xuống một client giao thức cục bộ một lần; việc render thực sự vẫn chạy trong đám mây của Scrapeless. Xuất khóa của bạn trước (export SCRAPELESS_API_KEY=your_api_token_here), sau đó:

python Copy
from scrapeless import Scrapeless
from scrapeless.types import ICreateBrowser
from playwright.sync_api import sync_playwright
from bs4 import BeautifulSoup

client = Scrapeless()  # đọc SCRAPELESS_API_KEY từ môi trường
session = client.browser.create(
    ICreateBrowser(proxy_country="US", session_ttl=180)
)

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(session.browser_ws_endpoint)
    ctx = browser.contexts[0] if browser.contexts else browser.new_context()
    page = ctx.pages[0] if ctx.pages else ctx.new_page()
    page.goto("https://quotes.toscrape.com/js/", wait_until="domcontentloaded", timeout=60_000)
    page.wait_for_timeout(4_000)  # để kịch bản phía client vẽ các câu trích dẫn
    html = page.content()
    browser.close()

soup = BeautifulSoup(html, "html.parser")
quotes = soup.select("div.quote")
print("bytes đã render:", len(html), "| số phần tử trích dẫn:", len(quotes))
print(quotes[0].select_one("small.author").get_text(strip=True))

Điều này trả về bytes đã render: 9246số phần tử trích dẫn: 10, và in ra Albert Einstein — cùng trang mà bạn nhận được số 0 qua HTTP đơn giản. session.browser_ws_endpoint là URL wss://browser.scrapeless.com/...; connect_over_cdp của Playwright giao tiếp với Giao thức DevTools, vì vậy trang chạy trên đám mây trong khi mã của bạn chạy cục bộ. wait_until="domcontentloaded" cộng với một thời gian cố định ngắn thì đáng tin cậy hơn là chờ đợi tình trạng mạng đang rỗi trên một trang được điều khiển bởi script. SDK và bề mặt CLI được tài liệu hóa tại docs.scrapeless.com.


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

Một khi trình duyệt đám mây trả về HTML đã render, việc phân tích giống hệt như tầng tĩnh — cùng bộ chọn, cùng hình dạng từ điển:

json Copy
[
  {
    "text": "Thế giới như chúng ta đã tạo ra nó là một quá trình của suy nghĩ của chúng ta.",
    "author": "Albert Einstein",
    "tags": ["thay đổi", "những suy nghĩ sâu sắc", "suy nghĩ", "thế giới"]
  }
]
// Sơ đồ phản ánh chính xác những gì phân tích div.quote phát ra. Các giá trị chỉ là ví dụ minh họa.

Một vài quan sát chân thật về các trang đã render:

  • Thời gian quan trọng trên các trang đã được hiển thị. Các trích dẫn chỉ xuất hiện sau khi kịch bản của trang chạy, vì vậy khoảng thời gian ngắn sau domcontentloaded là yếu tố giúp chúng hiện ra. Quá ngắn và bạn sẽ phân tích một trang trống.
  • Các bộ chọn vẫn có thể thay đổi. div.quote, span.text, và small.author là đánh dấu của sandbox này; trên một trang thực, hãy kiểm tra lại các bộ chọn khi trang thay đổi.
  • Các trường không có là điều bình thường. Một bản ghi có thể thiếu một thẻ hoặc một giá; hãy coi mọi trường là có thể null và trình ghi của bạn sẽ tiếp tục tạo ra các dòng sạch.
  • Xác định địa điểm xuất phát của bạn. proxy_country="US" giữ cho nội dung đã được hiển thị nhất quán với một người dùng từ Mỹ; chuyển mã để phù hợp với khu vực bạn cần.

Kết luận: từ một trang đến một đường ống thực

Một trình thu thập thông tin hoạt động giảm xuống bốn bước: lấy trang, phát hiện bản ghi lặp lại, trích xuất các trường của nó, và theo dõi phân trang cho đến khi kết thúc. Điều này bao phủ web tĩnh với requests và BeautifulSoup. Trường hợp mà nó không thể tiếp cận — các trang xây dựng nội dung của chúng bằng JavaScript — tăng lên một cách ngăn nắp đến Scrapeless Scraping Browser, mà hiển thị trang ở phía đám mây và trả lại cùng một DOM mà trình phân tích của bạn đã hiểu.

Từ đây, mở rộng nó theo cách mà mọi trình thu thập thông tin sản xuất mở rộng: giữ cho các bộ chọn của bạn chặt chẽ và kiểm tra lại chúng khi đánh dấu thay đổi, xác định địa lý xuất phát phù hợp với khán giả mà trang phục vụ, coi các trường không có là có thể null, và chỉ sử dụng trình duyệt đám mây đối với các trang thực sự cần hiển thị. Đối với sự phân chia tương tự trong JavaScript, hướng dẫn Cheerio và Puppeteer dẫn dắt quyết định tĩnh và động trong Node.js. So sánh các tùy chọn chạy tại trang giá cả khi bạn sẵn sàng chạy nó với khối lượng lớn.


Sẵn sàng để Xây dựng Đường Ống Dữ Liệu do AI Cung Cấp?

Tham gia cộng đồng của chúng tôi để nhận kế hoạch miễn phí và kết nối với các nhà phát triển đang xây dựng các đường ống thu thập thông tin: Discord · Telegram.

Đăng ký tại app.scrapeless.com để nhận runtime Scraping Browser miễn phí và điều chỉnh các mẫu ở trên cho các trang web, trang, và khu vực mà trình thu thập thông tin của bạn cần.


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

Q: Thu thập dữ liệu web có hợp pháp không?
Việc thu thập dữ liệu có thể nhìn thấy công khai thường được phép ở nhiều khu vực pháp lý, nhưng các quy định khác nhau theo quốc gia và theo trang web. Xem xét Điều khoản Dịch vụ của trang web mục tiêu và Giao thức loại trừ Robot, tránh dữ liệu cá nhân hoặc dữ liệu có cổng, và tham khảo ý kiến luật sư cho bất kỳ điều gì thương mại. Các trang web trong hướng dẫn này tồn tại cụ thể để được thu thập.

Q: Tôi có cần một proxy để xây dựng một trình thu thập thông tin không?
Đối với một trình thu thập thông tin với khối lượng thấp đối với một trang web cho phép, không. Đối với các trang web giới hạn tần suất theo IP hoặc thay đổi nội dung theo khu vực, có — định tuyến qua các proxy nhà ở và cố định quốc gia để trang trả về nội dung mà một người dùng địa phương sẽ thấy. Cấp độ Scraping Browser trong Bước 5 bao gồm đầu ra proxy với cài đặt proxy_country.

Q: Tại sao trình thu thập thông tin của tôi lại trả về một trang trống?
Hầu hết thời gian là vì trang hiển thị nội dung của nó bằng JavaScript sau khi phản hồi ban đầu. Các lệnh gọi giản đơn requests tải byte của máy chủ nhưng không bao giờ chạy các kịch bản của trang, vì vậy dữ liệu bạn thấy trong trình duyệt không có trong phản hồi. Xác nhận bằng cách in ra số lượng phần tử, như trong phần "Nơi mà HTTP giản đơn dừng lại", sau đó hiển thị trang với một trình duyệt đám mây.

Q: Tôi nên làm gì khi gặp một trang hiển thị "Truy cập Bị từ chối" hoặc một trang thách thức?
Đó là một kiểm tra chống bot trên yêu cầu. Hiển thị trang thông qua Scrapeless Scraping Browser với đầu ra nhà ở của Mỹ được cố định, và khởi động phiên làm việc bằng cách tải trang chính của trang web trước trong cùng một phiên trình duyệt trước khi truy cập trang mục tiêu, để yêu cầu mang lại bề mặt trình duyệt giống người.

Q: Các bộ chọn của tôi đã ngừng hoạt động sau khi thiết kế lại — tôi nên làm gì bây giờ?
Đánh dấu có thể thay đổi. Kiểm tra lại trang, ưa thích các móc ổn định (thẻ ngữ nghĩa, thuộc tính data-*, lớp mô tả dữ liệu) hơn các lớp CSS đã mã hóa, và cập nhật các bộ chọn. Xây dựng dựa trên móc bền vững nhất có sẵn giữ cho trình thu thập thông tin sống lâu hơn giữa các lần sửa đổi.

Q: Tôi có thể thu thập bao nhiêu trang song song?
Giữ cho độ song song ở mức vừa phải — khoảng ba công nhân mỗi máy chủ là một tường hợp hợp lý cho một trang web duy nhất, để bạn duy trì trong giới hạn yêu cầu tôn trọng và tránh rơi vào giới hạn tần suất. Các phiên trình duyệt đám mây hiếm hơn các yêu cầu HTTP, vì vậy hãy giới hạn chúng chặt chẽ hơn so với các lần tải tĩnh của bạn.

Q: Tôi có phải sử dụng trình duyệt cho mọi thứ không?
Không, và bạn không nên. Cấp độ tĩnh với requests và BeautifulSoup nhanh hơn và rẻ hơn, vì vậy hãy sử dụng nó cho mọi trang gửi HTML đã được xử lý. Chỉ nâng cấp lên trình duyệt đám mây cho những trang thực sự cần thực thi JavaScript.

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