Python爬虫自学之第(⑤)篇——爬取某宝商品信息
題外話:
《Pi Network 免費(fèi)挖礦國(guó)外熱門(mén)項(xiàng)目 一個(gè)π幣大約值3元到10元》相信過(guò)去BTC的人,信不信未來(lái)的PI,了解一下,唯一一個(gè)高度與之持平的項(xiàng)目
?
能看到這里說(shuō)明快進(jìn)入動(dòng)態(tài)網(wǎng)頁(yè)爬取了,在這之前還有一兩個(gè)知識(shí)點(diǎn)要了解,就如本文要講的json及其數(shù)據(jù)提取
JSON
是什么
??json是輕量級(jí)的文本數(shù)據(jù)交換格式,符合json的格式的字符串叫json字符串,其格式就像python中字符串化后的字典,有時(shí)字典中還雜著列表字典,但是里面的數(shù)據(jù)都被雙引號(hào)包著,下面是一個(gè)例子
'{"Africa": [ { "name":"蜜獾" , "nickname":"平頭哥" }, { "name":"蟲(chóng)子" , "nickname":"小辣條" }, { "name":"毒蛇" , "nickname":"大面筋" }]}'#這是理想化的數(shù)據(jù),實(shí)際上看到的json是不分行堆在一起,而且更多時(shí)候用unicode編碼取代中文而且為了能更好的傳輸各種語(yǔ)言,json對(duì)非英語(yǔ)的字符串進(jìn)行了Unicode編碼,于是我們直接看到的json數(shù)據(jù)通常都是帶著\uxxxx的字符串而不會(huì)帶著中文,json數(shù)據(jù)還會(huì)堆在一起不換行,給我們的分析帶來(lái)了困難,不過(guò)我們有json 模塊讓它轉(zhuǎn)回中文,更有一個(gè)牛逼工具把它轉(zhuǎn)回中文同時(shí)排版,分析json數(shù)據(jù)時(shí)多用這個(gè)工具。
在哪
??有時(shí)F12源碼中能看到完整的信息,request回來(lái)后就殘缺到?jīng)]有價(jià)值,這就說(shuō)明網(wǎng)頁(yè)使用了動(dòng)態(tài)或者ajax技術(shù),而這些技術(shù)所加載的信息,就有json的身影。為了順利爬取目標(biāo),我們需要找到j(luò)son數(shù)據(jù)。
- json數(shù)據(jù)有時(shí)會(huì)直接出在對(duì)原鏈接request的結(jié)果中,作為信息等待被加載到網(wǎng)頁(yè)中
- 有時(shí)會(huì)存在于獨(dú)立的鏈接里,需要捉包獲取鏈接再打開(kāi)獲得(而且這種鏈接的構(gòu)造很重要)
json 模塊
??JSON是JavaScript原生格式,親生無(wú)誤,所以在JavaScript中處理JSON數(shù)據(jù)不需要任何特殊的API或工具包。像python這樣連的遠(yuǎn)親,當(dāng)然不能直接一把捉走別人的孩子,至少要帶根棒棒糖來(lái)引誘一下呀,而這根棒棒糖就是json模塊,python自帶。
??json 模塊提供了一種很簡(jiǎn)單的方式來(lái)編碼和解碼JSON數(shù)據(jù),實(shí)現(xiàn)了JSON數(shù)據(jù)(字符串)和python對(duì)象(字典)的相互轉(zhuǎn)換。
 主要兩個(gè)方法及常用參數(shù):
- json.dumps(obj,ensure_ascii=True): 將一個(gè)字典(obj)轉(zhuǎn)換為JSON編碼的字符串,ensure_ascii默認(rèn)為T(mén)rue,全部是ascii字符,中文會(huì)以u(píng)nicode編碼形式顯示如\u597d;設(shè)置為False時(shí)保持中文
- json.loads(s,encoding=): 將一個(gè)JSON編碼的字符串(s)轉(zhuǎn)換回字典,如果傳入的json字符串的編碼不是UTF-8的話,需要用encoding指定字符編碼
如果你要處理的是文件而不是字符串/字典,你可以使用 json.dump() 和 json.load() 來(lái)編碼和解碼JSON數(shù)據(jù)。
# 編碼成json數(shù)據(jù)寫(xiě)入,data是字典 with open('data.json', 'w') as f:json.dump(data, f)# 讀取json數(shù)據(jù)并解碼,data是字典 with open('data.json', 'r') as f:data = json.load(f)另:requests對(duì)象的json()方法也可以把json數(shù)據(jù)轉(zhuǎn)為字典,dict = r.json(encoding=)
實(shí)戰(zhàn):簡(jiǎn)單爬取淘寶商品信息
??爬蟲(chóng)領(lǐng)域內(nèi)json的知識(shí)知道這些就行,那么馬上來(lái)個(gè)實(shí)戰(zhàn)了解一下怎樣提取json中的數(shù)據(jù),加深對(duì)json的認(rèn)識(shí)吧,正好可以拿某寶來(lái)試手,商品的json數(shù)據(jù)直接出在對(duì)原鏈接request的結(jié)果中,不用捉包。(然而大多數(shù)json數(shù)據(jù)不會(huì)這樣出現(xiàn),這里選擇某寶方便展示)
構(gòu)造鏈接(重要)
重要,但這也是要培養(yǎng)的能力,在這里只詳細(xì)講一次思路,以后靠自己分析
??構(gòu)造鏈接的原則是盡可能多的相關(guān)參數(shù),盡可能少的無(wú)關(guān)參數(shù),網(wǎng)址中?之后用&連起來(lái)的賦值關(guān)系就是那些參數(shù),這些參數(shù)會(huì)傳到服務(wù)器中,服務(wù)器根據(jù)它們來(lái)返回?cái)?shù)據(jù)。爬蟲(chóng)中,頁(yè)數(shù),排序,日期等這類的參數(shù)是關(guān)鍵。我們要?jiǎng)討B(tài)的修改這些參數(shù)來(lái)構(gòu)造鏈接,觀察能力很重要。還有構(gòu)造鏈接時(shí)要多requests下來(lái)測(cè)試哪些是相關(guān)參數(shù),哪些參數(shù)是無(wú)關(guān)緊要的,不是只看瀏覽器就行的
??先進(jìn)入官網(wǎng)搜索一件商品,這里以GTX2080為例,第一次出現(xiàn)的鏈接如下,
| https://s.taobao.com/search?initiative_id=tbindexz_20170306&ie=utf8&spm=a21bo.2017.201856-taobao-item.2&sourceId=tb.index&search_type=item&ssid=s5-e&commend=all&imgfile=&q=gtx2080ti&suggest=history_2&_input_charset=utf-8&wq=&suggest_query=&source=suggest | 
很長(zhǎng)是吧,能大約的看到日期,商品名之類的參數(shù),但是大部分參數(shù)都看不懂,我們假設(shè)部分參數(shù)是不影響爬取結(jié)果的,于是我們來(lái)繼續(xù)按下看看有什么變化,當(dāng)再次按下搜索鍵
鏈接變短了,在按多幾下都是這個(gè)鏈接了
| #初步結(jié)構(gòu) https://s.taobao.com/search?q=gtx2080ti&imgfile=&js=1&stats_click=search_radio_all%3A1&initiative_id=staobaoz_20200205&ie=utf8 | 
為了確保泛用性,我們要多換幾個(gè)商品再搜索,確定一下,發(fā)現(xiàn)鏈接除q參數(shù)(商品名)改變外,其他一模一樣,由此我們初步確定了鏈接結(jié)構(gòu),q參數(shù)是商品名,initiative_id是當(dāng)天日期,其他不用變
 ??但我們的還要有翻頁(yè)和排序的功能沒(méi)實(shí)現(xiàn),鏈接里也看不到和它們有關(guān)的參數(shù),因此我們要繼續(xù)按來(lái)引相關(guān)參數(shù)出來(lái),點(diǎn)擊排序那排按鈕
發(fā)現(xiàn)又多了一個(gè)sort參數(shù),不同的排序方式對(duì)應(yīng)不同的值,有default(默認(rèn)綜合排序),sale-desc(按銷(xiāo)量),renqi-desc(按人氣)等
??按下一頁(yè),又多了bcoffset,p4ppushleft,s三個(gè)參數(shù),經(jīng)測(cè)試只有s參數(shù)有用,其他兩個(gè)都不影響爬取結(jié)果(直接去掉),s是頁(yè)數(shù)相關(guān)參數(shù),值是44的倍數(shù)(因?yàn)槊宽?yè)加載44件商品),第一頁(yè)0,第二頁(yè)44,第三頁(yè)88……
??到此就捕捉到q,initiative_id,sort,s等參數(shù)了,如果想增加其它相關(guān)參數(shù),就自己到處按搗鼓吧,下面就這4個(gè)參數(shù)進(jìn)行構(gòu)造,可以format格式化,也可以將參數(shù)通過(guò)requests.get()的params參數(shù)傳入,下面選擇格式化
| #使用格式化輸出,傳四個(gè)字符串變量進(jìn)去 | 
剩下的就是整合到循環(huán)進(jìn)行多頁(yè)爬取了,代碼最后貼上,下面在看看json數(shù)據(jù)怎樣提取。
json數(shù)據(jù)分析&提取
先拿一個(gè)鏈接requests下來(lái)保存到txt看看先,打開(kāi)后看到一大堆又字典又列表的東西,仔細(xì)一看這貨是符合json格式的字符串,里面有我們要的信息。二話不說(shuō)馬上扔到那個(gè)工具里排版一下,排完后如圖
我們知道json數(shù)據(jù)本質(zhì)是字符串,也可以用json.load()轉(zhuǎn)化為字典,這樣的話就有兩種提取信息的方法
- 直接用正則對(duì)字符串匹配,缺點(diǎn)是當(dāng)json存在\uxxxx的unicode編碼時(shí)你會(huì)得到\uxxxx而不是中文,然而還是有辦法繞過(guò)編碼問(wèn)題——可以通過(guò)str(json.load())得到字典(已解碼回中文)后再?gòu)?qiáng)轉(zhuǎn)為字符串再匹配,但是要注意單引號(hào)問(wèn)題
- 轉(zhuǎn)為字典后逐層索引下去,缺點(diǎn)是當(dāng)結(jié)構(gòu)過(guò)于復(fù)雜時(shí),索引也比較麻煩。
?
最終代碼(替換版,使用了selenium模塊)
?
不要看完就算了,記得多實(shí)踐,擼起袖子就是干
import time from selenium import webdriver from lxml import htmletree = html.etree# 爬取函數(shù) def start_search_result(keys):# 創(chuàng)建瀏覽器對(duì)象browner = webdriver.Chrome()browner.get('https://www.taobao.com/')# 給搜索框賦值kw = browner.find_element_by_id("q") # qkw.send_keys(keys)# 模擬點(diǎn)擊搜索按鈕事件iconfont = browner.find_element_by_class_name('search-button')iconfont.click()# 滑動(dòng)至瀏覽器下端browner.execute_script("window.scrollTo(0, document.body.scrollHeight);")time.sleep(5)# 獲取網(wǎng)頁(yè)源碼html = browner.page_source# 獲取HTML數(shù)據(jù)html_etree = etree.HTML(html)return html_etree#解析爬取結(jié)果函數(shù) def analysis_html(html_etree):print("================================================================")# 獲取商品列表goods_list = html_etree.xpath('//div[@class="items"]/div')# 存儲(chǔ)字典的列表goods_map_list = []for k_value in goods_list:# 獲取圖片地址pic_src = "https:" + k_value.xpath('./div[@class="pic-box J_MouseEneterLeave J_PicBox"]/div[@class="pic-box-inner"]/div[@class="pic"]/a/img/@src',stream=True)[0]# 獲取價(jià)格price = "¥" + k_value.xpath('./div[2]/div[1]/div[@class="price g_price g_price-highlight"]/strong/text()',stream=True)[0]# 獲取標(biāo)題title_list = k_value.xpath('./div[2]/div[2]/a/text()', stream=True)title = "".join(title_list).strip().replace("\n", "")# 獲取店鋪名shop_elem = k_value.xpath('./div[2]/div[3]/div[@class="shop"]/a/text()', stream=True)shop_name = "".join(shop_elem).replace("\n", "").strip()if (len(shop_name) == 0):shop_elem = k_value.xpath('./div[2]/div[3]/div[@class="shop"]/a/span[2]/text()', stream=True)shop_name = "".join(shop_elem).replace("\n", "").strip()infor_map = {}infor_map['pic'] = pic_srcinfor_map['price'] = priceinfor_map['title'] = titleinfor_map['shop'] = shop_namegoods_map_list.append(infor_map)return goods_map_list# 主函數(shù) def main():search_key = input('輸入商品名:\n')print("search_key = ", search_key)# 先獲取爬取的HTML文本html_etree = start_search_result(search_key)# 解析HTML,將商品列表存到list里面goods_list = analysis_html(html_etree)for item in goods_list:print("標(biāo)題:" + item["title"])print("價(jià)格:" + item["price"])print("圖片:" + item["pic"])print("店鋪:" + item["shop"])print('-' * 100)main()效果截圖:
總結(jié)
以上是生活随笔為你收集整理的Python爬虫自学之第(⑤)篇——爬取某宝商品信息的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
 
                            
                        - 上一篇: Makefile教程二 变量
- 下一篇: Android 实现切换主题皮肤功能(类
