完成該請求後,爬取資料(李寧衛衣)如下:
接下來看如何實現的?
首先開啟淘寶網:https://www.taobao.com/,在搜尋欄輸入自行車,結果發現頁面轉跳到https://login.taobao.com/member/login.jhtml 淘寶登入頁面,要求登入才能進行關鍵字搜尋獲取資料。(需要登入的時候應當想到cookies)
cookies 及其用處:
當我們登入某網站時,伺服器會生成一個cookies,包含有使用者登入等資訊,與當前賬號繫結,瀏覽器將此cookies儲存到。下一次,瀏覽器帶著cookies存取網站,就不需要在輸入賬號密碼。注意cookies是有時效性的。
所以,目標明確,第一步,獲取使用者登入的cookies
需要登入淘寶頁面獲取cookies,才能執行後續操作。而模擬登入有兩種方法:
方法一:直接看原始碼+備註,具體原因看豬哥的解釋(當然程式碼是自己寫的啊,思想借用)
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])