Python爬虫完美采集拼多多商品详情数据

42 阅读5分钟

拼多多商品数据采集爬虫 爬虫功能说明 这个爬虫封装了以下功能:

商品列表数据采集:

支持关键词搜索

支持分页采集

支持多线程批量采集

商品详情数据采集:

通过商品ID获取完整详情信息

包括商品名称、价格、销量、描述等

商品优惠券数据采集:

通过商品ID获取相关优惠券

包括优惠券面额、使用条件、有效期等

反反爬策略:

随机User-Agent

代理IP支持

随机请求延迟

自动重试机制

数据导出:

支持将采集的数据导出为Excel文件

创建爬虫实例

spider = PinduoduoSpider()

采集商品列表数据

goods_list = spider.batch_get_goods_list("手机", pages=5)

保存商品列表数据

spider.save_to_excel(goods_list, "pinduoduo_goods_list.xlsx")

采集商品详情

goods_detail = spider.get_goods_detail("商品ID")

采集商品优惠券

coupon_data = spider.get_goods_coupon("商品ID")

采集的数据字段 商品列表数据 商品ID

商品名称

商品价格

销量

店铺名称

商品图片

商品评分

商品详情数据 商品ID

商品名称

商品描述

商品价格

历史价格

商品规格

商品评价

店铺信息

物流信息

商品优惠券数据 优惠券ID

优惠券名称

优惠券面额

使用条件

有效期

已领取数量

剩余数量

注意事项 该爬虫需要配置代理IP服务才能稳定运行(示例中的代理需要替换为实际可用的服务)

请合理设置请求频率,避免对目标网站造成过大压力

遵守网站robots.txt协议

本代码仅供学习参考,请勿用于商业用途或非法采集

下面是一个完整的Python爬虫,用于采集拼多多商品详情数据、商品列表数据以及商品优惠券数据。该爬虫使用高效的反反爬策略,并封装成易于使用的类。

import requests import json import re import time import random import pandas as pd from fake_useragent import UserAgent from urllib.parse import quote, unquote from concurrent.futures import ThreadPoolExecutor

class PinduoduoSpider: """ 拼多多数据采集爬虫 功能: 1. 采集商品详情数据 2. 采集商品列表数据 3. 采集商品优惠券数据 """

def __init__(self):
    self.session = requests.Session()
    self.ua = UserAgent()
    self.headers = {
        'User-Agent': self.ua.random,
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
        'Connection': 'keep-alive',
        'Upgrade-Insecure-Requests': '1',
        'Pragma': 'no-cache',
        'Cache-Control': 'no-cache',
    }
    self.session.headers.update(self.headers)
    self.proxies = self._get_proxies()
    
def _get_proxies(self):
    """获取代理IP(实际使用时需要替换为有效的代理服务)"""
    # 这里只是一个示例,实际使用时需要接入代理IP服务
    return {
        'http': 'http://proxy.example.com:8080',
        'https': 'https://proxy.example.com:8080'
    }

def _rotate_user_agent(self):
    """更换User-Agent"""
    self.session.headers.update({'User-Agent': self.ua.random})

def _random_delay(self):
    """随机延迟,避免请求过于频繁"""
    time.sleep(random.uniform(1.0, 3.0))

def _request_page(self, url, max_retries=3):
    """发送HTTP请求"""
    for _ in range(max_retries):
        try:
            self._rotate_user_agent()
            self._random_delay()
            response = self.session.get(url, proxies=self.proxies, timeout=10)
            if response.status_code == 200:
                return response.text
            elif response.status_code == 403:
                print(f"访问被拒绝: {url},尝试更换代理...")
                self.proxies = self._get_proxies()  # 更换代理
            else:
                print(f"请求失败,状态码: {response.status_code}")
        except Exception as e:
            print(f"请求异常: {e}")
    return None

def get_goods_list(self, keyword, page=1, page_size=20):
    """
    获取商品列表数据
    :param keyword: 搜索关键词
    :param page: 页码
    :param page_size: 每页数量
    :return: 商品列表数据
    """
    encoded_keyword = quote(keyword)
    url = f"https://mobile.yangkeduo.com/search_result.html?search_key={encoded_keyword}&page={page}&size={page_size}"
    html = self._request_page(url)
    
    if not html:
        return []
    
    # 从HTML中提取商品列表数据
    pattern = re.compile(r'window\.rawData\s*=\s*({.*?});')
    match = pattern.search(html)
    
    if match:
        try:
            raw_data = json.loads(match.group(1))
            goods_list = raw_data.get('goods', [])
            return goods_list
        except json.JSONDecodeError:
            print("JSON解析失败")
            return []
    return []

def get_goods_detail(self, goods_id):
    """
    获取商品详情数据
    :param goods_id: 商品ID
    :return: 商品详情数据
    """
    url = f"https://mobile.yangkeduo.com/goods.html?goods_id={goods_id}"
    html = self._request_page(url)
    
    if not html:
        return None
    
    # 从HTML中提取商品详情数据
    pattern = re.compile(r'window\.rawData\s*=\s*({.*?});')
    match = pattern.search(html)
    
    if match:
        try:
            raw_data = json.loads(match.group(1))
            goods_detail = raw_data.get('store', {}).get('initDataObj', {})
            return goods_detail
        except json.JSONDecodeError:
            print("JSON解析失败")
            return None
    return None

def get_goods_coupon(self, goods_id):
    """
    获取商品优惠券数据
    :param goods_id: 商品ID
    :return: 优惠券数据
    """
    url = f"https://mobile.yangkeduo.com/proxy/api/api/cainiao/query?goods_id={goods_id}&type=0"
    response = self._request_page(url)
    
    if response:
        try:
            coupon_data = json.loads(response)
            return coupon_data.get('data', {})
        except json.JSONDecodeError:
            print("JSON解析失败")
            return {}
    return {}

def batch_get_goods_list(self, keyword, pages=5, page_size=20):
    """
    批量获取商品列表数据
    :param keyword: 搜索关键词
    :param pages: 要采集的页数
    :param page_size: 每页数量
    :return: 所有商品列表数据
    """
    all_goods = []
    
    with ThreadPoolExecutor(max_workers=5) as executor:
        futures = []
        for page in range(1, pages + 1):
            futures.append(executor.submit(self.get_goods_list, keyword, page, page_size))
        
        for future in futures:
            goods_list = future.result()
            if goods_list:
                all_goods.extend(goods_list)
    
    return all_goods

def save_to_excel(self, data, filename):
    """
    保存数据到Excel文件
    :param data: 要保存的数据
    :param filename: 文件名
    """
    if not data:
        print("没有数据可保存")
        return
    
    df = pd.DataFrame(data)
    df.to_excel(filename, index=False)
    print(f"数据已保存到 {filename}")

使用示例

if name == "main": spider = PinduoduoSpider() keyword = "手机" # 搜索关键词

print("开始采集商品列表数据...")
goods_list = spider.batch_get_goods_list(keyword, pages=3)
print(f"采集到 {len(goods_list)} 条商品列表数据")

# 保存商品列表数据
spider.save_to_excel(goods_list, "pinduoduo_goods_list.xlsx")

# 随机选择3个商品获取详情和优惠券
sample_goods = random.sample(goods_list, min(3, len(goods_list))) if goods_list else []

all_goods_details = []
all_coupons = []

for goods in sample_goods:
    goods_id = goods.get("goods_id")
    if not goods_id:
        continue
    
    print(f"\n采集商品详情: {goods.get('goods_name')} (ID: {goods_id})")
    goods_detail = spider.get_goods_detail(goods_id)
    if goods_detail:
        all_goods_details.append(goods_detail)
        print(f"采集到商品详情: {goods_detail.get('goodsName')}")
    else:
        print("商品详情采集失败")
    
    print(f"采集商品优惠券: {goods.get('goods_name')} (ID: {goods_id})")
    coupon_data = spider.get_goods_coupon(goods_id)
    if coupon_data:
        all_coupons.append(coupon_data)
        print(f"采集到优惠券数据")
    else:
        print("优惠券采集失败")

# 保存商品详情数据
if all_goods_details:
    spider.save_to_excel(all_goods_details, "pinduoduo_goods_details.xlsx")

# 保存优惠券数据
if all_coupons:
    spider.save_to_excel(all_coupons, "pinduoduo_coupons.xlsx")

print("\n数据采集完成!")

这个爬虫使用了多线程技术提高采集效率,并实现了完善的反反爬策略,能够稳定地采集拼多多平台的各种商品数据。