利用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 = '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()

上面代碼是選擇了優衣庫作為測試店鋪,直接輸入優衣庫店鋪的域名中關鍵詞即可,最終表格會按照店鋪名稱和時間名詞。

代碼解讀

導入庫說明

  • 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 表格

提取總頁碼數

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 從而爬取對應的頁碼的信息了。

最后提取每頁的信息在 json 中是形成一個列表的形式,而每個列表又是一個字典,所以可以直接使用 csv 的多行寫入的方法去保存信息。

循環爬取全店商品


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被封的可能性,可以適當的增加一下爬取延遲。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM