<p>本文講述如何利用Python模擬淘寶的搜索過程并對搜索結果進行初步的數(shù)據(jù)可視化分析攒砖。</p>
- 搜索過程的模擬:淘寶的搜索頁面有兩種形式,一種形式是手機大類產品頁面谒臼,一種形式是其余產品頁面预烙。當然其余搜索占了總搜索類別的99%以上,本文會以其余為主進行淘寶搜索的模擬嘀略;
- 初步數(shù)據(jù)可視化分析:對搜索回來的數(shù)據(jù),通過店鋪城市生成坐標數(shù)據(jù)乓诽,并將銷量帜羊、售價在地圖上標示出來。坐標數(shù)據(jù)的獲得要通過高德地圖的API插口鸠天,數(shù)據(jù)可視化為利用Plotly生成Buble Map讼育。
利用Python模擬搜索過程
<p>首先需要先對淘寶的模式進行標識,通過幾個關鍵詞搜索之后稠集,可以發(fā)現(xiàn)其地址的變化規(guī)律奶段,如下圖所示:</p>
<p>忽略掉q=脫皮綠豆
后面的部分試試,在網址欄輸入(https://s.taobao.com/search?q=脫皮綠豆) 剥纷,發(fā)現(xiàn)可行忧饭。這樣就簡單了,后續(xù)就是解析生成頁筷畦、生成翻頁器、以及存儲生成數(shù)據(jù)即可刺洒。</p>
解析生成頁
<p>和之前的例子類似鳖宾,結合requests以及BeautifulSoup來完成頁面數(shù)據(jù)下載:</p>
def mainPaser(url):
Headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36"}
Response = requests.get(url, headers=Headers)
Interial = BeautifulSoup(Response.content, 'lxml')
pageConfig = Interial.find('script', text=re.compile('g_page_config'))
return pageConfig.string
<p>繼續(xù)對淘寶的頁面進行Inspect,發(fā)現(xiàn)每一框的店鋪數(shù)據(jù)儲存在g_page_config中的auctions中逆航,并且g_page_config中的數(shù)據(jù)為json格式鼎文。</p>
獲取原始數(shù)據(jù)
<p>在Python中,json可以通過專門的解析器來完成因俐。通過其中的loads 和dumps 可以輕易的在json以及str之間做轉換拇惋。將str轉換為json格式,在通過pandas 的read_json獲取json中的數(shù)據(jù)信息抹剩。</p>
<p>每一框店鋪的數(shù)據(jù)涵括非常豐富的店鋪信息以及銷售信息撑帖,在這里僅收集寶貝分類(category)、評論數(shù)(comment_count)澳眷、寶貝位置(item_loc)胡嘿、店鋪名稱(nick)、寶貝名稱(raw_title)钳踊、原價格(reserve_price)衷敌、顯示價格(view_price)勿侯、銷量(view_sales)進行分析:</p>
neededColumns = ['category', 'comment_count', 'item_loc', 'nick', 'raw_title', 'view_price', 'view_sales']
PageConfig = re.search(r'g_page_config = (.*?);\n', pageConfig.string)
pageConfigJson = json.loads(gPageConfig.group(1))
pageItems = pageConfigJson['mods']['itemlist']['data']['auctions']
pageItemsJson = json.dumps(pageItems)
pageData = pd.read_json(pageItemsJson)
neededData = pageData[Paser.neededColumns]
整理生成數(shù)據(jù)
<p>接下來就是對得出的數(shù)據(jù)進行整理,我們先看看neededData
的結構是如何缴罗,如下表所示:</p>
<p>其中item_loc
是網店的地址助琐,可以看到直轄市是比較特殊的存在,將這一列改的省份名稱刪掉面氓,方法是單獨將這一列拿出來通過pandas.Series.str.split來處理兵钮,以空格為標識符,將該列的省份以及城市拆分為兩列侧但,結果如下圖矢空,通過pandas.DataFrame.fillna向左填充對None進行填充:</p>
<p>這樣就實現(xiàn)對item_loc
列的修改,看回neededData
那張圖禀横,最后一列view_sales
中屁药,需要將每個單元格中付款兩個字刪去。需要采用pandas.Series.str.extract柏锄,結合正則表達式來處理酿箭。將數(shù)字文本拖出來之后,還需要通過astype函數(shù)將其轉化為int格式趾娃,并增加時間列缭嫡。最后該段數(shù)據(jù)整理的代碼,以及處理后的效果圖為:</p>
cityData = neededData['item_loc'].str.split(' ', expand = True)
cityData.fillna(method = 'pad', axis= 1, inplace= True)
neededData.loc[:,('item_loc')] = cityData[1]
neededData.loc[:,('view_sales')] = neededData['view_sales'].str.extract('([\d]*)([\w]*)').get(0)
neededData.loc[:,('view_sales')] = neededData['view_sales'].astype(int)
neededData['time'] = datetime.datetime.now().strftime('%Y%m%d%H')
生成翻頁器
<p>最后就是生成翻頁器了抬闷,在剛剛的g_page_config中搜索pager試試:</p>
<p>將其中的\\u003d
和=
以及\\u0026
和&
作替換(我是通過字符替換處理妇蛀。。單應該存在更加方便的笤成,從編碼角度入手處理的方法评架。。求指教)炕泳,并更換一二三頁纵诞,發(fā)現(xiàn)網址最后的參數(shù)s分別為0,44培遵,88浙芙。結合上面第二張圖,可以猜到這個數(shù)字為單頁的店鋪總量籽腕,當頁面默認每頁的店鋪數(shù)為44的時候嗡呼,只需要更改該參數(shù)即可達到翻頁效果。</p>
數(shù)據(jù)可視化
<p>為了對將銷售數(shù)據(jù)以及評論數(shù)據(jù)放在地圖上皇耗,顯示區(qū)域集中情況晤锥,首先需要將城市信息轉化為坐標信息,這個時候需要用到高德地圖的API插口。而為了減少反復查詢的次數(shù)矾瘾,需要對坐標信息進行存儲女轿,即將位置數(shù)據(jù)存儲在sql中,邏輯是這樣:</p>
<p>采用sqlite進行地理數(shù)據(jù)的存儲和查詢壕翩,對于查詢存在的數(shù)據(jù)直接輸出蛉迹,查詢不存在的數(shù)據(jù)需要通過高德地圖的行政區(qū)域查詢功能查詢。首先需要注冊自己的一個key放妈,并在對應賬號的控制版內增加Web服務API功能北救,使用過程中將key值以及設置信息用dict格式表示,并加載在requests的param中芜抒。查詢輸出的數(shù)據(jù)格式有兩種珍策,一種是json,一種是xml宅倒。這里輸出json攘宙,對json的字符串通過正則表達式將經緯度信息提取出來,提取出后存儲在數(shù)據(jù)文件中拐迁,并進行輸出蹭劈。 </p>
def getCenter(city):
conn = sqlite3.connect('citydata.db')
cursor = conn.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS CITYDATA(citycode text primary key , name text, latitude real, longitude real);")
cursor.execute("SELECT latitude, longitude FROM CITYDATA WHERE name = ?", (city,))
res = cursor.fetchall()
if not res:
payload = {
##yourkey = the key applied from amap.com
'key':yourkey,'keywords':'',
'subdistrict': '0','showbiz':False,'output':'json',
}
payload['keywords'] = city
jsonData = requests.get('http://restapi.amap.com/v3/config/district?', params = payload)
jsonText = jsonData.text
center = re.search(r'\"([\d]*\.[\d]*)\,([\d]*\.[\d]*)\"', jsonText)
cityCode = re.search(r'\"citycode\"\:\"(\d*)\"', jsonText)
latitude = float(center.group(1))
longitude = float(center.group(2))
cursor.execute("INSERT INTO CITYDATA VALUES(?, ?, ?, ?);", [cityCode.group(1), city, latitude, longitude])
cursor.close()
conn.commit()
return latitude, longitude
else:
res = list(res[0])
return res[0], res[1]
<p>經緯度數(shù)據(jù)獲得后,需要輸出到現(xiàn)有的dataFrame中线召,由于上述函數(shù)有兩個輸出铺韧,不能通過apply函數(shù)得出,需要結合zip以及map函數(shù)來實現(xiàn)雙輸出:</p>
neededData['latitude'], neededData['longitude'] = zip(*neededData['item_loc'].map(getCenter))
數(shù)據(jù)可視化
<p>dataFrame的可視化工具有很多缓淹,常用的有matplotlib哈打。但對于生成地理信息圖,似乎plotly更具有優(yōu)勢讯壶,并且經過優(yōu)化后料仗,plotly生成的圖像質量要更高。嘗試下對view_sales
列進行可視化操作鹏溯,首先對該列進行排序:</p>
neededData.sort_values('view_sales', axis = 0, ascending = False, inplace=True)
<p>plotly在第一次使用的時候也需要設置自己的賬號信息,具體可以參考getting started淹仑,本機只要設置過一次賬號后丙挽,后面就可以不用再設置了。</p>
<p>首先需要對圖例進行設置:</p>
import plotly.plotly as py
length = len(newData)
limits = [(0, int(0.05*length)),(int(0.05*length), int(0.2*length)),(int(0.2*length),int(0.5*length)),(int(0.5*length),length)]
colors = ["#0A3854","#3779A3", "#1B85C6", "#C0DAEA"]
cities = []
<p>而后就是設置每個點的地理信息匀借、泡泡面積大小颜阐、泡泡顏色,并將dataFrame中的數(shù)據(jù)轉換為ployly可識別的格式中:</p>
for i in range(len(limits)):
lim = limits[i]
df_sub = newData[lim[0]:lim[1]]
city = dict(
type = 'scattergeo',
locationmode = 'china',
lon = df_sub['longitude'],
lat = df_sub['latitude'],
text = df_sub['nick'],
marker = dict(
size = df_sub['view_sales']/10,
color = colors[i],
line = dict(width = 0.5, color = '#000'),
sizemode = 'area',
opacity = 0.5
),
name = "{0} - {1}".format(lim[0], lim[1])
)
cities.append(city)
<p>最后是對圖紙信息進行設定吓肋,包括標題凳怨,是否顯示圖例。由于ployly中已經包含有地圖信息,因此只需設定顯示區(qū)域(scope)肤舞,投影方式(projection)紫新,以及邊界線條顏色和邊界信息即可:</p>
layout = dict(
title = Keyword + "的淘寶分布",
showlegend = True,
geo = dict(
scope = "asia",
projection = dict(type = 'mercator'),
showland = True,
landcolor = 'rgb(217, 217, 217)',
subunitwidth=1,
countrywidth=1,
subunitcolor="rgb(255, 255, 255)",
countrycolor="rgb(255, 255, 255)",
lonaxis = dict(range = [newData['longitude'].min()-3, newData['longitude'].max() + 3]),
lataxis = dict(range = [newData['latitude'].min()-0.5, newData['latitude'].max() + 0.5]),
),
)
<p>完成后,輸出保存即可:</p>
fig = dict(data = cities, layout = layout)
py.iplot(fig, validate = False)
總結
<p>本文基本實現(xiàn)了最初目的李剖,模擬了淘寶的搜索數(shù)據(jù)芒率,并初步對數(shù)據(jù)進行可視化。但該程序還有很多優(yōu)化的地方:</p>
- 在搜索過程中篙顺,發(fā)現(xiàn)對于同一個關鍵詞會出現(xiàn)很多不同種類的東西偶芍,例如你搜索蘋果,可能會出現(xiàn)iphone也有可能出現(xiàn)能吃的蘋果德玫,不方便匪蟀;
- 結合ML,實現(xiàn)深度的搜索宰僧,對同一個物品進行價格對比材彪,銷量對比,客戶評價對比撒桨,幫助客戶進行選擇查刻;
- 可視化的意義沒有體現(xiàn)出來;
- 本文中凤类,還有bug未完善穗泵,很多地方需要采用try來規(guī)避。