<p>在上一个任务完成之后,任务的最后是通过crontab设置每天8点,13点,18点,23点,定时采集任务,而该篇内容的目的就是在每天23点最后一次任务完成之后,对该天采集的数据进行处理,时间设定在23点30分,也是采用crontab来定时开启。</p>
<p>这个只要通过SQLite将每天收集的数据重新提取出来,由于我们的当天的销售数据是收集在SCOUNT表格中,而数据的列名称是依据时间来命名,为了获得当天四个时间点采集的销售数据,需要先获得列名称。</p>
<p>在SQLite里面,可以通过 Pragma 获得所有的列名称信息,Pragma有两个功能,包括更改内部操作以及获得表格固有数据,通过其中的table_info,既可以获得列名称信息,所有列名称信息获得后,通过 list comprehensions (这个实在不知道怎么翻译),可以获得今天的新生成的4个销售数据列:</p>
<p>然后就是获得进行的销售数据,由于每个SKU一天将采集四次数据,并且收集的SKU有下架的可能,SKU列表中的不是每个SKU都有可能被采集,所以对采集出来需要的数据需要 dropna ,并且需要将SKU信息表格和销售数据表格通过 merge 函数合并,形成我们需要的data。每个SKU在每个时刻采集的数据会出现波动,销量数据并不是一个连续增长的过程,因此为了求得当天的销量,可取一天中最大数和最小数差值。</p>
<p>生成销售额的方法类似,就不在这里列出。</p>
<p>生成PDF,这是当时的一个设想,后来参考这篇 教程 做出来了( Practical Business Python 是个好网站,推荐),原理是通过DataFrame转化为HTML,再将HTML转化为PDF。但是写邮件模块的时候,发现邮件可以内嵌HTML,因此就没有必要专门生成PDF,再通过邮件以附件的形式发送了。但在这里,还是先梳理下整个流程:</p>
<p>采用 Jinja2 生成PDF,首先需要生成一个模板,模板里面需设定好HTML的样式,这是参考教程写出的一个HTML的样式:</p>
<p>完成后,再将DataFrame通过 to_html 函数转化为HTML并填入到样式中。</p>
<p>最后生成PDF,只加入一个模块喝一句话就可以了。 weasyprint 这个模块是专门用于将HTML或者CSS转化为PDF:</p>
<p>python里面有专门的发送邮件模块, email 模块。邮件的模块包括两部分,一部分是邮件正文模块,一部分邮件发送模块:</p>
<p>邮件正文模块,通过MIMEText完成。在email模块里面有专门的( MIME , Multipurpose Internet Mail Extensions,多用途互联网邮件扩展)模块,用来生成对应的邮件正文类型。在这里先采用文本模块MIMEText做个示范:</p>
<p>然后就是发送邮件了,需要经过 stmplib 模块,下面详细讲讲。发送邮件首先需要设置 smtp (Simple Mail Transfer Protocol,简单邮件传输协议)的地址和端口,然后部分邮箱需要采用TTS加密协议的时候,则需要使用starttts()函数。然后对应的是登陆的用户名的密码,再将上面编写的msg发出去,最后quit即可。</p>
<p>总结下,之前设定的任务大体完成了。但是还是有很多可以深化的内容,例如前面采用DataFrame的时候,没有对数据进行可视化,HTML的模板还可以再美化下,另外假如引入了数据可视化,要怎么将可视化的图片嵌入到邮件中。邮件登陆那部分,部分邮箱没有办法采用这个方法发出(需要再考虑smtp设置)。</p>
<p>上面这些问题,后续会继续以小项目的形式进行研究。后面还可以进行平台之间的销售情况对比等等,总而言之,该项目还是有很大的扩张空间的。嘛,这一次就先这样结束吧。</p>
本编博客是关于爬取天猫店铺中指定店铺的所有商品基础信息的爬虫,爬虫运行只需要输入相应店铺的域名名称即可,信息将以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 = ''.format(storename)
self.headers = {
"user-agent":"Mozilla/5.0 (iPhoneCPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 "
"(KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
}
datenum = datetime.now().strftime('%Y%m%d%H%M')
self.filename = '{}_{}.csv'.format(self.storename, datenum)
self.get_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 = requests.get(url,headers=self.headers).text
infos = re.findall('\(({.*})\)',html)[0]
infos = json.loads(infos)
totalpage = infos.get('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 = requests.get(url, headers=self.headers).text
infos = re.findall('\(({.*})\)', html)[0]
infos = json.loads(infos)
products = infos.get('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 = self.get_totalpage()
for i in range(1,total_page+1):
self.get_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 都是时间库,前者一般用来生成当前时间字符串,后者本爬虫使用设置延迟时间
爬虫思路
首先通过分析手机端天猫店铺所有商品的网页,可以发现每次下滑一页都有一个 js 被加载,这个 js 的规律可以总结一下;
通过分析可以发现每次请求 js 都可以得到一个关键信息,那就是 total_page 这个参数,这也一想就能猜到,就是当前店铺的总页码数,所以可以先取得这个数字,然后使用循环爬取全店商品;
每一页有24个商品,而请求得到的是一个类似于 json 格式的网页信息,但是并非是直接的 json,所以可以用正则表达式提取符合 json 格式的部分留用;
将每一页的信息保存到 csv 表格中,可以直接使用 csv 库的字典存储方式,非常方便;
得到了单页的信息,也得到了总页码数,只需要一个循环就可以爬取全店的商品了。
构造爬虫类
def __init__(self,storename):self.storename = storename
self.url = '.format(storename)
self.headers = {
"user-agent":"Mozilla/5.0 (iPhoneCPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 "
"(KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
}
datenum = datetime.now().strftime('%Y%m%d%H%M')
self.filename = '{}_{}.csv'.format(self.storename, datenum)
self.get_file()
上面代码依次完成以下操作:
首先整个爬虫是写成了一个类,在初始化类的时候需要传递一个参数,这个参数就是店铺的名称。
然后构造出店铺的所有商品页面的前半部分,这部分都是不会变的
接着设置一个请求头
按照当前时间生成一个以时间为依据的字符串,用来给文件命名,然后赋值给文件名称,确定保存文件的名称
最后一句是在类生成的时候就运行这个函数,及生成一个带有标题的表格,后面会说道这个函数的具体含义