อัปเดตล่าสุด: 30 ตุลาคม 2026

การติดตามราคาอีคอมเมิร์ซด้วย Playwright และพร็อกซีที่อยู่อาศัย

ราคาที่แสดงของสินค้าไม่ได้เป็นค่าเดียวสากลเสมอไป ร้านออนไลน์อาจแสดงข้อมูลต่างกันตามหน้าสินค้า สกุลเงิน จุดจัดส่ง โลเคิลของเบราว์เซอร์ คุกกี้ หรือบัญชีที่ลงชื่อเข้าใช้

ดังนั้นการติดตามราคาจึงไม่ใช่แค่การอ่านตัวเลขจาก HTML ระบบติดตามที่มีประโยชน์ต้องบันทึกเงื่อนไขที่ตรวจสอบหน้าด้วย—และแยกการสังเกตราคาจริงออกจากคำขอหรือการดึงข้อมูลที่ล้มเหลว

ในบทช่วยสอนนี้ เราจะสร้างตัวติดตาม Python ขนาดเล็กด้วย Playwright มันเปิดแคตตาล็อกสินค้า จับชื่อสินค้า ราคาที่แสดง และความพร้อมจำหน่าย แล้วบันทึก JSON และ CSV พร้อมเวลาประทับ พร็อกซีที่อยู่อาศัยเป็นตัวเลือก: มันเปลี่ยนเส้นทางเครือข่ายที่เบราว์เซอร์ใช้ แต่ไม่ได้ตั้งประเทศจัดส่ง สกุลเงิน หรือสถานะบัญชีของร้านโดยอัตโนมัติ

ขอบเขตของเดโมนี้: ตัวอย่างใช้ Books to Scrape ซึ่งเป็นเว็บฝึกหัดที่ราคาถูกกำหนดแบบสุ่มและไม่มีนัยยะในโลกจริง เหมาะสำหรับเรียนรู้เวิร์กโฟลว์การติดตาม ไม่ใช่การพิสูจน์ความต่างของราคาตามภูมิภาค หากต้องการศึกษาความต่างของตลาดจริง ให้ใช้สโตร์ฟรอนต์ที่คุณได้รับอนุญาตให้เข้าถึงและเปลี่ยนข้อมูลที่แสดงตามตลาดจริงๆ

เมื่อไหร่ควรใช้ Playwright?

ใช้ API สินค้าหรือฟีดข้อมูลอย่างเป็นทางการก่อน หากให้ข้อมูลและขอบเขตที่คุณต้องการ โดยทั่วไปจะเสถียรและดูแลรักษาง่ายกว่าการทำงานอัตโนมัติของเบราว์เซอร์

Playwright มีประโยชน์เมื่อ:

  • ข้อมูลสินค้าที่เกี่ยวข้องถูกเรนเดอร์ด้วย JavaScript;
  • คุณต้องตรวจสอบเนื้อหาที่เบราว์เซอร์ได้รับจริง;
  • ความพร้อมจำหน่ายหรือราคาที่มองเห็นบนสโตร์ฟรอนต์ไม่ได้เปิดผ่านฟีดที่เหมาะสม

สำหรับหน้าสถิต ไคลเอนต์ HTTP ธรรมดาอาจง่ายและเร็วกว่า คู่มือนี้เน้นการรันเบราว์เซอร์ครั้งเดียวและบริบทการทดสอบที่กำหนดค่าแล้ว ไม่ใช่ตัวจัดตารางหลายประเทศพร้อมใช้

สำหรับการวางแผนที่กว้างขึ้น ดู คู่มือติดตามราคาอีคอมเมิร์ซ หากต้องการความช่วยเหลือในการตั้งค่าพร็อกซีใน Playwright ดู วิธีใช้พร็อกซีที่อยู่อาศัยกับ Playwright

ระเบียนติดตามราคาควรมีอะไรบ้าง?

การสังเกตราคามีประโยชน์เมื่อคุณเข้าใจว่าเก็บมาอย่างไร เป็นอย่างน้อย ให้บันทึก:

ฟิลด์ทำไมสำคัญ
ชื่อสินค้าและ URLระบุรายการที่กำลังติดตาม
เวลาประทับ UTCระบุว่าสังเกตเมื่อใด
ป้ายตลาดอธิบายการตั้งค่าการทดสอบ ไม่ใช่หลักฐานตำแหน่ง IP
IP ทางออกพร็อกซีช่วยวินิจฉัยเส้นทางเครือข่าย หากใช้พร็อกซี
โลเคิลและโซนเวลาของเบราว์เซอร์บันทึกการตั้งค่าเบราว์เซอร์ที่อาจส่งผลต่อการแสดงหน้า
ประเทศจัดส่งบันทึกการตั้งค่าจัดส่งที่ใช้จริง หากมี
สถานะบัญชีแยกการสังเกตที่ออกจากระบบและเข้าสู่ระบบ
ข้อความราคาดิบเก็บสิ่งที่หน้าแสดงไว้ตามจริง
จำนวนที่แปลงแล้วและรหัสสกุลเงินทำให้เปรียบเทียบการสังเกตที่ถูกต้องได้ง่ายขึ้น
ข้อความและความพร้อมจำหน่ายเก็บถ้อยคำบนหน้าและการตีความที่ทำให้เป็นมาตรฐาน
สถานะการรันและการดึงข้อมูลแยกการตรวจสอบที่ล้มเหลวออกจากการสังเกตที่ถูกต้อง

อย่าถือว่าตัวแปรเหล่านี้ใช้แทนกันได้ ผลภูมิศาสตร์ IP ไม่พิสูจน์ว่าตลาดจัดส่งใดที่ร้านใช้ โลเคิลเบราว์เซอร์ไม่ได้ตั้งที่อยู่จัดส่ง สัญลักษณ์สกุลเงินอย่างเดียวอาจกำกวม—เช่น $ อาจหมายถึงหลายสกุลเงิน

สคริปต์ตัวอย่างบันทึกรหัสสกุลเงินที่กำหนดไว้ มันไม่ตรวจจับสกุลเงินจากหน้าโดยอัตโนมัติ

1. สร้างโปรเจกต์

สร้างโฟลเดอร์ที่มีไฟล์เหล่านี้:

price-monitor/
├── .env
├── requirements.txt
└── monitor.py

เพิ่มการพึ่งพาใน requirements.txt:

playwright>=1.40
python-dotenv>=1.0

ติดตั้งพวกนั้นและเบราว์เซอร์ Chromium:

python -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
python -m playwright install chromium

บน Linux ให้ติดตั้งการพึ่งพาระบบของ Chromium หาก Playwright รายงานไลบรารีที่ใช้ร่วมกันหายไป:

sudo .venv/bin/playwright install-deps chromium

2. กำหนดค่าบริบทการทดสอบ

สร้างไฟล์ .env:

# Optional proxy settings. Leave all three blank for a direct practice run.
PROXY_SERVER=http://gw.kindproxy.com:12000
PROXY_USERNAME=your_dashboard_username
PROXY_PASSWORD=your_dashboard_password

PRODUCT_URL=https://books.toscrape.com/
REGION_LABEL=UK
BROWSER_LOCALE=en-GB
BROWSER_TIMEZONE=Europe/London
CURRENCY_CODE=GBP
DELIVERY_COUNTRY=
ACCOUNT_STATE=signed_out

ใช้ปลายทางพร็อกซีและข้อมูลรับรองจากบัญชีของคุณ คัดลอกชื่อผู้ใช้และรหัสผ่านที่สร้างขึ้นตามจริง อย่าต่อพารามิเตอร์เซสชันหรือตำแหน่งของผู้ให้บริการอื่นด้วยมือ เก็บ .env ไว้นอกการควบคุมเวอร์ชัน และอย่าเผยแพร่ข้อมูลรับรองพร็อกซีในภาพหน้าจอหรือบันทึก

สำหรับการรันฝึกโดยตรง ให้เว้น PROXY_SERVER, PROXY_USERNAME และ PROXY_PASSWORD ว่างไว้

ค่า REGION_LABEL, DELIVERY_COUNTRY และ ACCOUNT_STATE เป็นเมตาดาต้าที่บันทึกพร้อมผลลัพธ์ เดโมนี้ไม่ได้ยืนยันว่าพร็อกซีออกในประเทศที่ระบุ ไม่กรอกที่อยู่จัดส่ง และไม่ลงชื่อเข้าใช้ร้าน เพิ่มขั้นตอนเหล่านั้นเฉพาะเมื่อคุณมีบัญชีทดสอบและเวิร์กโฟลว์ที่ได้รับอนุญาต และบันทึกสถานะที่ใช้จริง

Playwright รองรับการตั้งค่าพร็อกซีตอนเปิดเบราว์เซอร์ รวมถึงฟิลด์ชื่อผู้ใช้และรหัสผ่านแยกสำหรับพร็อกซีที่ต้องยืนยันตัวตน ดู เอกสารเครือข่าย Playwright Python

3. รันตัวติดตาม

บันทึกเนื้อหาต่อไปนี้เป็น monitor.py ตัวเลือกเขียนสำหรับการ์ดแคตตาล็อกของ Books to Scrape ต้องปรับสำหรับเว็บไซต์อื่น

import asyncio
import csv
import json
import os
import re
from datetime import datetime, timezone
from decimal import Decimal, InvalidOperation
from pathlib import Path
from urllib.parse import urljoin

from dotenv import load_dotenv
from playwright.async_api import async_playwright

BASE_DIR = Path(__file__).resolve().parent
load_dotenv(BASE_DIR / ".env")

PRODUCT_URL = os.getenv("PRODUCT_URL", "https://books.toscrape.com/").strip()
REGION = os.getenv("REGION_LABEL", "not-set").strip()
LOCALE = os.getenv("BROWSER_LOCALE", "en-GB").strip()
BROWSER_TIMEZONE = os.getenv("BROWSER_TIMEZONE", "Europe/London").strip()
CURRENCY = os.getenv("CURRENCY_CODE", "GBP").strip().upper() or None
DELIVERY_COUNTRY = os.getenv("DELIVERY_COUNTRY", "").strip() or None
ACCOUNT_STATE = os.getenv("ACCOUNT_STATE", "signed_out").strip()
OUTPUT_DIR = BASE_DIR / "output"
JSON_PATH = OUTPUT_DIR / "snapshots.json"
CSV_PATH = OUTPUT_DIR / "snapshots.csv"

# These selectors are specific to Books to Scrape's catalogue cards.
CARD_SELECTOR = "article.product_pod"
TITLE_SELECTOR = "h3 a"
PRICE_SELECTOR = ".price_color"
AVAILABILITY_SELECTOR = ".availability"

CSV_FIELDS = [
    "record_type", "checked_at", "status", "error",
    "product_name", "product_url", "region", "locale",
    "browser_timezone", "delivery_country", "account_state",
    "proxy_exit_ip", "price_text", "price_amount",
    "currency", "availability_text", "availability_status",
    "comparison",
]


def utc_now() -> str:
    return datetime.now(timezone.utc).isoformat(timespec="seconds")


def parse_price(raw_text: str) -> str | None:
    """Parse a decimal amount from the demo site's GBP-style price text."""
    match = re.search(r"\d[\d,]*(?:\.\d{1,2})?", raw_text)
    if not match:
        return None
    try:
        return format(Decimal(match.group(0).replace(",", "")), ".2f")
    except InvalidOperation:
        return None


def normalize_availability(raw_text: str) -> str:
    value = raw_text.casefold()
    if "in stock" in value:
        return "in_stock"
    if "out of stock" in value:
        return "out_of_stock"
    return "unknown"


def load_records() -> list[dict]:
    if not JSON_PATH.exists():
        return []
    try:
        data = json.loads(JSON_PATH.read_text(encoding="utf-8"))
        return data if isinstance(data, list) else []
    except (OSError, json.JSONDecodeError):
        return []


def save_records(records: list[dict]) -> None:
    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    JSON_PATH.write_text(
        json.dumps(records, ensure_ascii=False, indent=2),
        encoding="utf-8",
    )
    with CSV_PATH.open("w", newline="", encoding="utf-8-sig") as file:
        writer = csv.DictWriter(file, fieldnames=CSV_FIELDS, extrasaction="ignore")
        writer.writeheader()
        writer.writerows(records)


def compare_with_previous(records: list[dict], current: dict) -> str:
    if current.get("status") != "success" or not current.get("price_amount"):
        return "not_compared"

    dimensions = (
        "product_url", "region", "locale", "browser_timezone",
        "delivery_country", "account_state", "currency",
    )
    previous = next(
        (
            item for item in reversed(records)
            if item.get("record_type") == "product"
            and item.get("status") == "success"
            and item.get("price_amount") is not None
            and all(item.get(key) == current.get(key) for key in dimensions)
        ),
        None,
    )
    if previous is None:
        return "baseline"

    old_price = Decimal(str(previous["price_amount"]))
    new_price = Decimal(str(current["price_amount"]))
    if new_price < old_price:
        return "price_decreased"
    if new_price > old_price:
        return "price_increased"
    return "no_change"


def base_record(record_type: str, status: str, **extra) -> dict:
    record = {
        "record_type": record_type,
        "checked_at": utc_now(),
        "status": status,
        "error": None,
        "product_name": None,
        "product_url": None,
        "region": REGION,
        "locale": LOCALE,
        "browser_timezone": BROWSER_TIMEZONE,
        "delivery_country": DELIVERY_COUNTRY,
        "account_state": ACCOUNT_STATE,
        "proxy_exit_ip": None,
        "price_text": None,
        "price_amount": None,
        "currency": CURRENCY,
        "availability_text": None,
        "availability_status": "unknown",
        "comparison": "not_compared",
    }
    record.update(extra)
    return record


async def main() -> None:
    if not PRODUCT_URL:
        raise ValueError("PRODUCT_URL must be set.")

    proxy_server = os.getenv("PROXY_SERVER", "").strip()
    proxy_username = os.getenv("PROXY_USERNAME", "").strip()
    proxy_password = os.getenv("PROXY_PASSWORD", "").strip()

    if bool(proxy_username) != bool(proxy_password):
        raise ValueError("Set both PROXY_USERNAME and PROXY_PASSWORD, or neither.")
    if (proxy_username or proxy_password) and not proxy_server:
        raise ValueError("Set PROXY_SERVER when proxy credentials are provided.")

    proxy = None
    if proxy_server:
        proxy = {"server": proxy_server}
        if proxy_username:
            proxy["username"] = proxy_username
            proxy["password"] = proxy_password

    records = load_records()
    run_record = base_record("run", "started")
    new_records = [run_record]

    async with async_playwright() as playwright:
        browser = await playwright.chromium.launch(proxy=proxy)
        try:
            context = await browser.new_context(
                locale=LOCALE,
                timezone_id=BROWSER_TIMEZONE,
            )
            page = await context.new_page()
            exit_ip = None

            if proxy:
                try:
                    ip_response = await page.goto(
                        "https://api.ipify.org?format=json",
                        wait_until="domcontentloaded",
                        timeout=30_000,
                    )
                    if ip_response and ip_response.ok:
                        ip_data = json.loads(await page.locator("body").inner_text())
                        exit_ip = ip_data.get("ip")
                except Exception as exc:
                    new_records.append(
                        base_record(
                            "diagnostic", "failed",
                            error=f"Proxy exit-IP check failed: {type(exc).__name__}: {exc}",
                        )
                    )

            try:
                response = await page.goto(
                    PRODUCT_URL,
                    wait_until="domcontentloaded",
                    timeout=45_000,
                )
                if response and response.status >= 400:
                    raise RuntimeError(f"Target returned HTTP {response.status}")

                body_text = (await page.locator("body").inner_text()).casefold()
                challenge_markers = (
                    "verify you are human",
                    "unusual traffic",
                    "captcha",
                    "access denied",
                    "automated requests",
                )
                if any(marker in body_text for marker in challenge_markers):
                    raise RuntimeError(
                        "Challenge or access-restriction page detected; "
                        "the monitor stopped without retrying or rotating IPs."
                    )

                cards = page.locator(CARD_SELECTOR)
                await cards.first.wait_for(state="visible", timeout=15_000)
                count = await cards.count()

                for index in range(count):
                    card = cards.nth(index)
                    try:
                        title_link = card.locator(TITLE_SELECTOR)
                        title = (await title_link.get_attribute("title")) or (
                            await title_link.inner_text()
                        ).strip()
                        href = await title_link.get_attribute("href")
                        product_url = urljoin(PRODUCT_URL, href or "")

                        price_text = (await card.locator(PRICE_SELECTOR).inner_text()).strip()
                        price_amount = parse_price(price_text)
                        availability_text = (
                            await card.locator(AVAILABILITY_SELECTOR).inner_text()
                        ).strip()

                        if price_amount is None:
                            item = base_record(
                                "product", "extraction_failed",
                                error="Price text was present but could not be parsed.",
                                product_name=title,
                                product_url=product_url,
                                proxy_exit_ip=exit_ip,
                                price_text=price_text,
                                availability_text=availability_text,
                                availability_status=normalize_availability(availability_text),
                            )
                        else:
                            item = base_record(
                                "product", "success",
                                product_name=title,
                                product_url=product_url,
                                proxy_exit_ip=exit_ip,
                                price_text=price_text,
                                price_amount=price_amount,
                                availability_text=availability_text,
                                availability_status=normalize_availability(availability_text),
                            )
                            item["comparison"] = compare_with_previous(records + new_records, item)

                        new_records.append(item)
                    except Exception as exc:
                        new_records.append(
                            base_record(
                                "product", "extraction_failed",
                                error=f"{type(exc).__name__}: {exc}",
                                proxy_exit_ip=exit_ip,
                            )
                        )

                run_record["status"] = "success"
                run_record["error"] = None
                run_record["products_seen"] = count

            except Exception as exc:
                run_record["status"] = "check_failed"
                run_record["error"] = f"{type(exc).__name__}: {exc}"
                run_record["products_seen"] = 0

            finally:
                await context.close()
        finally:
            await browser.close()

    records.extend(new_records)
    save_records(records)

    print(f"Run status: {run_record['status']}")
    print(f"Records written: {len(new_records) - 1} product/diagnostic records")
    print(f"JSON: {JSON_PATH}")
    print(f"CSV:  {CSV_PATH}")
    if run_record["error"]:
        print(f"Error: {run_record['error']}")


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

รัน:

python monitor.py

การรันเดโมที่สำเร็จสร้างระเบียนสินค้า 20 รายการและบันทึกไฟล์ผลลัพธ์ทั้งสอง:

Playwright price monitor running successfully in the terminal, with 20 product records written to JSON and CSV

สคริปต์เขียน:

output/
├── snapshots.json
└── snapshots.csv

ไฟล์ JSON เก็บระเบียนเต็ม ไฟล์ CSV สะดวกสำหรับตรวจในสเปรดชีต ระเบียนระดับการรันยังถูกบันทึกแม้การนำทางล้มเหลวหรือตรวจพบหน้า challenge การรันที่ไม่สำเร็จจะไม่ถูกแปลงเป็นการสังเกตราคาเป็นศูนย์

นี่คือตัวอย่างระเบียนสินค้าที่ดึงสำเร็จ รวมราคาที่แสดงเดิม จำนวนที่แปลงแล้ว สกุลเงินที่ตั้งไว้ ความพร้อมจำหน่าย และ IP ทางออกพร็อกซี:

JSON snapshot showing a successfully extracted product, its GBP price, availability status, and proxy exit IP

4. เข้าใจผลลัพธ์และกฎการเปรียบเทียบ

ตัวติดตามเก็บข้อความราคาเดิมและจำนวนตัวเลขที่แปลงแล้ว ตัวอย่างเช่น หน้าอาจแสดง £51.77 ตัวแปลงเก็บ 51.77 ส่วนรหัสสกุลเงินมาจาก CURRENCY_CODE=GBP

ตัวแปลงนี้ตั้งใจให้แคบ เหมาะกับรูปแบบตัวเลขแบบ GBP ของเดโม ไม่ใช่ทุกโลเคิล ตัวแปลงในโปรดักชันควรปรับให้เข้ากับรูปแบบตัวเลขและเมตาดาต้าสกุลเงินของร้านเป้าหมาย

การเปรียบเทียบใช้เฉพาะระเบียนที่สำเร็จก่อนหน้าซึ่งมี URL สินค้า ป้ายตลาด โลเคิล โซนเวลา การตั้งค่าประเทศจัดส่ง สถานะบัญชี และสกุลเงินที่ตั้งไว้เดียวกัน ราคาที่หายไปหรือแปลงไม่ได้จะถูกมาร์กว่า extraction_failed ไม่เคยถือเป็นศูนย์

ป้ายตลาดยังคงเป็นเพียงป้าย ก่อนเปรียบเทียบตลาดจริง ให้ยืนยันตำแหน่งทางออกพร็อกซีจริงและการตั้งค่าจัดส่งกับบัญชีของสโตร์ฟรอนต์แยกกัน

ในเดโม การรันแรกสร้าง baseline สำหรับสินค้า 20 รายการ การรันที่สองเพิ่มอีก 20 ระเบียน และราคาที่ไม่เปลี่ยนถูกติดป้าย no_change อย่างถูกต้อง ฟิลด์ delivery_country ว่างเพราะไม่ได้ตั้งประเทศจัดส่ง ซึ่งเป็นเรื่องปกติสำหรับไซต์ฝึก Books to Scrape

CSV spreadsheet showing two monitoring runs, with baseline labels in the first run and no_change labels in the second

5. การแก้ปัญหา

อาการสิ่งที่ควรตรวจ
Chromium เปิดไม่ได้ติดตั้งเบราว์เซอร์และการพึ่งพาระบบ Linux
การยืนยันตัวตนพร็อกซีล้มเหลวตรวจปลายทางและคัดลอกชื่อผู้ใช้/รหัสผ่านที่สร้างขึ้นตามจริง
ตรวจ IP ได้แต่หน้าเป้าหมายล้มเหลวปลายทางอาจมีกฎหรือข้อจำกัดการเข้าถึงแยก
ไม่พบการ์ดแคตตาล็อกยืนยันว่าหน้าโหลดแล้วและอัปเดต CSS selector สำหรับไซต์นั้น
มีข้อความราคาแต่จำนวนว่างปรับ parse_price() ให้เข้ากับรูปแบบตัวเลขของไซต์
ความพร้อมจำหน่ายเป็น unknownทบทวนถ้อยคำความพร้อมจำหน่ายของไซต์และอัปเดตตัวทำให้เป็นมาตรฐาน
ปรากฏ CAPTCHA ทราฟฟิกผิดปกติ หรือหน้าปฏิเสธการเข้าถึงหยุดการตรวจสอบ บันทึกความล้มเหลว และทบทวนกฎของไซต์กับตารางคำขอ

อย่าตอบสนองต่อ challenge ด้วยการเปลี่ยน IP ซ้ำๆ หรือทำให้ challenge เป็นอัตโนมัติ พร็อกซีที่อยู่อาศัยไม่รับประกันการเข้าถึงหรือป้องกันหน้า CAPTCHA

6. API การทำงานอัตโนมัติของเบราว์เซอร์ หรือพร็อกซี?

เครื่องมือเหล่านี้แก้ปัญหาต่างกัน:

  • API หรือฟีดอย่างเป็นทางการ: จุดเริ่มต้นที่ดีที่สุดเมื่อให้ข้อมูลสินค้าแบบมีโครงสร้างที่ได้รับอนุญาต
  • Playwright: มีประโยชน์เมื่อข้อมูลที่เกี่ยวข้องถูกเรนเดอร์ในเบราว์เซอร์ หรือคุณต้องตรวจสอบหน้าที่มองเห็นของสโตร์ฟรอนต์
  • พร็อกซีที่อยู่อาศัย: เปลี่ยนเส้นทางเครือข่าย อาจช่วยทดสอบว่าไซต์ตอบสนองอย่างไรจากทางออกเครือข่ายต่างกัน แต่ไม่ได้ตั้งประเทศจัดส่ง สกุลเงิน คุกกี้ หรือสถานะบัญชีด้วยตัวเอง

สำหรับแคตตาล็อกขนาดใหญ่ ให้เพิ่มการจัดตาราง ขีดจำกัดอัตรา นโยบายลองใหม่สำหรับข้อผิดพลาดเครือข่ายชั่วคราว การแจ้งเตือน และการเก็บข้อมูล หลังจากเวิร์กโฟลว์รันครั้งเดียวเชื่อถือได้แล้วเท่านั้น เคารพข้อกำหนดของไซต์เป้าหมาย คำแนะนำ robots เมื่อใช้ได้ และกฎหมายที่เกี่ยวข้อง เลือกการเข้าถึงข้อมูลอย่างเป็นทางการเมื่อมี

หากคุณกำลังประเมินตัวเลือกพร็อกซีสำหรับเวิร์กโฟลว์ติดตามที่ได้รับอนุญาต ดู แผนพร็อกซีที่อยู่อาศัยของ KindProxy

FAQ

Playwright ติดตามราคาอีคอมเมิร์ซได้หรือไม่?

ได้ Playwright สามารถอ่านฟิลด์ราคาและความพร้อมจำหน่ายที่มองเห็นจากหน้าที่คุณได้รับอนุญาตให้เข้าถึง ตัวเลือกต้องตรงกับมาร์กอัปของไซต์เป้าหมาย และการสังเกตแต่ละครั้งควรได้รับการตรวจสอบก่อนเปรียบเทียบกับข้อมูลก่อนหน้า

พร็อกซีที่อยู่อาศัยอย่างเดียวแสดงราคาในประเทศอื่นได้หรือไม่?

ไม่ใช่อัตโนมัติ ร้านอาจพิจารณาตำแหน่งทางออกเครือข่าย ที่อยู่จัดส่ง สกุลเงิน โลเคิล คุกกี้ และสถานะบัญชี พร็อกซีเปลี่ยนเฉพาะเส้นทางเครือข่าย

พร็อกซีป้องกันหน้า CAPTCHA ได้หรือไม่?

ไม่ได้ ไซต์ยังอาจส่ง CAPTCHA challenge การบล็อก หรือหน้าที่ไม่สมบูรณ์ บันทึกการตรวจสอบที่ล้มเหลวและทบทวนกฎการเข้าถึง แทนการหมุน IP ซ้ำๆ

ถ้าแปลงราคาไม่ได้ล่ะ?

เก็บข้อความดิบ มาร์กระเบียนว่าการดึงข้อมูลล้มเหลว และปล่อยจำนวนตัวเลขให้ว่าง อย่าเปลี่ยนค่าที่หายไปเป็นศูนย์หรือนับเป็นการลดราคา

สรุปท้าย

การติดตามราคาที่เชื่อถือได้ขึ้นอยู่กับคุณภาพของการสังเกต ไม่ใช่แค่โค้ดสแครป บันทึกเงื่อนไขการทดสอบ เก็บค่าดิบบนหน้า ตรวจสอบการดึงข้อมูลแต่ละครั้ง และเปรียบเทียบเฉพาะระเบียนที่สำเร็จในเงื่อนไขเดียวกัน

ตัวอย่าง Books to Scrape แสดงเวิร์กโฟลว์ มันไม่ได้กำหนดพฤติกรรมราคาตามภูมิภาคจริง สำหรับการใช้งานจริง ให้ปรับตัวเลือกและกฎการแปลงให้เข้ากับสโตร์ฟรอนต์ที่ได้รับอนุญาต ยืนยันเงื่อนไขตลาดแยกต่างหาก และถือข้อจำกัดการเข้าถึงเป็นการตรวจสอบที่ล้มเหลว—ไม่ใช่เหตุผลที่จะหลีกเลี่ยง