拼多多商品信息爬取
拼多多商品信息爬取
爬取完几个主流电商平台的信息,今天想着也去攻克一下拼多多。于是先去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、店铺信息在商品页列表里面每次请求会有所缺失,故需到商品页里面获取,但是商品页需要带请求参数,主要是
cookie
和AccessToken
(访问令牌)。这两个参数会过期,解决方法后面讨论。
二、爬取字段
店铺信息获取比较麻烦,如果不要的话会简单很多,商品评价如果要获取可以参考一下上面的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() # 店铺名字
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
三、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('数据获取不全,重新获取')
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
四、最后
不知道什么时候的数据