利用Python爬虫爬取指定天猫店铺全店商品信息

本编博客是关于爬取天猫店铺中指定店铺的全部商品基础信息的爬虫,爬虫运行只须要输入相应店铺的域名名称便可,信息将以csv表格的形式保存,能够单店爬取也能够增长一个循环进行同时爬取。html

源码展现

首先仍是完整代码展现,后面会分解每一个函数的意义。正则表达式

# -*- 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 = 'https://{}.m.tmall.com'.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 = 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()

上面代码是选择了优衣库做为测试店铺,直接输入优衣库店铺的域名中关键词便可,最终表格会按照店铺名称和时间名词。json

代码解读

导入库说明

  • requests 库不用多数,爬取网页的主要库
  • json 库是用来解析 json 格式的数据的,也就是 Python 中的字典格式
  • csv 库是用来建立 csv 表格和保存信息的
  • random 库是用来生成一个随机数的,这个代码中用到了两次,第一次是生成一个随机数据去获取最新的网页信息而不是缓存信息,第二次是随机一个时间,来减缓爬虫速度
  • re 库是正则,主要用来提取信息
  • datetimetime 都是时间库,前者通常用来生成当前时间字符串,后者本爬虫使用设置延迟时间

爬虫思路

  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 = 'https://{}.m.tmall.com'.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 = 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

这个函数的用意是建立一个带有标题的表格,标题就是提取的网页信息中的 key,这个必须跟须要提取的参数保持一致。关于 csv 库按照字典格式保存信息的方式能够参考以前的一篇文章 Python 内置 csv 模块简介,使用三种方式写入 csv 表格dom

提取总页码数

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)

这个函数其实跟提取信息的函数是同样的,只不过须要提取的信息不同而已,这个函数只须要提取总页码数。具体步骤是先构造出每页请求的URL,这个须要本身去总结一个最简约的连接形式,而且尽量模仿人工浏览。函数

请求网页会获得一个相似于 json 的信息,可是不是纯 json ,所以须要使用正则来处理一下,而后须要用到 json 库来转换格式为真正的 json 格式。测试

提取单页的信息

def get_products(self,page) 的用法是跟提取总页码数同样的,只不过这个须要传入一个参数,也就是须要爬取的页码数,这样就能够改变 URL 从而爬取对应的页码的信息了。jsonp

最后提取每页的信息在 json 中是造成一个列表的形式,而每一个列表又是一个字典,因此能够直接使用 csv 的多行写入的方法去保存信息。url

循环爬取全店商品

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())

最后一个函数就是使用循环的方式去爬取全部页面的信息并保存了,同时能够在每次爬完一页以后打印一句话做为提示,而且为了尽量的减小IP被封的可能性,能够适当的增长一下爬取延迟。code

相关文章
相关标签/搜索