利⽤Python爬⾍爬取指定天猫店铺全店商品信息
本编博客是关于爬取天猫店铺中指定店铺的所有商品基础信息的爬⾍,爬⾍运⾏只需要输⼊相应店铺的域名名称即可,信息将以csv表格的形式保存,可以单店爬取也可以增加⼀个循环进⾏同时爬取。
源码展⽰
⾸先还是完整代码展⽰,后⾯会分解每个函数的意义。
# -*- coding: utf-8 -*-
import requests
import json
import csv
import random
import re
from datetime import datetime
import time
class TM_producs(object):
def __init__(self,storename):
self.storename = storename
self.url = '{}.m.tmall'.format(storename)
self.headers = {
"user-agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 "
"(KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
}
datenum = w().strftime('%Y%m%d%H%M')
self.filename = '{}_{}.csv'.format(self.storename, datenum)
<_file()
def get_file(self):
'''创建⼀个含有标题的表格'''
title = ['item_id','price','quantity','sold','title','totalSoldQuantity','url','img']
with open(self.filename,'w',newline='') as f:
writer = csv.DictWriter(f,fieldnames=title)
writer.writeheader()
return
def get_totalpage(self):
'''提取总页码数'''
num = random.randint(83739921,87739530)
endurl = '/shop/shop_auction_search.do?sort=s&p=1&page_size=12&from=h5&ajson=1&_tm_source=tmallsearch&callback=jsonp_{}'
url = self.url + endurl.format(num)
html = (url,headers=self.headers).text
infos = re.findall('\(({.*})\)',html)[0]
infos = json.loads(infos)
totalpage = ('total_page')
return int(totalpage)
def get_products(self,page):
'''提取单页商品列表'''
num = random.randint(83739921, 87739530)
endurl = '/shop/shop_auction_search.do?sort=s&p={}&page_size=12&from=h5&ajson=1&_tm_source=tmallsearch&callback=jsonp_{}'
url = self.url + endurl.format(page,num)
html = (url, headers=self.headers).text
python正则表达式爬虫infos = re.findall('\(({.*})\)', html)[0]
infos = json.loads(infos)
products = ('items')
title = ['item_id', 'price', 'quantity', 'sold', 'title', 'totalSoldQuantity', 'url', 'img']
with open(self.filename, 'a', newline='') as f:
writer = csv.DictWriter(f, fieldnames=title)
writer.writerows(products)
def main(self):
'''循环爬取所有页⾯宝贝'''
total_page = _totalpage()
for i in range(1,total_page+1):
<_products(i)
print('总计{}页商品,已经提取第{}页'.format(total_page,i))
time.sleep(1+random.random())
if __name__ == '__main__':
storename = 'uniqlo'
tm = TM_producs(storename)
tm.main()
上⾯代码是选择了优⾐库作为测试店铺,直接输⼊优⾐库店铺的域名中关键词即可,最终表格会按照店铺名称和时间名词。
代码解读
导⼊库说明
requests库不⽤多数,爬取⽹页的主要库
json库是⽤来解析 json 格式的数据的,也就是 Python 中的字典格式
csv库是⽤来创建 csv 表格和保存信息的
random库是⽤来⽣成⼀个随机数的,这个代码中⽤到了两次,第⼀次是⽣成⼀个随机数据去获取最新的⽹页信息⽽不是缓存信息,第⼆次是随机⼀个时间,来减缓爬⾍速度
re库是正则,主要⽤来提取信息
datetime和time都是时间库,前者⼀般⽤来⽣成当前时间字符串,后者本爬⾍使⽤设置延迟时间
爬⾍思路
1. ⾸先通过分析⼿机端天猫店铺所有商品的⽹页,可以发现每次下滑⼀页都有⼀个 js 被加载,这个 js 的规律可以总结⼀下;
2. 通过分析可以发现每次请求 js 都可以得到⼀个关键信息,那就是 total_page 这个参数,这也⼀想就能猜到,就是当前店铺的总页码
数,所以可以先取得这个数字,然后使⽤循环爬取全店商品;
3. 每⼀页有24个商品,⽽请求得到的是⼀个类似于 json 格式的⽹页信息,但是并⾮是直接的 json,所以可以⽤正则表达式提取符合 json
格式的部分留⽤;
4. 将每⼀页的信息保存到 csv 表格中,可以直接使⽤ csv 库的字典存储⽅式,⾮常⽅便;
5. 得到了单页的信息,也得到了总页码数,只需要⼀个循环就可以爬取全店的商品了。
构造爬⾍类
def __init__(self,storename):
self.storename = storename
self.url = '{}.m.tmall'.format(storename)
self.headers = {
"user-agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 "
"(KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
}
datenum = w().strftime('%Y%m%d%H%M')
self.filename = '{}_{}.csv'.format(self.storename, datenum)
<_file()
上⾯代码依次完成以下操作:
⾸先整个爬⾍是写成了⼀个类,在初始化类的时候需要传递⼀个参数,这个参数就是店铺的名称。
然后构造出店铺的所有商品页⾯的前半部分,这部分都是不会变的
接着设置⼀个请求头
按照当前时间⽣成⼀个以时间为依据的字符串,⽤来给⽂件命名,然后赋值给⽂件名称,确定保存⽂件的名称
最后⼀句是在类⽣成的时候就运⾏这个函数,及⽣成⼀个带有标题的表格,后⾯会说道这个函数的具体含义
创建表格
def get_file(self):
'''创建⼀个含有标题的表格'''
title = ['item_id','price','quantity','sold','title','totalSoldQuantity','url','img']
with open(self.filename,'w',newline='') as f:
writer = csv.DictWriter(f,fieldnames=title)
writer.writeheader()
return
这个函数的⽤意是创建⼀个带有标题的表格,标题就是提取的⽹页信息中的 key,这个必须跟需要提取的参数保持⼀致。关于 csv 库按照字典格式保存信息的⽅式可以参考之前的⼀篇⽂章
提取总页码数
def get_totalpage(self):
'''提取总页码数'''
num = random.randint(83739921,87739530)
endurl = '/shop/shop_auction_search.do?sort=s&p=1&page_size=12&from=h5&ajson=1&_tm_source=tmallsearch&callback=jsonp_{}'
url = self.url + endurl.format(num)
html = (url,headers=self.headers).text
infos = re.findall('\(({.*})\)',html)[0]
infos = json.loads(infos)
totalpage = ('total_page')
return int(totalpage)
这个函数其实跟提取信息的函数是⼀样的,只不过需要提取的信息不⼀样⽽已,这个函数只需要提取总页码数。具体步骤是先构造出每页请求的URL,这个需要⾃⼰去总结⼀个最简约的链接形式,并且尽可能模仿⼈⼯浏览。
请求⽹页会得到⼀个类似于 json 的信息,但是不是纯 json ,因此需要使⽤正则来处理⼀下,然后需要⽤到 json 库来转换格式为真正的 json
格式。
提取单页的信息
def get_products(self,page)的⽤法是跟提取总页码数⼀样的,只不过这个需要传⼊⼀个参数,也就是需要爬取的页码数,这样就可以改变 URL 从⽽爬取对应的页码的信息了。
最后提取每页的信息在 json 中是形成⼀个列表的形式,⽽每个列表⼜是⼀个字典,所以可以直接使⽤ csv 的多⾏写⼊的⽅法去保存信息。循环爬取全店商品
def main(self):
'''循环爬取所有页⾯宝贝'''
total_page = _totalpage()
for i in range(1,total_page+1):
<_products(i)
print('总计{}页商品,已经提取第{}页'.format(total_page,i))
time.sleep(1+random.random())
最后⼀个函数就是使⽤循环的⽅式去爬取所有页⾯的信息并保存了,同时可以在每次爬完⼀页之后打印⼀句话作为提⽰,并且为了尽可能的减少IP被封的可能性,可以适当的增加⼀下爬取延迟。