Cách tạo và triển khai một công cụ thu thập dữ liệu web chứng khoán: Hướng dẫn thực tiễn
TL;DR
Dự án này thu thập OHLCV hàng ngày thông qua một API dữ liệu thị trường đã được tài liệu, xác thực các bản ghi, và cập nhật chúng vào SQLite.
Tệp đính kèm chạy mà không cần thông tin xác thực và chứa giá tổng hợp, không phải quan sát thị trường.
Ngày tháng đại diện cho các phiên giao dịch; thời gian truy xuất, tiền tệ, sàn giao dịch, và cơ sở điều chỉnh là các trường riêng biệt.
Triển khai sử dụng một container Docker một lần và một lịch trình bên ngoài, với một cơ sở dữ liệu lâu dài và bí mật bên ngoài hình ảnh.
Truy cập API trực tiếp, quyền dữ liệu thị trường, và việc triển khai container cần được xác thực trong môi trường của bạn. Tệp đính kèm địa phương không chứng minh quyền lợi sống hoặc tính mới trong thời gian thực.
Những Gì Bạn Sẽ Xây Dựng: Một Trình Thu Thập Dữ Liệu Thị Trường Chứng Khoán
Bạn sẽ xây dựng một trình thu thập dữ liệu thị trường hàng ngày: biểu tượng → API được hỗ trợ → xác thực → SQLite → làm mới theo lịch trình. Cấu trúc kỹ thuật tương tự có thể hỗ trợ một nguồn HTML được ủy quyền, nhưng một API đã được tài liệu tránh được các trình chọn trang báo giá dễ bị hỏng.
Hướng dẫn sử dụng hợp đồng TIME_SERIES_DAILY đã được tài liệu của Alpha Vantage. Đây là các thanh hàng ngày thô chứ không phải giá có thể thực thi ngay lập tức hoặc một chuỗi tổng lợi nhuận tự động điều chỉnh. Dữ liệu có thể bị trễ hoặc lịch sử tùy thuộc vào quyền lợi nguồn; dự án này không phải là một chuỗi cung cấp giao dịch.
Các Yêu Cầu và Thiết Lập Dự Án
Sử dụng Python 3.12, tệp kịch bản và tệp đính kèm được cung cấp, và Docker nếu bạn muốn con đường triển khai. Dự án Python chỉ sử dụng thư viện tiêu chuẩn.
Trải nghiệm Nstproxy Crawl - Bắt Đầu Dùng Thử Miễn Phí Hôm Nay
project/
Tệp yêu cầu có thể chứa một bình luận nêu rằng không có phụ thuộc thời gian chạy bên thứ ba. Một lần chạy trực tiếp cần một khóa API Alpha Vantage đã được chấp thuận và một giấy phép dữ liệu cho phép bạn sử dụng.
Chọn Một Nguồn Dữ Liệu Chứng Khoán Đáng Tin Cậy
Chọn nguồn bằng quyền lợi, phạm vi sàn giao dịch, định nghĩa phiên giao dịch, điều chỉnh, ngân sách tỷ lệ, và quyền sử dụng. Một nguồn mà tốt cho nghiên cứu hàng ngày nội bộ có thể không cho phép phân phối lại hoặc hiển thị theo thời gian thực.
APIs Thị Trường Chứng Khoán so với Thu Thập Dữ Liệu Từ Website
Một API có giấy phép thông thường cung cấp một hình dạng dữ liệu đã được tài liệu và lỗi. Một trang báo giá công khai có thể tải dữ liệu một cách động, hiển thị các giá trị bị trễ, và áp đặt các hạn chế truy cập riêng biệt.
Tài liệu Alpha Vantage xác định các trường chuỗi hàng ngày và tham số API. Điều khoản của nó phân biệt quyền sử dụng; đừng giả định rằng một điểm cuối có thể truy cập cho phép phân phối thương mại.
Hiểu Các Trường Dữ Liệu Chứng Khoán
Trường
Ý nghĩa trong dự án này
Mối quan tâm xác thực
Biểu tượng và sàn giao dịch
Danh tính công cụ cụ thể nguồn
Cùng một mã ngắn có thể xác định các công cụ khác nhau
Ngày phiên giao dịch
Ngày giao dịch gắn với thanh hàng ngày
Không phải ngày truy xuất UTC
Mở/cao/thấp/đóng
Giá phiên thô
Dương, hữu hạn, nhất quán nội bộ
Khối lượng
Đơn vị báo cáo cho công cụ/phiên giao dịch
Không âm; định nghĩa đơn vị phụ thuộc vào nguồn
Tiền tệ
Siêu dữ liệu công cụ được cung cấp rõ ràng
Không suy diễn chỉ từ một biểu tượng
Cơ sở
raw_daily
Giữ tách biệt với dữ liệu đã điều chỉnh chia/cổ tức
Quan sát tại
Dấu thời gian UTC của trình thu thập
Theo dõi tính mới của việc thu thập
Số học thập phân tránh những thay đổi nhị phân không cần thiết đối với giá được lưu trữ. Giá trị tiền tệ và sàn giao dịch là cấu hình trong bản demo; hãy xác thực chúng từ master công cụ sản xuất của bạn.
Bước 1: Tạo Dự Án Trình Thu Thập Dữ Liệu Python
Sao chép các tệp mã được cung cấp vào một thư mục, tạo một môi trường ảo, và chạy tệp đính kèm trước tiên.
Tệp đính kèm có hai thanh tự tạo dưới một hình dạng API. Giá trị của nó không bao giờ được trộn lẫn với một tập dữ liệu thị trường nghiên cứu hoặc sản xuất.
Bước 2: Lấy Dữ Liệu Chứng Khoán Từ Nguồn
Trình thu thập gửi một biểu tượng rõ ràng, hàm, kích thước đầu ra, loại dữ liệu, và khóa API. Nó áp dụng một khoảng thời gian chờ, xử lý các lỗi HTTP tạm thời đủ điều kiện, và tránh ghi lại các URL chứa thông tin xác thực.
Sau khi xác nhận quyền lợi của bạn, hãy chạy:
python stock_scraper.py --live--symbol IBM \--currency USD --exchange YOUR_VERIFIED_EXCHANGE --db stocks.sqlite
Không có cuộc gọi có thông tin xác thực sống nào được thực hiện cho bài viết này. Toàn bộ triển khai này được bao gồm trong gói:
"""Bộ thu thập OHLCV hàng ngày. Thực thi mặc định yêu cầu một tệp đính kèm địa phương rõ ràng."""import argparse
import json
import logging
import os
import re
import sqlite3
import time
from datetime import date, datetime, timezone
from decimal import Decimal
from pathlib import Path
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode
from urllib.request import Request, urlopen
deffetch(symbol):key = os.environ["ALPHAVANTAGE_API_KEY"] query = urlencode(dict(function="TIME_SERIES_DAILY", symbol=symbol, outputsize="compact", datatype="json", apikey=key))for attempt inrange(3):try: request = Request("https://www.alphavantage.co/query?"+ query, headers={"User-Agent":"DailyDataCollector/1.0"})with urlopen(request, timeout=30)as response:return json.load(response)except HTTPError as exc:# Never print exc or its URL: the query contains the API key.if exc.code notin(429,502,503,504)or attempt ==2:raise RuntimeError(f"Source HTTP failure: {exc.code}")fromNone delay = exc.headers.get("Retry-After","")if delay:# Schedule a later run; never retry earlier than requested.raise RuntimeError("Rate limited; reschedule using Retry-After")fromNoneexcept(URLError, TimeoutError):if attempt ==2:raise RuntimeError("Source unavailable after three attempts")fromNone time.sleep(2** attempt)defnormalize(payload, symbol, currency, exchange):ifnot re.fullmatch(r"[A-Z]{3}", currency)ornot exchange.strip():raise ValueError("Cung cấp mã tiền tệ và mã sàn đã được xác thực")if payload.get("Meta Data",{}).get("2. Symbol","").upper()!= symbol.upper():raise ValueError("Thiếu hoặc không khớp mã nhà cung cấp") series = payload.get("Time Series (Daily)")ifnotisinstance(series,dict)ornot series:raise ValueError("Không có thanh hàng ngày; kiểm tra giới hạn tài khoản hoặc lỗi nguồn") observed = datetime.now(timezone.utc).isoformat() rows =[]for session, bar insorted(series.items()): date.fromisoformat(session) prices =[Decimal(bar[f"{i}. {name}"])for i, name in((1,"mở cửa"),(2,"cao nhất"),(3,"thấp nhất"),(4,"đóng cửa"))]ifany(not p.is_finite()or p <=0for p in prices):raise ValueError(f"OHLC không hợp lệ: {session}") opening, high, low, close = prices
if low >min(opening, close)or high <max(opening, close)or low > high:raise ValueError(f"Nến không đồng nhất: {session}") volume =int(bar["5. volume"])if volume <0:raise ValueError("Khối lượng âm") rows.append((symbol, exchange, currency,"raw_daily", session,*(str(p)for p in prices), volume,"alpha_vantage", observed))return rows
defsave(rows, database):with sqlite3.connect(database)as db: db.execute("""CREATE TABLE IF NOT EXISTS bars(
symbol TEXT, exchange TEXT, currency TEXT, basis TEXT, session_date TEXT,
open TEXT, high TEXT, low TEXT, close TEXT, volume INTEGER,
source TEXT, observed_at TEXT,
PRIMARY KEY(symbol,exchange,currency,basis,session_date))""") db.executemany("""INSERT INTO bars VALUES(?,?,?,?,?,?,?,?,?,?,?,?)
ON CONFLICT(symbol,exchange,currency,basis,session_date) DO UPDATE SET
open=excluded.open,high=excluded.high,low=excluded.low,
close=excluded.close,volume=excluded.volume,observed_at=excluded.observed_at
""", rows)defmain(): parser = argparse.ArgumentParser() parser.add_argument("--symbol", default="IBM") parser.add_argument("--currency", required=True) parser.add_argument("--exchange", required=True) parser.add_argument("--fixture") parser.add_argument("--live", action="store_true") parser.add_argument("--db", default="stocks.sqlite") args = parser.parse_args()ifbool(args.fixture)== args.live: parser.error("Chọn chính xác một trong hai --fixture hoặc --live") payload = json.loads(Path(args.fixture).read_text())if args.fixture else fetch(args.symbol) rows = normalize(payload, args.symbol, args.currency, args.exchange) save(rows, args.db) logging.info("accepted_bars=%s latest_session=%s",len(rows), rows[-1][4])if __name__ =="__main__": logging.basicConfig(level=logging.INFO,format="%(levelname)s %(message)s")try: main()except(ValueError, KeyError, RuntimeError, OSError)as exc: logging.error("collector_failed: %s",type(exc).__name__)raise SystemExit(1)
Kích thước phản hồi compact là có chủ đích. Nó giới hạn một lần chạy và hỗ trợ cập nhật lặp lại; nó không loại bỏ nhu cầu điều chỉnh các sửa đổi lịch sử bên ngoài khoảng thời gian đó.
Bước 3: Phân Tích và Xác Thực Giá Cổ Phiếu
Trình phân tích từ chối các ký hiệu không khớp, chuỗi vắng mặt, ngày không hợp lệ, giá trị OHLC không hữu hạn hoặc không dương, phạm vi nến không nhất quán, và khối lượng âm. Nó phân biệt một phiên hợp lệ trước đó với một lần lấy dữ liệu thất bại.
Do not write the retrieval date as the market session date. If the source has not published a new bar because the exchange is closed, preserve the previous accepted session and report its age in context.
For splits and dividends, select a separate adjusted-data contract if your analysis needs it. Mixing raw and adjusted closes can create artificial “price changes.”
Step 4: Save Stock Data to CSV or SQLite
SQLite stores one row per symbol, exchange, currency, basis, and session date. Repeated ingestion updates the existing bar rather than creating duplicates.
The collector preserves observed_at separately. For correction auditing, extend the design with an append-only source revision table; the compact example keeps the latest accepted values.
Export a report after collection if required:
import csv
import sqlite3
with sqlite3.connect("stocks.sqlite")as db: cursor = db.execute("SELECT * FROM bars ORDER BY symbol, session_date")withopen("stocks.csv","w", newline="")as handle: writer = csv.writer(handle) writer.writerow([column[0]for column in cursor.description]) writer.writerows(cursor)
Retries are capped and limited to transient failures. A Retry-After response causes the collector to stop and request rescheduling instead of retrying earlier than allowed. JSON-level account or quota messages fail validation even if HTTP status is 200.
Log accepted bars, latest session, elapsed time, and a redacted error category. Never log the full request URL, API token, or secret environment contents. Preserve the last accepted dataset if the latest run fails.
Step 6: Schedule Automatic Stock Data Updates
For daily data, schedule after the provider is expected to publish the completed session, with a timezone-aware exchange calendar. A weekday cron alone does not know exchange holidays or daylight-saving changes.
This illustrative host schedule starts a run at 23:15 in the host's configured timezone:
15 23 * * 1-5 /opt/stock/run-collector.sh
Adjust timing to your entitlement and exchange. Avoid overlapping jobs with a scheduler lock, and alert if the expected latest session is still absent after the publication window.
Step 7: Deploy the Scraper to Production
Use a scheduled one-shot deployment. Successful process exit means the configured collection completed; the external scheduler owns the next execution.
Dockerize the Stock Scraper
The supplied image runs as a non-root user and writes data to a mounted directory.
Docker was not available for a container build in this authoring environment; these are deployment instructions, not a claim of a successful remote deployment.
Configure Environment Variables and Secrets
Place only the required API key in a permission-restricted environment file or a secret store. Keep it outside the image build context and repository. The supplied .dockerignore excludes environment files and databases.
Use a separate test credential and database during deployment checks. Rotate a key if it is exposed in logs or a committed file.
Set Up Scheduling and Monitoring
For price-monitoring operations, monitor process exit status, last successful run, latest expected session, accepted-row count, and database accessibility. Keep provider outage alerts distinct from market closure.
Do not attach a permanent restart loop to a one-shot successful job. Let the scheduler retry eligible failures with an explicit budget and an overlap lock.
Testing the Deployed Stock Scraper
The local fixture check verifies two accepted bars, invalid-bar rejection, and no extra rows after an identical re-run. It does not verify source authorization, live prices, Docker, or VPS persistence.
On your deployment, verify the mounted database survives container replacement; a secret is available only at runtime; a repeated job is idempotent; quota errors produce a nonzero exit; and backup restoration works.
Scaling from One Stock to Hundreds of Tickers
Tính toán ngân sách yêu cầu của bạn trước khi thêm độ đồng thời. Áp dụng kiểm soát yêu cầu sản xuất và ưa tiên các giao diện lô hỗ trợ khi có sẵn, lưu trữ lịch sử không thay đổi, phân bổ công việc, và duy trì một danh sách công cụ đã được xác minh.
Phân vùng trạng thái theo công cụ và phiên. Giữ lại tiến trình một phần để một ký hiệu không thành công không lặp lại mỗi yêu cầu thành công. Một vòng lặp lớn trên một quyền nhỏ sẽ tạo ra các lỗi hạn mức thay vì thông lượng có thể sử dụng.
Các Vấn Đề và Giải Pháp Khi Thu Thập Dữ Liệu Cổ Phiếu
JSON rỗng có thể là thông điệp giới hạn tài khoản, không phải là một thị trường rỗng. Một thanh không còn hoạt động có thể là một ngày lễ, một công cụ bị hoãn, độ trễ xuất bản, hoặc một yêu cầu không thành công; kiểm tra chứng cứ đúng.
Các bước nhảy bất ngờ có thể đến từ việc tách cổ phiếu, thay đổi tiền tệ, tái sử dụng ký hiệu, hoặc trộn nguyên liệu/điều chỉnh. Xác thực sự kiện và danh tính công cụ trước khi phát hành báo cáo bất thường.
Chi Phí và Cân Nhắc Pháp Lý Khi Thu Thập Dữ Liệu Cổ Phiếu
Ngân sách truy cập dữ liệu, quyền phân phối hoặc hiển thị, tính toán, lưu trữ, sao lưu, giám sát, và bảo trì. Chỉ riêng thông tin xác thực API không thiết lập tất cả quyền sử dụng.
Nếu bạn sử dụng Nstdata Crawl cho một trang web tài chính được ủy quyền, hãy coi đây là hạ tầng thu mua. Đây không phải là một nguồn cấp dữ liệu thị trường dữ liệu được ủy quyền hay một sự thay thế cho việc xác thực dữ liệu tài chính.
Bắt đầu với thiết bị, xác nhận siêu dữ liệu công cụ, xem xét quyền đối với nguồn, xác thực phản hồi tài khoản trực tiếp, kiểm tra tính bền vững của lưu trữ, và cấu hình giám sát nhận thức về lịch. Chuyển sang nhiều công cụ chỉ sau khi một lần chạy đã được lên lịch xử lý thành công và thất bại một cách chính xác.
Xác Thực Các Nguồn Trang Được Phê Duyệt
Kiểm tra nội dung trang web được phép tách biệt ra khỏi các nguồn cấp dữ liệu thị trường dữ liệu đã cấp phép.
H: Tôi có thể thu thập giá cổ phiếu bằng Python không?
Có, thông qua một API được ủy quyền hoặc nguồn được phép. Hướng dẫn này sử dụng một hợp đồng API dữ liệu hàng ngày được tài liệu hóa và một thiết bị cục bộ.
H: Tôi có thể sử dụng Yahoo Finance thay vào đó không?
Sử dụng quyền truy cập hiện tại và các thỏa thuận cấp phép dữ liệu của nó thay vì giả định một trang công cộng cho phép tự động hóa hoặc phân phối không giới hạn.
H: Ví dụ có phải là thời gian thực không?
Không. Nó thu thập các thanh hàng ngày; độ tươi mới phụ thuộc vào quyền của nhà cung cấp và xuất bản.
H: Tại sao bản demo yêu cầu tiền tệ và sàn giao dịch?
Phản hồi được chọn không phải là một danh sách công cụ hoàn chỉnh. Bộ thu thập tránh đoán các trường đó từ một mã chứng khoán.
H: Cập nhật nên chạy bao lâu một lần?
Phù hợp với quyền nguồn và khoảng thời gian dữ liệu dự kiến. Các yêu cầu thanh hàng ngày thường xuyên hơn không biến tập dữ liệu thành nguồn cấp dữ liệu trực tiếp.
H: Điều gì chứng minh việc triển khai hoạt động?
Các kiểm tra chấp nhận có chứng thực, lưu trữ bền vững, chạy lại idempotent, độ tươi mới phiên giao dịch thị trường chính xác, và hồi phục lỗi quan sát được trong môi trường của bạn.
Lena Zhou
Oct. 19th 2026
Thu thập toàn bộ trang web chỉ với một yêu cầu API
Chuyển mọi trang web thành Markdown, HTML, JSON, liên kết, PDF và hơn thế nữa mà không cần quản lý hạ tầng thu thập dữ liệu.
Tỷ lệ thành công 99,8% với kết xuất JavaScript
Nhận dữ liệu sạch, sẵn sàng cho LLM ở nhiều định dạng