本編博客是關於爬取天貓店鋪中指定店鋪的全部商品基礎信息的爬蟲,爬蟲運行只須要輸入相應店鋪的域名名稱便可,信息將以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
庫是正則,主要用來提取信息datetime
和 time
都是時間庫,前者通常用來生成當前時間字符串,後者本爬蟲使用設置延遲時間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