Lazadaのスクレイピングでは、商品名や価格を取得するだけでなく、「どの販売者の、どの仕様を、いつ、どの購入条件で確認したか」を記録することが重要です。PythonでLazadaの商品データを扱う場合も、データの取得権限と対象市場を確認し、項目の意味を検証してからCSVに出力します。
本記事では、架空の商品データを使ったローカル解析の実行例を紹介します。あわせて、動的ページを扱う手順、Socks5.IOのプロキシ設定、データ収集サービスの比較ポイントを整理します。サンプルは現在のLazadaページの構造を保証するものではありません。実際のブラウザー収集処理は、利用を認められた取得元に合わせて別途実装・検証する必要があります。
最初に押さえたい点は、次の3つです。
- 表示価格だけでは比較できません。 バリエーション、販売者、送料、クーポンの適用条件をそろえます。
- プロキシは通信経路を提供します。 商品データや取得権限を提供するサービスではありません。
- 小さなサンプルで検証してから対象を広げます。 出力件数だけでなく、対象の網羅性、データの鮮度、欠損値も確認します。

1. Lazadaのスクレイピングを始める前に、取得方法を選ぶ
自社店舗の業務データには、まず公式APIを検討します。商品ページを収集する場合は、取得権限、必要な項目、保守体制に応じてPython、ノーコードツール、代行サービスを選びます。
| 目的 | 最初に検討する方法 | 確認すること |
|---|---|---|
| 自社店舗の商品管理や業務連携 | Lazada Open Platform | アプリの権限、販売者の認可、APIの項目と利用上限 |
| 許可された少数の商品情報を取得 | 取得元に合わせたPythonやブラウザーの処理 | 取得範囲、実際のページ構造、市場、バリエーション、取得日時 |
| コードを書かずに収集手順を組む | ノーコードのデータ収集ツール | 現在のページへの対応、ページ送り、出力の正確さ |
| 定期的に整備済みのデータを受け取る | データ収集代行サービス | 対象範囲、納品までの時間、項目定義、利用権限、検収条件 |
Lazadaの販売者認可に関するドキュメントでは、販売者の業務データにアクセスするための認可を説明しています。自社店舗との連携権限があっても、全出品者の競合データを自由に取得できるわけではありません。APIキーの有無だけで判断せず、利用するAPIと認可範囲を確認してください。
Webページを収集する場合も、対象サイトの最新の利用条件と許可範囲を確認します。公開ページであることやrobotsルールだけでは、必要な権限を確認したことにはなりません。アカウント制限、CAPTCHA、アクセス制御を回避する目的では使わず、業務に不要な購入者情報、注文情報、レビュー投稿者の個人情報は収集対象から外します。
2. Lazadaの商品データは何を記録すればよいか
価格監視に使えるデータには、商品を識別する情報と購入条件が必要です。商品名と価格だけでは、同じ条件の販売価格かどうかを判断できません。
| 分類 | 記録する項目 | よくある誤り |
|---|---|---|
| 取得元・日時 | 市場、取得元URL、取得日時、実行ID、取得方法 | 古い保存ページの価格を現在価格として扱う |
| 商品の識別 | 商品ID、SKU・バリエーションID、販売者、ブランド、数量・内容量 | 名前が似ているだけで別の仕様を同一商品にまとめる |
| 表示価格 | 金額、通貨、価格の種類、選択中の仕様 | 最低価格や取り消し線付きの参考価格を採用する |
| 購入条件 | 送料、税の扱い、配送先、クーポン・会員条件 | 表示価格を支払総額とみなす |
| 在庫 | 明示された状態、対象仕様、取得日時 | 記載がない商品を在庫切れにする |
| 評価 | 評価値、満点、評価・レビュー件数、評価対象 | 店舗評価を商品評価として扱う |
| 画像 | 画像URL、商品やバリエーションとの対応 | CDNのURLがあれば転載できると判断する |
LazMall、発送元、送料、クーポンを分けて管理する
Lazadaでは、次の項目を別々に記録します。ある項目から別の項目を推測して埋めると、比較条件が崩れます。
| フィールド | 記録方法 | 不明な場合 |
|---|---|---|
| listing_type | 確認できたLazMall表示、または確認済みのMarketplace区分を根拠とともに保存 | unknown。部分的な応答に表示がないだけではMarketplaceと断定しません |
| cross_border | その販売条件に明示された越境区分 | unknown。店舗名から推測しません |
| ship_from_country | 発送国をサイトの市場や販売者情報と分けて保存 | 空欄。対象市場の国名で埋めません |
| shipping_fee / shipping_currency | 配送先、数量、配送方法に対応する送料と通貨 | 空欄。0にはしません |
| lead_time_days | 配達日数の範囲、取得日、配送先を記録し、元の配送案内も保存 | 空欄。単一の日数を推測しません |
| platform_voucher / seller_voucher | 適用資格、最低購入額、割引上限、有効期間、適用条件を別々に保存 | 空欄。自動で値引きしません |
| bundle_offer | 対象の組み合わせ、数量、仕様、割引条件を保存 | 空欄。単品価格と置き換えません |

LazMallの表示は、国内発送やすべての注文への同一配送条件を保証するものではありません。LazadaのLazMallサービス案内にある特典も、適用条件を確認する必要があります。販売者の名称と実際の発送国は、別の情報として扱います。
越境商品の表示価格が安くても、国内から短期間で届く商品より有利とは限りません。商品、仕様、内容量、配送先、発送元、到着予定、購入条件をそろえて比較します。プラットフォームのクーポン、販売者のクーポン、セット割引は、適用条件や併用ルールが異なるため、同じ購入条件で利用できると確認した特典だけを計算に含めます。
Lazadaシンガポールの利用条件も、配送料金と配送条件を区別しています。市場や商品ごとに条件が異なるため、シンガポールのルールを別の国にそのまま適用しないでください。

商品調査、品ぞろえの確認、価格監視では、必要な項目が異なります。特定カテゴリのサンプルから全商品の網羅性を判断したり、レビュー件数を販売数量として扱ったりしないよう、指標の名称と意味を残します。
対象市場、配送先、出口IPは別々に確認する
代表的な組み合わせは、シンガポール/SGD、マレーシア/MYR、フィリピン/PHP、タイ/THB、インドネシア/IDR、ベトナム/VNDです。実際にアクセスしたサイトと表示された通貨を記録します。CSVの国名を書き換えても、別の市場で取得したデータにはなりません。
国を指定できるプロキシで変更できるのは、主にネットワークの出口です。商品仕様、配送先、クーポン、税込み・税抜きの条件は別途確認します。ブラウザーの言語設定、ドメイン、ログイン状態、配送条件がIPの所在地と一致するとは限りません。
継続的な監視で通信経路を選ぶ際は、価格監視向けプロキシの比較と選び方も参考になります。仕様や販売者、購入条件を確認できないレコードは、最安値の順位に入れず、確認待ちとして扱います。
3. PythonでLazadaの商品データを抽出してCSVに保存する
まず保存済みHTMLの解析を検証し、その後でオンライン収集を組み込みます。ここでは、架空のJSON-LDを読み取り、商品項目の検証とCSV出力までを行うプログラムを使います。
対象はSchema.orgのProductとOfferの一部です。
- 文書のルート、または@graph内にあるProductを読み取ります。
- 各Productには、具体的なOfferが1件必要です。
- JSON-LDのコンテキスト展開や@id参照の解決は行いません。
- AggregateOfferによる価格帯、複数のOffer、入れ子のItemListやProductGroupには、別の抽出処理が必要です。
現在のLazadaページが、この構造を採用しているとは限りません。
手順1:仮想環境を作成して依存パッケージを入れる
Python 3.10以降を使用します。WindowsのPowerShellでは、次のコマンドを実行します。
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install "beautifulsoup4>=4.13,<5"
macOS/Linuxでは、次のように実行します。
python3 -m venv .venv
.venv/bin/python -m pip install "beautifulsoup4>=4.13,<5"
以降も仮想環境内のPythonを直接指定します。仮想環境の有効化操作や、別のコードパッケージのダウンロードは不要です。
手順2:解析プログラムを保存する
処理の流れは、保存済みHTML→JSON-LDのProduct→単一のOffer→項目の検証→CSV出力です。
サンプルの1件目には評価、画像、在庫状態があり、2件目にはこれらの任意項目がありません。どちらも送料、税、クーポンの条件は未確認なので、支払総額の比較には使えません。
次のコードをlazada_extract.pyとして保存します。フィールド名と診断コードは、出力との照合のため原文のまま残しています。
import argparse
import csv
import hashlib
import json
import re
import sys
from datetime import datetime, timezone
from decimal import Decimal
from pathlib import Path
from urllib.parse import urlsplit, urlunsplit
from uuid import uuid4
from bs4 import BeautifulSoup
MAX_BYTES = 2_000_000
MARKETS = {
"SG": ("www.lazada.sg", "SGD"), "MY": ("www.lazada.com.my", "MYR"),
"PH": ("www.lazada.com.ph", "PHP"), "TH": ("www.lazada.co.th", "THB"),
"ID": ("www.lazada.co.id", "IDR"), "VN": ("www.lazada.vn", "VND")}
FIXTURE_PRODUCTS = [
{"@type": "Product", "productID": "DEMO-ITEM-01", "sku": "DEMO-BLUE",
"name": "Fictional travel mug - blue, 350 ml",
"url": "https://catalog.example.invalid/mug-blue",
"image": "https://images.example.invalid/mug-blue.jpg",
"aggregateRating": {"ratingValue": "4.6", "bestRating": "5", "ratingCount": "12"},
"offers": {"@type": "Offer", "price": "24.90", "priceCurrency": "SGD",
"seller": {"name": "Demo Seller"},
"availability": "https://schema.org/InStock"}},
{"@type": "Product", "productID": "DEMO-ITEM-02", "sku": "DEMO-RED",
"name": "Fictional travel mug - red, 350 ml",
"url": "https://catalog.example.invalid/mug-red",
"offers": {"@type": "Offer", "price": "26.50", "priceCurrency": "SGD",
"seller": {"name": "Demo Seller"}}}]
FIXTURE = ('<html><script type="application/ld+json">' +
json.dumps({"@context": "https://schema.org", "@graph": FIXTURE_PRODUCTS}) +
'</script></html>').encode()
def fail(code):
raise ValueError(code)
def typed(node, expected):
value = node.get("@type", []) if isinstance(node, dict) else []
return value == expected or (isinstance(value, list) and expected in value)
def text(value):
return str(value).strip() if isinstance(value, (str, int, float, Decimal)) and not isinstance(value, bool) else ""
def safe_url(value, host=None):
p = urlsplit(text(value))
if p.scheme != "https" or not p.hostname or p.username or p.password or p.port not in (None, 443):
fail("FIELD_URL")
if host and p.hostname.lower() != host:
fail("MARKET_HOST")
return urlunsplit((p.scheme, p.netloc, p.path, "", ""))
def products_from_html(data):
if len(data) > MAX_BYTES:
fail("INPUT_SIZE")
nodes = []
for tag in BeautifulSoup(data, "html.parser").select('script[type="application/ld+json"]'):
parsed = json.loads(tag.get_text(), parse_float=Decimal,
parse_constant=lambda value: fail("JSON_NUMBER"))
roots = parsed if isinstance(parsed, list) else [parsed]
for root in roots:
if not isinstance(root, dict):
continue
if typed(root, "Product"):
nodes.append(root)
graph = root.get("@graph", [])
if not isinstance(graph, list):
fail("JSON_GRAPH")
nodes.extend(node for node in graph if typed(node, "Product"))
if not nodes:
fail("NO_PRODUCT_ADAPTER")
return nodes
def extract(data, market, kind, observed_at, run_id):
host, currency = MARKETS[market]
if kind == "synthetic_fixture":
host = "catalog.example.invalid"
rows, seen = [], set()
for product in products_from_html(data):
offer = product.get("offers")
if isinstance(offer, list) and len(offer) == 1:
offer = offer[0]
if not typed(offer, "Offer"):
fail("OFFER_ADAPTER")
amount = text(offer.get("price"))
if not re.fullmatch(r"\d+(?:\.\d+)?", amount) or Decimal(amount) <= 0:
fail("FIELD_AMOUNT")
if text(offer.get("priceCurrency")) != currency:
fail("MARKET_CURRENCY")
name = text(product.get("name"))
url = safe_url(product.get("url"), host)
if not name or url in seen:
fail("IDENTITY_OR_DUPLICATE")
seen.add(url)
seller = offer.get("seller", {})
seller = text(seller.get("name")) if isinstance(seller, dict) else ""
availability = text(offer.get("availability"))
stock = {"https://schema.org/InStock": "in_stock",
"https://schema.org/OutOfStock": "out_of_stock"}.get(availability, "unknown")
rating = product.get("aggregateRating", {})
if not isinstance(rating, dict):
rating = {}
image = product.get("image", "")
if isinstance(image, list):
image = image[0] if image else ""
image = safe_url(image) if image else ""
item_id, sku = text(product.get("productID")), text(product.get("sku"))
review = ["purchase_conditions_unverified"]
for missing, label in [(not item_id, "item_id_missing"), (not sku, "sku_missing"),
(not seller, "seller_missing"), (stock == "unknown", "availability_unknown")]:
if missing:
review.append(label)
rows.append(dict(item_id=item_id, sku=sku, title=name, seller=seller,
display_price=str(Decimal(amount)), currency=currency,
availability=stock, listing_type="unknown", cross_border="unknown",
ship_from_country="", shipping_fee="", shipping_currency="",
lead_time_days="", platform_voucher="", seller_voucher="", bundle_offer="",
rating_value=text(rating.get("ratingValue")),
rating_scale=text(rating.get("bestRating")),
rating_count=text(rating.get("ratingCount")), image_url=image,
source_url=url, requested_market=market, source_kind=kind,
source_observed_at_utc=observed_at, run_id=run_id,
comparison_eligible=False, review_reason=";".join(review)))
return rows
def main():
p = argparse.ArgumentParser()
p.add_argument("--input", type=Path)
p.add_argument("--approved", action="store_true")
p.add_argument("--market", choices=MARKETS, default="SG")
p.add_argument("--observed-at")
p.add_argument("--out", type=Path, required=True)
a = p.parse_args()
log_path = a.out.with_suffix(".run.json")
if a.out.exists() or log_path.exists():
fail("OUTPUT_EXISTS")
if a.input:
if not a.approved or not a.observed_at:
fail("REQUIRE_APPROVAL_AND_CAPTURE_TIME")
stamp = datetime.fromisoformat(a.observed_at.replace("Z", "+00:00"))
if stamp.tzinfo is None:
fail("CAPTURE_TIME_ZONE")
observed = stamp.astimezone(timezone.utc).isoformat()
with a.input.open("rb") as handle:
data = handle.read(MAX_BYTES + 1)
kind = "approved_saved_html"
else:
if a.market != "SG":
fail("FIXTURE_IS_SG_ONLY")
data, kind, observed = FIXTURE, "synthetic_fixture", "2026-10-27T00:00:00+00:00"
run_id = uuid4().hex
rows = extract(data, a.market, kind, observed, run_id)
log = dict(run_id=run_id, source_kind=kind, requested_market=a.market,
source_observed_at_utc=observed,
processed_at_utc=datetime.now(timezone.utc).isoformat(),
input_sha256=hashlib.sha256(data).hexdigest(),
records_exported=len(rows), proxy_tested=False)
with log_path.open("x", encoding="utf-8") as handle:
json.dump(log, handle, indent=2)
with a.out.open("x", encoding="utf-8", newline="") as handle:
writer = csv.DictWriter(handle, fieldnames=list(rows[0]))
writer.writeheader()
writer.writerows(rows)
print(f"Exported {len(rows)} records; inspect review_reason before analysis.")
if __name__ == "__main__":
try:
main()
except Exception as error:
allowed = {"INPUT_SIZE", "FIELD_URL", "MARKET_HOST", "JSON_NUMBER", "JSON_GRAPH",
"NO_PRODUCT_ADAPTER", "OFFER_ADAPTER", "FIELD_AMOUNT", "MARKET_CURRENCY",
"IDENTITY_OR_DUPLICATE", "OUTPUT_EXISTS", "REQUIRE_APPROVAL_AND_CAPTURE_TIME",
"CAPTURE_TIME_ZONE", "FIXTURE_IS_SG_ONLY"}
code = str(error) if isinstance(error, ValueError) and str(error) in allowed else "INPUT_OR_OUTPUT_ERROR"
print("Stopped:", code, "- inspect input and configuration privately.", file=sys.stderr)
sys.exit(1)
出力を利用する前に、次の制約を確認してください。
- productIDとskuは取得元の値を対応付けています。Lazadaの商品IDやバリエーションIDとして正しいかは、実際の取得元で確認が必要です。
- 評価項目は元のテキストを保存します。評価の正当性を認証したり、再集計したりしません。満点の記載がなくても5で補完しません。
- Lazada固有の列は予約済みの項目です。listing_typeとcross_borderはunknown、発送元、送料、配送日数、クーポンなどは空欄のままです。
- 購入条件を検証する別工程を実装するまでは、comparison_eligibleはFalseです。
この例の重複判定は、クエリ文字列とフラグメントを除いたURLを使います。同じパスで仕様だけが異なる商品は重複と判定され、同じ商品でもパスが違えば重複を見落とす可能性があります。本番で使う場合は、確認済みの商品ID、仕様、販売者などに基づく識別キーを設計してください。
手順3:ローカルで実行してCSVを確認する
WindowsのPowerShell:
.\.venv\Scripts\python.exe lazada_extract.py --out lazada-demo.csv
macOS/Linux:
.venv/bin/python lazada_extract.py --out lazada-demo.csv
主な項目は、次のように出力されます。
商品ID |
SKU |
表示価格 |
在庫状態 |
比較対象にできるか |
|---|---|---|---|---|
DEMO-ITEM-01 |
DEMO-BLUE |
SGD 24.90 |
in_stock |
False |
DEMO-ITEM-02 |
DEMO-RED |
SGD 26.50 |
unknown |
False |
これは仕様の異なる2件のデータです。同一条件の商品を安い順に並べた結果ではありません。
JSON形式の実行記録には、入力ファイルのハッシュ、取得元の種類、取得日時、処理日時が残ります。サンプルの取得日時は固定の架空値です。今日実行しても、今日のLazada価格を取得したことにはなりません。


実行ごとに新しい出力ファイル名を指定します。このプログラムは上書きを拒否しますが、CSVと実行記録を一括で確定する仕組みはありません。ディスクエラーなどで実行記録だけが残る場合があります。外部のテキストを表計算ソフトで開く際は、数式として評価させず、文字列として安全に取り込んでください。
手順4:許可された保存ページに合わせて調整する
まず保存した応答を確認します。対応するProduct/Offerがある場合も、表示中の仕様や価格とフィールドの意味が一致するかを照合します。別の埋め込みデータや描画後のDOMを使っている場合は、その実際の構造に合わせて抽出処理を変更します。古い記事から現在のCSSセレクター、非公開API、JSONの項目名を推測して使わないでください。
シンガポールの商品ページを処理する例は次のとおりです。日時は説明用の値なので、ファイルを実際に取得した日時へ置き換えます。
WindowsのPowerShell:
.\.venv\Scripts\python.exe lazada_extract.py --input approved-product.html --approved --market SG --observed-at "2026-10-27T09:00:00+08:00" --out approved-sg.csv
macOS/Linux:
.venv/bin/python lazada_extract.py --input approved-product.html --approved --market SG --observed-at "2026-10-27T09:00:00+08:00" --out approved-sg.csv
–marketは、商品リンクのホストと通貨を検証する設定です。実際のアクセス地域や配送条件を証明するものではありません。このプログラムは通信を行わず、画像、追加レビュー、次のページも取得しません。画像URLを保存しても、その画像の転載権を取得したことにはなりません。
CSV内のURLからは、クエリ文字列とフラグメントを削除しています。そこに仕様や取得条件が含まれる場合は、完全な取得URLと選択内容を、run_idでひも付けたアクセス制限付きの記録に残します。短縮されたURLから仕様を復元したり、認証トークンを公開したりしないでください。HTMLのハッシュは保存ファイルとの対応を示すもので、現在のページ内容を証明するものではありません。
4. JavaScriptで表示される商品情報を取得するには
必要な項目がJavaScript実行後にしか現れない場合は、ブラウザーで描画してから保存します。ページを開けたことと、正しい商品データを取得できたことは、別々に確認します。
- 設定を明確にした新しいブラウザーコンテキストで、許可された商品URLを1件開きます。対象市場、配送先、選択した仕様を記録します。
- メインページの応答と最終URLを確認します。アクセス拒否、認証要求、ログイン要求、予期しない遷移があれば停止します。IPを変更して制限を回避する処理には進みません。
- 実際の取得元で確認した商品・仕様の表示条件を待ちます。固定秒数の待機やbody要素の存在だけで完了としません。
- 商品名、販売者、仕様、表示価格、通貨をまとめて照合します。許可された範囲の描画済みHTMLと取得日時を、アクセス制限付きの保存先に残します。
- 調整済みの解析プログラムを実行し、CSVと画面上の内容を照合します。その後で対象URLやページ送りを増やします。
PlaywrightやSeleniumは描画に使えますが、スクリーンショットだけでは、出力値が選択中の仕様に対応しているとは証明できません。Seleniumによるスクレイピングの実践ガイドでは、描画、待機、ページ送りの練習手順を紹介しています。練習用のセレクターはLazada用ではありません。
検索結果の順位と商品詳細の販売条件も分けて記録します。ページ番号、検索条件、必要に応じて広告表示を残し、ページ送り後に内容が変わったことを確認します。確認済みの識別子で重複を処理し、許可されたページ数に達したら終了します。検索結果のテンプレートだけで、すべての商品や仕様を網羅できるとは限りません。
ここで示すのは取得手順です。現在のLazadaにそのまま使える汎用セレクターや、完成済みのブラウザー収集プログラムは含みません。
5. Socks5.IOのプロキシをLazadaの収集処理に設定する
Socks5.IOを使うのは、必要な地域や住宅回線の出口を確保する工程です。契約した製品の接続方式とブラウザーの対応を確認し、収集に使うブラウザーから通信経路を検証します。
許可された処理に住宅回線の経路や特定地域の出口が必要な場合は、ローテーション型住宅プロキシを検討します。購入前に、対象地域、セッション方式、提供状況、利用条件を確認してください。対応地域の一覧は、個別のLazadaページへの接続実績を示すものではありません。
管理画面では、次の順に設定内容を確認します。
- 利用する住宅プロキシ製品を選びます。
- Proxy Setupを開きます。
- プロキシ用ユーザーと認証方式を設定します。
- 対象地域とセッション方式を指定します。
- クライアントが対応するプロトコルを選びます。
- 発行されたホスト、ポート、プロキシ認証情報を取得します。
管理画面のログイン情報ではなく、発行されたプロキシ用の認証情報を使用します。接続先の生成と検証は、住宅プロキシの設定ガイドも参照してください。
Playwrightのプロキシ設定は、対応プロトコルを確認する
Playwrightのネットワーク設定ドキュメントでは、HTTP(S)とSOCKSv5のプロキシを扱っています。一方、ユーザー名・パスワードの項目はHTTP(S)プロキシ向けに説明されています。Requestsで使える認証付きSOCKS5の接続文字列を、そのままChromiumに渡せるとは限りません。
次の設定例は、利用する製品から互換性のあるHTTP(S)ゲートウェイを発行できる場合に限って使用します。 コードでは、発行済みのHTTPゲートウェイを指定しています。HTTP用の設定から取得したホストとポートを、対応する環境変数に設定してください。
# Configuration excerpt inside your approved Playwright collector, not a standalone scraper.
import os
proxy = {
"server": "http://" + os.environ["SOCKS5IO_HTTP_HOST"] + ":" + os.environ["SOCKS5IO_HTTP_PORT"],
"username": os.environ["SOCKS5IO_USER"],
"password": os.environ["SOCKS5IO_PASSWORD"],
}
# browser = playwright.chromium.launch(proxy=proxy)
これは既存のPlaywright収集処理に組み込む設定の抜粋で、単体では商品を取得しません。SOCKS専用の接続先は、URLの先頭を http:// に変えるだけでは使えません。提供元が対応するクライアントと認証方法で別途確認します。
認証情報は保護された環境変数やシークレット管理に保存し、proxy辞書をログへ出力しないでください。TLS証明書の検証も有効なままにします。
プロキシURLのスキームは、ゲートウェイまでの接続方式を表します。商品ページがHTTPSだからといって、プロキシ設定も必ず https:// になるわけではありません。発行された接続方式とクライアントの仕様に従います。

同じブラウザーコンテキストで出口IPを確認する
利用を認められたIP確認サービスに、収集用と同じブラウザーコンテキストからアクセスします。その後、実際の商品ページの応答を確認します。地域判定が必要なら別途検証し、第三者のIP確認サービスへ送る情報も把握してください。
別のターミナルで確認したIPは、ブラウザーの出口を証明しません。また、リクエストごとにIPが変わるサービスでは、処理の前後に確認しても、途中の全リクエストが同じIPだったとはいえません。
ページ操作中に同じ出口を維持する必要があれば、対応するスティッキーセッションを選びます。セッションの有効期限、ゲートウェイへの接続、実際の出口を確認してください。同じブラウザーインスタンスでも、IPが固定されるとは限りません。SOCKS5が常に高速または安全というわけでもなく、プロトコルの変更で誤った抽出ルールを直すことはできません。
6. エラーへの対処とデータ品質の測り方
失敗は、アクセス、抽出形式、項目の意味に分けて調べます。HTTP応答の成功数と、業務で使えるレコード数を別々に集計すると、原因とコストを把握しやすくなります。
| 状況・診断コード | 次に確認すること |
|---|---|
| HTTP 401/403、ログイン要求、認証チャレンジ | 停止し、アクセス権限と応答内容を確認します |
| HTTP 429 | 停止し、全ワーカーを含めた利用上限と許可された再試行条件を確認します |
| NO_PRODUCT_ADAPTER | 保存済みHTMLの実際の構造に合わせて抽出処理を調整します |
| OFFER_ADAPTER | 価格帯、複数のOffer、異なる形式を個別に処理します |
| MARKET_HOST / MARKET_CURRENCY | 指定市場、商品リンク、実際の通貨を照合します |
| FIELD_AMOUNT | 通常価格、参考価格、価格帯を区別し、欠損値や0以下の値を確認します |
| 仕様、販売者、購入条件が不明 | 確認待ちにし、比較可能な商品群へ入れません |
| レイアウトやJSON項目の変更 | 保存を認められたサンプルで再検証し、抽出処理の版を管理します |
解析プログラムは、例外の全文ではなく、許可した診断コードを出力します。自動再試行、IPの切り替え、ブラウザー保護の解除、別の取得元への自動切り替えは行いません。
入力上限の2,000,000バイトは、ファイルの読み込み量を制限するものです。任意の不正な入力に対して、CPUやプロセスメモリ全体の使用量を制限する仕組みではありません。本番処理では実行時間などの上限も設け、依存パッケージを保守します。
品質は、少なくとも次の指標に分けます。
- 予定した取得対象数
- 正常に応答した取得元の数
- 構造上の検証を通過したレコード数
- 購入条件まで確認できた比較対象数
- 重複数
- 取得からの経過時間
1回の応答に複数行が含まれることがあるため、「出力行数÷リクエスト数」は通信成功率ではありません。抽出結果が空でも在庫ゼロとは限らず、取得できなかったページも対象範囲の集計に残します。
費用は、次のように計算すると比較しやすくなります。
有効な取得記録1件あたりの費用=収集・描画・サービス利用・保守にかかった対象費用÷合意した基準で検収できた記録数
先に分母の条件を決めてから、提供元を比較します。スクレイピング向けプロキシの選定ガイドも参考になります。1GBあたりの料金が安くても、利用できる販売価格1件あたりの費用が安いとは限りません。
7. Lazadaのデータ収集サービスを比較するポイント
最適な方法は、抽出処理とデータ品質を誰が維持するかで変わります。料金だけでなく、対象範囲、更新頻度、検収条件をそろえて比較します。
| 方法 | 向いているケース | 導入前の確認事項 |
|---|---|---|
| 自社店舗のAPI連携 | 認可された店舗の業務データを扱う | 必要な操作と項目をアプリ・販売者の権限で利用できるか |
| Pythonとブラウザーで自作 | 独自の検証が必要で、開発・保守を担当できる | 市場ごとの変更対応、鮮度、網羅性を誰が管理するか |
| ノーコードツール | 少量の処理を画面操作で組みたい | 現在のテンプレートがページ、仕様、ページ送りに対応するか |
| データ収集代行 | 収集プログラムの保有より納品と保守を重視する | 検収済みレコード、取得失敗、課金単位をどう定義するか |
OctoparseのLazadaガイドは、画面操作による収集と出力の流れを紹介しています。Actowizのサービスページは、代行による納品やAPIを使う選択肢を説明しています。
いずれも提供元の説明であり、独立した性能試験ではありません。利用を認められた対象から現在のサンプルを取得してもらい、必要な項目を満たすか確認します。過去のチュートリアルや営業用データだけでは、現在のページへの対応は判断できません。

依頼時には、次の5点を明文化します。
- 対象範囲: 国・サイト、URL一覧または発見方法、仕様と販売者の範囲、対象外の情報。
- 項目定義: 識別子、表示価格と支払総額、通貨、評価、在庫、欠損値の扱い。
- 鮮度: 取得日時、納品日時、更新周期、取得不能時の処理。
- 品質: 重複判定、項目の抜き取り確認、確認待ちレコード、網羅性の分母、ページ変更への対応。
- 契約条件: 課金単位、最低利用量、失敗時の課金、訂正・再納品、保存期間、再利用の範囲。
最初は小さな納品サンプルを検収します。商品名と価格があれば基本的な抽出には合格しても、支払総額の比較要件には届かない場合があります。「成功率が高い」という説明には、分子、分母、サンプル、失敗の扱いを確認してください。
8. 活用例:シンガポールの商品価格を定期監視する
価格監視では、商品と仕様を対応付けてから変化を追います。表示価格の推移と、送料・クーポンを含む支払総額の比較は、別の判定として設計します。
ブランドの担当チームが、シンガポールの20商品・バリエーションを1日1回確認する許可を得たとします。目的は、自社の商品台帳と対応付けた商品の変化を把握することで、全販売者や全レビューの収集ではありません。
20件の確認予定が、20回のブラウザーリクエストになるとは限りません。描画中に複数のリソースを読み込むためです。失敗した確認も、対象の網羅性を示す集計に含めます。
まず、取得元の商品、選択中の仕様、販売者を社内の商品番号と対応付けます。表示価格、通貨SGD、在庫状態を記録し、送料やクーポン条件は分けて保存します。この業務例では、青色350mlと赤色500mlのマグを同一条件の商品として扱いません。これはローカルコードの2件とは別の比較例です。在庫項目がなければ、在庫切れ通知ではなく確認待ちにします。
Lazada固有の項目も、次のように扱います。
- listing_type、cross_border、ship_from_country、shipping_fee、lead_time_daysを個別に記録します。
- LazMallとMarketplaceを区別しますが、その区分だけで国内発送と判断しません。
- 到着まで時間のかかる海外発送の商品を、国内の短納期商品と同じ基準で順位付けしません。
- 発送元、送料、配送条件が不明なら、比較を保留します。
クーポン処理では、platform_voucher、seller_voucher、bundle_offerを分けます。同じ購入数量で、対象仕様、最低購入額、割引上限、有効期限、併用条件を確認してから価格を計算します。条件が確認できなければ表示価格のみを報告し、支払総額やクーポン適用後の節約額を算出しません。

必要な購入条件を確認した後で、別の比較処理が価格通知の対象を決めます。掲載コードのcomparison_eligibleはFalseのままで、決済処理やクーポン判定は実装していません。ただし、検証済みの表示価格は、集計条件を明示すれば推移の分析に利用できます。
この処理でシンガポールの出口が必要な場合に、対応するプロキシを設定し、収集クライアントから接続を確認します。そのうえで有効レコード数と保守費用を計測します。ここでの説明は業務設計例であり、顧客の実績やSocks5.IOのLazada接続試験を示すものではありません。
9. まとめ:比較できる商品データを、小さく検証して育てる
Lazadaのスクレイピングでは、取得権限と項目定義を先に固め、保存したデータを検証してから収集範囲を広げます。正しく識別でき、価格の条件を説明できる記録が、業務に使えるデータです。
まずローカルのPythonサンプルを動かし、次に許可された取得元の構造へ合わせます。ノーコードツールや代行サービスを選ぶ場合も、少量のサンプルで項目と納品条件を確認します。
通信経路に地域や住宅回線の要件がある場合は、Socks5.IOを設定し、収集クライアントから検証します。拡張の判断には、リクエスト数やCSVの行数ではなく、検収できたデータ、対象の網羅性、鮮度、維持費用を使ってください。






