プロキシで商品レビューを大規模にスクレイピングする方法

Amazonや他のプラットフォームから製品のレビューをスケールでスクレイピングすることを学びます。 Python と Node.js のコードは、マルチプラットフォームのレビューコレクション、パジネーション処理、および sendiment 解析の準備に使用されます.

プロキシで商品レビューを大規模にスクレイピングする方法

なぜスケールで製品のレビューをScrape?

製品レビューは、電子商取引における最も貴重なデータソースの一つです。 顧客の感情、製品品質の問題、機能要求、競争力のある位置を明らかにし、他のデータソースが提供できない情報。 スケールで、レビューデータを有効化:

  • センチメント分析: お客様が製品や競合他社の製品について、時間をかけてどのように感じているかを追跡します。
  • プロダクト開発: クレームや機能リクエストを数千件のレビューで識別します。
  • 競争力のあるインテリジェンス: 競合他社の強みや弱みをお客様自身の言葉から把握します。
  • 市場調査: さまざまなカテゴリーでレビューパターンを分析することで、不要なニーズや新しいトレンドを発見。
  • 質の監視: 製品の品質問題を早期に検出し、レビューの送信傾向を監視します。

課題は、データが複数のプラットフォーム(Amazon、Walmart、Best Buy、Trustpilot、Google)に分散し、それぞれ異なる構造とアンチボット保護を持つことです。 スケールでのスクレイピングレビューには、プラットフォーム固有の戦略と堅牢なプロキシインフラストラクチャが必要です。 基礎的なeコマーススクレイピングパターンについては、こちらをご覧ください eコマースデータスクレイピングガイド. .

プラットフォーム間でのデータ構造を確認する

プラットフォーム間でのデータ構造を確認する
プラットフォームレビューフィールドパジネーションアンチボットレベル
アマゾン評価、タイトル、テキスト、日付、検証、有用な投票ページベース(10/ページ)高い
ウォルマート評価、タイトル、テキスト、日付、投稿ソースオフセットベース APIメディア
最高の購入評価、タイトル、テキスト、日付、有用/非役立つページベースAPIメディア
トラストパイロット評価、タイトル、テキスト、日付、応答ページベース低媒体
Googleショッピング評価、テキスト、日付、ソーススクロールベース高い

レビューのスクレイピングのためのプロキシ構成

スクラップレビューは、複数のリクエスト間でセッションを維持することを意味し、 paginatedナビゲーションを含みます。 ProxyHatのスティッキーセッションは、このパターンに理想的です。

ProxyHat セットアップ

# Per-request rotation for initial product lookups
http://USERNAME:PASSWORD@gate.proxyhat.com:8080
# Sticky session for paginating through reviews of one product
http://USERNAME-session-rev001:PASSWORD@gate.proxyhat.com:8080
# Geo-targeted for region-specific review pages
http://USERNAME-country-US:PASSWORD@gate.proxyhat.com:8080

レビューのスクレイピングのために、粘りのあるセッションを使用して、すべてのレビューを1つの製品にペギンティングし、異なる製品間で移動するときに1回の探求回転を使用します。 この mimics は、次の製品に移動する前に、ユーザーが複数のレビューを 1 つの製品に読む自然な閲覧行動を模倣します。

Pythonの実装

ここでは、マルチプラットフォームのレビュースクレーパーを使用して ProxyHatのPython SDK. .

Amazon レビュー スクレーパー

import requests
from bs4 import BeautifulSoup
import json
import time
import random
from dataclasses import dataclass
from datetime import datetime
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
]
@dataclass
class Review:
    platform: str
    product_id: str
    rating: float
    title: str
    text: str
    date: str
    author: str
    verified: bool
    helpful_votes: int
def scrape_amazon_reviews(asin, max_pages=10):
    """Scrape all reviews for an Amazon product."""
    reviews = []
    session_id = f"rev-{asin}-{random.randint(1000, 9999)}"
    proxy = f"http://USERNAME-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"
    session = requests.Session()
    session.proxies = {"http": proxy, "https": proxy}
    session.headers.update({
        "User-Agent": random.choice(USER_AGENTS),
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
    })
    for page in range(1, max_pages + 1):
        url = (f"https://www.amazon.com/product-reviews/{asin}"
               f"?pageNumber={page}&sortBy=recent")
        try:
            response = session.get(url, timeout=30)
            if response.status_code != 200:
                break
            if "captcha" in response.text.lower():
                print(f"CAPTCHA on page {page}, switching session")
                break
            soup = BeautifulSoup(response.text, "html.parser")
            review_divs = soup.find_all("div", {"data-hook": "review"})
            if not review_divs:
                break
            for div in review_divs:
                review = parse_amazon_review(div, asin)
                if review:
                    reviews.append(review)
            print(f"Page {page}: {len(review_divs)} reviews (total: {len(reviews)})")
            time.sleep(random.uniform(2, 5))
        except requests.RequestException as e:
            print(f"Error on page {page}: {e}")
            break
    return reviews
def parse_amazon_review(div, asin):
    """Parse a single Amazon review element."""
    try:
        rating_el = div.find("i", {"data-hook": "review-star-rating"})
        rating = float(rating_el.get_text().split(" ")[0]) if rating_el else None
        title_el = div.find("a", {"data-hook": "review-title"})
        title = title_el.get_text(strip=True) if title_el else ""
        body_el = div.find("span", {"data-hook": "review-body"})
        text = body_el.get_text(strip=True) if body_el else ""
        date_el = div.find("span", {"data-hook": "review-date"})
        date_str = date_el.get_text(strip=True) if date_el else ""
        author_el = div.find("span", {"class": "a-profile-name"})
        author = author_el.get_text(strip=True) if author_el else ""
        verified = bool(div.find("span", {"data-hook": "avp-badge"}))
        helpful_el = div.find("span", {"data-hook": "helpful-vote-statement"})
        helpful = 0
        if helpful_el:
            text_h = helpful_el.get_text()
            if "one" in text_h.lower():
                helpful = 1
            else:
                nums = [int(s) for s in text_h.split() if s.isdigit()]
                helpful = nums[0] if nums else 0
        return Review(
            platform="amazon",
            product_id=asin,
            rating=rating,
            title=title,
            text=text,
            date=date_str,
            author=author,
            verified=verified,
            helpful_votes=helpful,
        )
    except Exception:
        return None

マルチプラットフォームレビューコレクター

class ReviewCollector:
    """Collect reviews from multiple platforms for a product."""
    def __init__(self):
        self.scrapers = {
            "amazon": scrape_amazon_reviews,
        }
    def collect_all(self, product_ids: dict) -> list[Review]:
        """
        Collect reviews from all platforms.
        product_ids: {"amazon": "B0CHX3QBCH", "walmart": "12345"}
        """
        all_reviews = []
        for platform, product_id in product_ids.items():
            if platform in self.scrapers:
                print(f"\nScraping {platform} reviews for {product_id}")
                reviews = self.scrapers[platform](product_id)
                all_reviews.extend(reviews)
                print(f"Collected {len(reviews)} reviews from {platform}")
                time.sleep(random.uniform(5, 10))
        return all_reviews
    def to_dataframe(self, reviews: list[Review]):
        """Convert reviews to a pandas DataFrame for analysis."""
        import pandas as pd
        return pd.DataFrame([vars(r) for r in reviews])
# Usage
collector = ReviewCollector()
reviews = collector.collect_all({
    "amazon": "B0CHX3QBCH",
})
print(f"\nTotal reviews collected: {len(reviews)}")

Node.js 実装

Node.jsレビュースクレーパーを使用して ProxyHat ノード SDK. .

const axios = require("axios");
const cheerio = require("cheerio");
const { HttpsProxyAgent } = require("https-proxy-agent");
function getProxy(sessionId = null) {
  if (sessionId) {
    return `http://USERNAME-session-${sessionId}:PASSWORD@gate.proxyhat.com:8080`;
  }
  return "http://USERNAME:PASSWORD@gate.proxyhat.com:8080";
}
async function scrapeAmazonReviews(asin, maxPages = 10) {
  const reviews = [];
  const sessionId = `rev-${asin}-${Math.floor(Math.random() * 9000 + 1000)}`;
  const agent = new HttpsProxyAgent(getProxy(sessionId));
  for (let page = 1; page <= maxPages; page++) {
    const url = `https://www.amazon.com/product-reviews/${asin}?pageNumber=${page}&sortBy=recent`;
    try {
      const { data } = await axios.get(url, {
        httpsAgent: agent,
        headers: {
          "User-Agent":
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36",
          "Accept-Language": "en-US,en;q=0.9",
        },
        timeout: 30000,
      });
      if (data.toLowerCase().includes("captcha")) {
        console.log(`CAPTCHA on page ${page}`);
        break;
      }
      const $ = cheerio.load(data);
      const reviewDivs = $('[data-hook="review"]');
      if (reviewDivs.length === 0) break;
      reviewDivs.each((_, el) => {
        const $el = $(el);
        const ratingText = $el.find('[data-hook="review-star-rating"]').text();
        const rating = parseFloat(ratingText.split(" ")[0]) || null;
        reviews.push({
          platform: "amazon",
          productId: asin,
          rating,
          title: $el.find('[data-hook="review-title"]').text().trim(),
          text: $el.find('[data-hook="review-body"]').text().trim(),
          date: $el.find('[data-hook="review-date"]').text().trim(),
          author: $el.find(".a-profile-name").text().trim(),
          verified: $el.find('[data-hook="avp-badge"]').length > 0,
        });
      });
      console.log(`Page ${page}: ${reviewDivs.length} reviews (total: ${reviews.length})`);
      await new Promise((r) => setTimeout(r, 2000 + Math.random() * 3000));
    } catch (err) {
      console.error(`Error page ${page}: ${err.message}`);
      break;
    }
  }
  return reviews;
}
// Usage
scrapeAmazonReviews("B0CHX3QBCH", 5).then((reviews) => {
  console.log(`Collected ${reviews.length} reviews`);
  console.log(JSON.stringify(reviews.slice(0, 2), null, 2));
});

スケールでのパジネーション処理

大規模なレビュースクレイピングで最大の課題の1つです。

Amazonパジネーション戦略

Amazonでは、レビューページを10レビューに制限し、通常最大500ページ(5,000レビュー)が表示されます。 より多くのレビューを持つ製品には、フィルタパラメータを使用してセグメントに使用します。

# Filter by star rating to get more reviews
star_filters = [
    "one_star", "two_star", "three_star",
    "four_star", "five_star"
]
for star in star_filters:
    url = (f"https://www.amazon.com/product-reviews/{asin}"
           f"?filterByStar={star}&pageNumber={page}")
    # This lets you access more reviews per product

パジネーションセッション管理

各製品のレビューペジネーションは、独自のスティッキーセッションを使用する必要があります。 1つの製品を終了し、次に移動すると、異なるIPで新しいセッションを作成します。

パジネーションセッション管理
フェーズプロキシ戦略レイソン
製品を探すパーリクエスト回転独立したルックアップ、セッション不要
レビューの開始製品の粘着セッションページ全体で同じIPが自然に見える
製品について新規セッション/IP各製品の新鮮な身元

センチメント分析のためのデータの準備

生の見直しのテキストは、感情解析の前に、前処理が必要です。

import re
from collections import Counter
def clean_review_text(text):
    """Clean review text for analysis."""
    # Remove HTML entities
    text = re.sub(r'&\w+;', ' ', text)
    # Remove excessive whitespace
    text = re.sub(r'\s+', ' ', text).strip()
    # Remove very short reviews (likely not useful)
    if len(text) < 20:
        return None
    return text
def extract_key_phrases(reviews, min_frequency=3):
    """Extract frequently mentioned phrases from reviews."""
    from collections import Counter
    import re
    words = []
    for review in reviews:
        if review.text:
            # Simple bigram extraction
            tokens = re.findall(r'\b\w+\b', review.text.lower())
            for i in range(len(tokens) - 1):
                bigram = f"{tokens[i]} {tokens[i+1]}"
                words.append(bigram)
    return Counter(words).most_common(50)
def aggregate_sentiment(reviews):
    """Calculate aggregate sentiment metrics."""
    if not reviews:
        return {}
    ratings = [r.rating for r in reviews if r.rating]
    return {
        "total_reviews": len(reviews),
        "avg_rating": sum(ratings) / len(ratings) if ratings else 0,
        "rating_distribution": {
            str(i): len([r for r in reviews if r.rating == i])
            for i in range(1, 6)
        },
        "verified_pct": (
            len([r for r in reviews if r.verified]) / len(reviews) * 100
            if reviews else 0
        ),
    }

何百万人もの口コミをスケーリング

ターゲットリストが複数のプラットフォーム間で何千もの製品に成長する場合、アーキテクチャの問題。

キューベースアーキテクチャ

  • メッセージキュー (Redis, RabbitMQ) を使用して、製品リストを管理し、労働者間で作業を配布します。
  • 各ワーカーは、1つの製品を一度に処理します。すべてのレビュー、ストア結果を通して、次の製品に移動します。
  • 異なるレートの制限を尊重するプラットフォームごとのキューを分離します。

ストレージ戦略

  • パーサが変更したときに、オブジェクトストレージ(S3)で未加工HTMLを保存します。
  • PostgreSQL で解析のための全文検索で解析されたレビューを保存します。
  • レビューIDまたはハッシュに基づいて重複排除を使用して、再処理に重複を保存しないようにします。

イントレメンタルスクレイピング

継続的な監視では、毎回すべてのレビューを再処理する必要はありません。 あなたがすでに収集したレビューに当たると、最新かつ停止でソートします。 これにより、プロキシの使用量を劇的に削減し、コレクションをスピードアップ。

キーテイクアウト: 以前に収集したコンテンツをヒットしたときに、最新の最初からレビューをソートし、スクレイピングを停止します。 これは、増分の更新に完全に再処理されます。

ベストプラクティス

  • pagination 用のスティッキーセッションを使用する: アンチボット検出のトリガーを避けるために、レビューページ全体で同じIPを維持します。
  • レートの限界を点検して下さい: 2-5 ページ間の秒間遅延、製品間の長い遅延。 異なるプラットフォームは異なる許容値を持っています。
  • 空のページを処理する: 空のレビューページは、最後に到達したことを意味します。 より多くのページを試し続けないでください。
  • 有効なデータ品質: CAPTCHAページ、空のコンテンツ、およびパイプラインでのレビューを複製するためのチェック。
  • 使用条件 住宅のプロキシ: : : Amazonなどの保護されたプラットフォームに不可欠です。
  • 増分保存: 処理し、最後に1つのバッチではなく、それらを掻くようにレビューを保存します。

キーテイクアウト

  • 他のデータソースが提供していない独自の競争力のあるインテリジェンスを提供します。
  • 異なるプラットフォームは、プラットフォームごとにモジュラースクレーパーを構築し、異なるスクレイピング戦略を必要とします。
  • 製品間のペジネーションとパーリクエストの回転をレビューするために、スティッキーセッションを使用します。
  • 新しく最初にソートし、以前に収集したレビューでストップし、効率的なインクリメンタルスクレイピングを実現します。
  • 送信分析のための事前プロセスレビューテキスト:きれいで、重複し、キーフレーズを抽出します。
  • 使用条件 ProxyHatの住宅用プロキシ ジオターゲティングで、すべてのプラットフォーム間でページをレビューする信頼性の高いアクセスを実現します。

レビューデータを収集する準備はできましたか? お問い合わせ Amazonスクレイピングガイド プラットフォーム固有の詳細と当社の eコマースデータスクレイピングガイド 完全な戦略のため。 チェックイン Pythonでプロキシを使う そして、 Node.js でプロキシを使用する 実装パターンのため。

始める準備はできましたか?

AIフィルタリングで148か国以上、5,000万以上のレジデンシャルIPにアクセス。

料金を見るレジデンシャルプロキシ
← ブログに戻る