拼多多商品信息爬取

拼多多商品信息爬取

爬取完几个主流电商平台的信息,今天想着也去攻克一下拼多多。于是先去GitHub上面找一下有没有哪位大神搞过了借鉴一下,然后果然发现一个好用的接口。

想着既然找到了就先下载下来跑一下,嗯。。。“热门”的感觉可以,应该很简单。然后就兴高采烈地扩展一下别的商品种类,果然很多坑。。

一、思路分析

经过谷歌F12工具一番分析,总结一下爬取思路:

1、“热门”商品比较特殊,其他商品种类有细分小分类,故需从大分类获取到小分类地址,然后进一步请求。以“女装”为例:地址为:http://apiv3.yangkeduo.com/operation/14/groups?page=1&size=100&opt_type=1 ,size为单页显示商品数量,最大可以400,大分类opt_type为1,小分类opt_type为2,14是“女装”ID。

2、大分类和小分类页面有时第一次请求会失败,需多次请求才能成功,故需要设置一个循环。

3、店铺信息在商品页列表里面每次请求会有所缺失,故需到商品页里面获取,但是商品页需要带请求参数,主要是cookieAccessToken(访问令牌)。这两个参数会过期,解决方法后面讨论。

二、爬取字段

店铺信息获取比较麻烦,如果不要的话会简单很多,商品评价如果要获取可以参考一下上面的GitHub地址,这里先注释掉。
    goods_id = scrapy.Field()  # 商品ID
    goods_name = scrapy.Field()  # 商品名字
    price = scrapy.Field()  # 拼团价格 返回的字段多乘了100
    sales = scrapy.Field()  # 已拼单数量
    normal_price = scrapy.Field()  # 单独购买价格
    # comments = scrapy.Field()  # 商品评价
    opt_id = scrapy.Field()  # 小分类ID
    opt_name = scrapy.Field()  # 小分类名字
    link_url = scrapy.Field()  # 商品地址
    mall_id = scrapy.Field()  # 店铺ID
    mall_name = scrapy.Field()  # 店铺名字

三、spider代码

这次爬虫采用的是scrapy_redis分布式爬取(顺便再熟悉一下),下面放上spider代码:
# -*- coding: utf-8 -*-
import scrapy
import json
from pinduoduo.items import PinduoduoItem
from copy import deepcopy
from scrapy_redis.spiders import RedisSpider
import re


class PdditemSpider(RedisSpider):
    name = 'pdditem'
    allowed_domains = ['yangkeduo.com']
    page = 1  # 起始页码数
    size = 400  # 单页显示数量(最大400)
    opt_type = 1
    offset = 0  # 偏移量100为一页
    # start_urls = ['http://apiv3.yangkeduo.com/operation/14/groups?page={}&size={}&opt_type={}'.format(page, size,opt_type)]  # 女装商品
    # 'http://apiv3.yangkeduo.com/operation/14/groups?page=1&size=400&opt_type=1'
    redis_key = "pinduoduo"

    def parse(self, response):  # 解析分类页
        goods_list_json = json.loads(response.body)
        url = response.url
        keys = goods_list_json.keys()
        key = list(keys)[2]
        if key == "error_code":  # 请求失败获取到错误json代码,重新请求
            print(key, "再次尝试请求")
            yield scrapy.Request(
                url,
                callback=self.parse,
                dont_filter=True
            )
        else:
            item = PinduoduoItem()
            opt_infos = goods_list_json['opt_infos']
            if opt_infos is not None:
                for info in opt_infos:
                    item['opt_id'] = info['id']
                    item['opt_name'] = info['opt_name']
                    yield scrapy.Request(
                        'http://apiv3.yangkeduo.com/operation/'+ str(item['opt_id'])+ '/groups?offset=0&size=100&opt_type=2',
                        callback=self.parse_good,
                        meta={"item": deepcopy(item)}
                    )

    def parse_good(self, response):  # 解析商品页
        item = response.meta["item"]
        goods_list_json = json.loads(response.body)
        url = response.url
        keys = goods_list_json.keys()
        key = list(keys)[-1]
        if key == "error_code":
            print(key,"再次尝试请求")
            yield scrapy.Request(
                url,
                callback=self.parse_good,
                meta={"item": deepcopy(item)},  # 大坑!!重新请求需要带上item
                dont_filter=True
            )
        else:
            goods_list = goods_list_json['goods_list']
            # 判断是否是最后一页
            if not goods_list:
                return
            for each in goods_list:
                item['goods_name'] = each['goods_name']
                item['price'] = float(each['group']['price']) / 100  # 拼多多的价格默认多乘了100
                item['sales'] = each['cnt']
                item['normal_price'] = float(each['normal_price']) / 100
                item['goods_id'] = each['goods_id']
                item['link_url'] = 'http://yangkeduo.com/'+ each['link_url']
                yield scrapy.Request(
                     item['link_url'],
                     callback=self.get_mall_data, meta={"item": item},)

            self.page += 1
            self.offset = self.page*100  # 构造下一页地址
            yield scrapy.Request(url='http://apiv3.yangkeduo.com/operation/'+ str(item['opt_id'])+ '/groups?offset={}&size=100&opt_type=2'.format(self.offset),
                                 callback=self.parse_good,
                                 meta={"item": item}
                                 )

    def get_mall_data(self, response):  # 获取店铺信息
        item = response.meta["item"]
        Cookie = response.request.headers.getlist('Cookie')
        mall_name = response.xpath("//div[@class='goods-mall-name']/text()").extract_first()
        if mall_name is not None:
            item['mall_name'] = mall_name
        data = response.body.decode('utf-8')
        pattern = re.compile(r'mall_id=(.*?)\"', re.S)
        result = re.search(pattern, data)
        if result is not None:
            item['mall_id'] = result.group(1)
        else:
            yield scrapy.Request(
                response.url,
                callback=self.get_mall_data,
                meta={"item": item},
                dont_filter=True
            )
        if item['mall_name'] and item['mall_id']:
            print(item)
            yield (item)
        else:
            print('数据获取不全,重新获取')



四、最后

不知道什么时候的数据
在这里插入图片描述

具体过程和参考代码请见:博客
有任何问题请留言,谢谢。
  • 12
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 51
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 51
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值