爬取淘寶商家貨物簡單銷售資料(銷量,價格,銷售地,貨物名稱)

2020-10-29 10:00:01

爬取淘寶商家貨物簡單銷售資料(銷量,價格,銷售地,貨物名稱)


前天接一個爬取淘寶商家(自行車)資訊的請求,要求資料按照其銷售量排行。

完成該請求後,爬取資料(李寧衛衣)如下:
在這裡插入圖片描述

接下來看如何實現的?

首先開啟淘寶網:https://www.taobao.com/,在搜尋欄輸入自行車,結果發現頁面轉跳到https://login.taobao.com/member/login.jhtml 淘寶登入頁面,要求登入才能進行關鍵字搜尋獲取資料。(需要登入的時候應當想到cookies)

cookies 及其用處:
當我們登入某網站時,伺服器會生成一個cookies,包含有使用者登入等資訊,與當前賬號繫結,瀏覽器將此cookies儲存到。下一次,瀏覽器帶著cookies存取網站,就不需要在輸入賬號密碼。注意cookies是有時效性的。

所以,目標明確,第一步,獲取使用者登入的cookies

一、登入淘寶,獲取Cookies

需要登入淘寶頁面獲取cookies,才能執行後續操作。而模擬登入有兩種方法:

  • 搞清淘寶登入機制,修改引數登入。(借鑑裸睡的豬 豬哥的文章)
  • 使用selenium呼叫webdriver模組,模擬人真實的操作瀏覽器。

方法一:直接看原始碼+備註,具體原因看豬哥的解釋(當然程式碼是自己寫的啊,思想借用)

import requests
import re
import json
import time
import random

check_url = 'https://login.taobao.com/newlogin/account/check.do?appName=taobao&fromSite=0'
headers = {
    'origin':'https://login.taobao.com',
    'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
    # 標記了請求從什麼裝置,什麼瀏覽器上發出
}

session  = requests.session()
login_url = 'https://login.taobao.com/newlogin/login.do'

#自己手動登入一次,在引數頁面把所有引數複製過來替換掉,看下圖
Login_Data = {
    'loginId': '****',  
    'password2': '*****',
    'keepLogin': 'true',
    'ua': '***',
    'umidGetStatusVal': '255',
    'screenPixel': '1536x864',
    'navlanguage': 'zh-CN',
    'navUserAgent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36',
    'navPlatform': 'Win32',
    'appName': 'taobao',
    'appEntrance': 'taobao_pc',
    '_csrf_token': '*****',
    'umidToken': '****',
    'hsiz': '****',
    'bizParams':'',
    'style': 'default',
    'appkey': '00000000',
    'from': 'tbTop',
    'isMobile': 'false',
    'lang': 'zh_CN',
    'returnUrl': 'https://www.taobao.com/',
    'fromSite': '0',
}
login_res = session.post(login_url,headers=headers,data=Login_Data) #帶著這些引數再登入一次爬取資料

#獲取st碼申請地址
token_json = login_res.json()
st_url = token_json['content']['data']['asyncUrls'][0]  #st碼的申請地址
print('驗證使用者名稱和密碼成功')

#通過st碼申請地址獲取st碼
st_res = requests.get(st_url,headers=headers)
st_code_text = st_res.text
st_code = st_code_text[579:-270]  #獲取st碼,自己發現的規律,可以這麼提取,也可以使用正規表示式
print('獲取st碼成功,st碼:{}'.format(st_code))


#獲取登入跳轉連結
res_st = session.get('https://login.taobao.com/member/vst.htm?st={}'.format(st_code) , headers=headers)
my_taobao = re.search(r'top.location.href = "(.*?)"', res_st.text)
print('登入淘寶成功,跳轉連結:{}'.format(my_taobao.group(1)))
my_taobao_url = my_taobao.group(1)

#登入
res_login = session.get(my_taobao_url, headers=headers)
nick_name = re.search(r'<input id="mtb-nickname" type="hidden" value="(.*?)"/>', res_login.text)
print('登入淘寶成功,你的使用者名稱是:{}'.format(nick_name.group(1)))
username = nick_name.group(1)

# 獲取cookies,將cookies轉成字典,再將字典轉成字串,儲存到資料夾中
cookies_ditc = requests.utils.dict_from_cookiejar(session.cookies)
cookies_str = json.dumps(cookies_ditc)
f = open(r'C:\Users\13426\Desktop\cookies.txt','w',encoding='utf-8')
f.write(cookies_str)
print(cookies_str)  #cookies,具有時效性。
print('cookie已經完成序列化')  
f.close()

在自行登入以後,把引數都複製到Data裡替換掉程式碼中的data就可以。
在這裡插入圖片描述

方法二:使用selenium呼叫webdriver模組(自己寫的,所以解釋詳細點)

前提是安裝了Chorm driver外掛,Chorm外掛下載地址
下載完成後,解壓到python根目錄下即可。

driver可以模擬人在目標欄目輸入,也可以模擬人對按鈕進行點選。

對登入頁面以及原始碼進行分析:發現:
在這裡插入圖片描述

帳號輸入框對應:
<input name="fm-login-id" type="text" class="fm-text" id="fm-login-id" tabindex="1" aria-label="會員名/郵箱/手機號" placeholder="會員名/郵箱/手機號" autocapitalize="off">
密碼輸入框對應:
<input name="fm-login-password" type="password" class="fm-text" id="fm-login-password" tabindex="2" aria-label="請輸入登入密碼" placeholder="請輸入登入密碼" maxlength="40" autocapitalize="off">
登入按鈕欄目對應:
<button type="submit" tabindex="3" class="fm-button fm-submit password-login">登入</button>

所以,程式碼如下:在賬號密碼框裡輸入內容,點選登入進行登入.

from selenium import webdriver#呼叫webdriver模組

driver = webdriver.Chrome()#設定引擎為Chrome,模擬真實地開啟一個瀏覽器
driver.get('https://login.taobao.com/member/login.jhtml')  #開啟這個連結
time.sleep(1) #等待一秒鐘,模擬真人操作


## 執行程式碼之前輸入自己的賬號和密碼
user = driver.find_element_by_name('fm-login-id')
user.send_keys('這裡輸入自己的賬號')  #在fm-login-id對應框中輸入賬號
time.sleep(1)
assistant = driver.find_element_by_name('fm-login-password')
assistant.send_keys('這裡輸入自己的密碼')
time.sleep(1)
submit = driver.find_element_by_class_name('fm-btn')  #點選登入按鈕
submit.click()#登入
time.sleep(5)
cookie_list = driver.get_cookies() #登入以後獲取cookie
cookies = {}
print(len(cookie_list))
for cookie in cookie_list:
    cookies[cookie['name']] = cookie['value']  #將cookies字典化
print("已經成功的獲取到使用者登入的cookies")
print(cookies)
driver.close()

注意,有時候登入時需要滑動滾軸,手動滑動登入即可。

到此使用者操作所用cookies的已經獲取,這時候就可以搜尋鍵碼了

二、輸入關鍵字,翻動頁碼,檢視原始碼以及迴應內容的變化。並請求資料

進入搜尋頁:https://s.taobao.com/search? 輸入關鍵字,觀察url變化
在這裡插入圖片描述

我們發現q引數對應著搜尋內容。然後翻動頁面,來到第二頁,觀察url變化,發現變化的有s引數
在這裡插入圖片描述

研究多個頁面發現,url需要修改的引數只有q與s。

在翻頁的過程中,發現我們所需要的內容在Response的第0個迴應中,即存在於Element中,所以只要獲取到該網頁的原始碼,就可以獲取到資料。
在這裡插入圖片描述

所以使用https://s.taobao.com/search?q=自行車&s=88 這個格式(q表示搜尋的關鍵字,s*44代表頁數)的連結就可以存取帶有資料的原始碼。

所以程式碼如下:

headers = {'Host':'s.taobao.com',
           'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0',
           'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
           'Accept-Language':'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
           'Accept-Encoding':'gzip, deflate, br',
           'Connection':'keep-alive'
        }
list_url = 'http://s.taobao.com/search?q=%(key)s&ie=utf8&s=%(pnum)d'

for i in range(Page):
    pnum = i*44
    url = list_url%{'key':key,'pnum':pnum}
    print(url)
    res = requests.get(url,headers=headers,cookies=cookies)  #帶有前面獲取的cookies

三、分析資料網頁原始碼,獲取資料

這是我爬取的一個李寧衛衣的網頁原始碼,發現重要資訊儲存在一個大字典:g_page_config中
在這裡插入圖片描述
在這裡插入圖片描述

所以我們可以通過正規表示式獲取這個大字典,然後逐一提取各資料。或者直接正則各資料提取,我們採用第二種方法。

#建立正規表示式
titles = '"raw_title":"(.*?)"'       #標題
locations = '"item_loc":"(.*?)"'    #銷售地
sales = '"view_sales":"(.*?)人付款"' #銷售量
comments = '"comment_count":"(.*?)"'#評論數
prices = '"view_price":"(.*?)"'     #銷售價格
nids = '"nid":"(.*?)"'          #這裡需要nid,是因為商品的連結是需要這個引數的  


#res.text表示網頁原始碼,在其中匹配正則
title = re.findall(titles,res.text)
location = re.findall(locations,res.text)
sale = re.findall(sales,res.text)
comment = re.findall(comments,res.text)
price = re.findall(prices,res.text)
nid = re.findall(nids,res.text)

到這裡已經把所有有效資料儲存到title,location等變數中。它們均為字串列表

四、儲存資料,並將資料按照銷量降序排列

使用csv儲存資料

csv_file = open(r'檔案儲存路徑','w',newline='',encoding='utf-8-sig')
writer = csv.writer(csv_file)
writer.writerow(['商品名稱','銷售地','銷售量','評論數','銷售價格','商品連結'])
#後續寫入即可

因為要求資料要根據銷量降序排列,而銷量資料格式為字串。分析原始碼,發現原始碼中銷量的表示一般有’8000+’、‘1.6萬+’、‘784’這幾種表示。即如果銷量小於10000,則按照 ‘具體數位’ 或 ‘具體數位+’ 這樣表示,如’845’、‘3500+’,如果資料大於一萬,則會在後續加個萬字, 如’1.6萬+’,‘5.8萬’,強轉為float時需要做判斷:

所以,通過條件判斷語句和if else判斷:

sale[j] = sale[j]  if sale[j][-1] !='+'  else sale[j][:-1]  #判斷最後一位是不是+,如果是,就刪掉
if sale[j][-1] == '萬':
    data.append([ title[j],location[j],float(sale[j][:-1])*10000,comment[j],price[j],goods_url ]) #如果最後一位是萬,去掉最後一位,乘以10000即可
else:
    data.append([ title[j],location[j],float(sale[j]),comment[j],price[j],goods_url ])

data.sort(key=itemgetter(2))  #按照第3個元素,即銷量進行排序
data.reverse()#按照銷量進行排序

還有一個發現就是,商品的連結與nid是有關係的,具體關係如下:

goods_url = 'https://item.taobao.com/item.htm?id='+nid[j]+'&ns=1&abbucket=19#detail'

到此程式碼已經分析完畢,原始碼如下,登入時修改自己的賬號密碼,以及檔案的儲存路徑即可:

import time
import requests
import json
import re
from selenium import webdriver#呼叫webdriver模組
import csv
from operator import itemgetter



## 在這裡設定下爬取結果檔案儲存的路徑
csv_file = open(r'C:\Users\13426\Desktop\demo.csv','w',newline='',encoding='utf-8-sig')
writer = csv.writer(csv_file)




driver = webdriver.Chrome()#設定引擎為Chrome,模擬真實地開啟一個瀏覽器
driver.get('https://login.taobao.com/member/login.jhtml')
time.sleep(1)


## 執行程式碼之前輸入自己的賬號和密碼
user = driver.find_element_by_name('fm-login-id')
user.send_keys('輸入自己的賬號')
time.sleep(1)
assistant = driver.find_element_by_name('fm-login-password')
assistant.send_keys('輸入自己的密碼')
time.sleep(1)
submit = driver.find_element_by_class_name('fm-btn')
submit.click()#登入
time.sleep(5)
cookie_list = driver.get_cookies()
cookies = {}
print(len(cookie_list))
for cookie in cookie_list:
    cookies[cookie['name']] = cookie['value']
print("已經成功的獲取到使用者登入的cookies")
print(cookies)
driver.close()



headers = {'Host':'s.taobao.com',
           'User-Agent':'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0',
           'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
           'Accept-Language':'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
           'Accept-Encoding':'gzip, deflate, br',
           'Connection':'keep-alive'
        }
list_url = 'http://s.taobao.com/search?q=%(key)s&ie=utf8&s=%(pnum)d'

titles = '"raw_title":"(.*?)"'       #標題
locations = '"item_loc":"(.*?)"'    #銷售地
sales = '"view_sales":"(.*?)人付款"' #銷售量
comments = '"comment_count":"(.*?)"'#評論數
prices = '"view_price":"(.*?)"'     #銷售價格
nids = '"nid":"(.*?)"'          #這裡需要nid,是因為商品的連結是需要這個引數的  
writer.writerow(['商品名稱','銷售地','銷售量','評論數','銷售價格','商品連結'])



key = input('輸入想要爬取的商品名稱:')
Page = 5 # 爬取的頁數 ,可以自行修改
data = []

for i in range(Page):
    pnum = i*44
    url = list_url%{'key':key,'pnum':pnum}
    print(url)
    res = requests.get(url,headers=headers,cookies=cookies)
    html = res.text


    title = re.findall(titles,html)
    location = re.findall(locations,html)
    sale = re.findall(sales,html)
    comment = re.findall(comments,html)
    price = re.findall(prices,html)
    nid = re.findall(nids,html)
    for j in range(len(title)):
        goods_url = 'https://item.taobao.com/item.htm?id='+nid[j]+'&ns=1&abbucket=19#detail'
        sale[j] = sale[j]  if sale[j][-1] !='+'  else sale[j][:-1]
        if sale[j][-1] == '萬':
            data.append([ title[j],location[j],float(sale[j][:-1])*10000,comment[j],price[j],goods_url ]) #如果最後一位是萬,去掉最後一位,乘以10000即可
        else:
            data.append([ title[j],location[j],float(sale[j]),comment[j],price[j],goods_url ])
    
    print('-------Page%s 已經抓取完畢!--------\n\n'%(i+1))
    time.sleep(2)
data.sort(key=itemgetter(2))
data.reverse()#按照銷量進行排序  
for j in range(len(data)):
    writer.writerow(data[j])