准備爬取太平洋網上的小米手機的評論,因為發現評論已經自動打好標簽了,並且對於手機的幾種性能表現也打了分,以及詳細的評論都有,對於后面自己的工作有幫助,所以就准備爬取這些評論.但發現這個網站的每次點下一頁都是相同的URL地址,也就是說源代碼只顯示第一頁的評論內容,對於用requests來爬取網頁內容,用這個地址的話無法爬取更多內容。后來查了一下,這是用了Ajax動態加載技術,專門用來動態加載網頁內容,實現網頁的異步更新。
關於Ajax的比較詳細的解釋推薦兩個鏈接,比較詳細的闡述了這是怎么回事,爬取Ajax動態加載和翻頁時url不變的網頁+網站案例,爬取Ajax動態加載和翻頁時url不變的網頁。自己說一下我遇到的問題,以及如何既解決的方法,我的問題比較簡單就是翻頁url地址不變,無法爬取下一頁評論的內容。其實這是因為網站的網站隱藏住了url地址后面的參數部分,只顯示了地址的主體部分,辦法很簡單就是找到這些網頁url地址被隱藏的參數部分。下面講一下我的解決步驟:
我爬去的網站是這個小米6x(4GB RAM)點評,當你點開網站點擊下一頁,再看看對應的url地址都是一樣的沒有變化,再看看對應的源代碼發現都是一樣的,只顯示第一頁的評論內容,第2,3,4....內容無法找到。開始找網站被隱藏的url參數部分。我用的瀏覽器時谷歌Chrome瀏覽器,按F12打開開發者選項,打開找到最上面導航欄network,下面選擇All,篩選網頁文件類型,這里也可選XHR表示動態網頁類型,選擇右邊的preview來展示網頁的內容用來確定我們要找的網頁,
我們點擊最左側網頁中的下一頁就會在邊上的對應文件中找到這個網頁的代碼文件信息,通過preview可以看見這個文件的預覽。當我們找到要找的網頁時,在點擊headers找到我們所要的信息。
Query String Parameters顯示了我們請求的網頁地址的參數部分,也就是我們網頁的主體部分是'http://product.pconline.com.cn/readIntf.jsp?'參數部分是'url:http://pdcmt.pconline.com.cn/front/2015/mtp-list.jsp?productId=1073867&filterBy=-1&itemCfgId=-1&order=2&pageNo=2&vId=432764',我們打來的網頁的完整url地址是 'http://product.pconline.com.cn/readIntf.jsp?url=http%3A%2F%2Fpdcmt.pconline.com.cn%2Ffront%2F2015%2Fmtp-list.jsp%3FproductId%3D1073867%26filterBy%3D-1%26itemCfgId%3D-1%26order%3D2%26pageNo%3D2%26vId%3D432764'。標黃部分就是參數部分。再打開幾頁評論發現,參數部分的pageNo=1,2,3,4,5...分別代表評論的1,2,3,4.。。頁,也就是說我們找到下一頁評論網站的頁碼,改變這個值,就可以進入到不同頁面的評論頁面了。在編碼時為了方便用get(url,params)直接得到完整的url地址,params是參數的字典表示即params={'url':'http://pdcmt.pconline.com.cn/front/2015/mtp-list.jsp?productId=1073867&filterBy=-1&itemCfgId=-1&order=2&pageNo=2&vId=432764'},這時候發現改動pageNo比較困難,所以嘗試用這個參數地址試試能不能打開評論頁面,結果發現可以打開,只要改動頁面值,就可跳到相應的評論頁,同樣,按F12,找到這個頁面對應的Query String Parameters.
可以看見,Query String Parameters.對應是個字典,也可以通過鍵值對的形式改變字典pageNo的值,來達到訪問不同評論網址的目的。下面就是爬取網站內容的工作了,這就是我找隱藏網址的過程。
總結一下,我們就是在找動態網頁的時候通過打開開發者選項(F12),找到要爬取網頁文件的header,在Query String Parameters中找到對應的參數部分,最后將url主體部分和參數部分結合一起就能得到完整的url地址了。
下面附一下爬取的代碼:
1 from bs4 import BeautifulSoup 2 import requests 3 import re 4 import pandas as pd 5 6 #太平洋網爬取小米6X的評論 7 #動態網頁爬取(ajax) 8 9 10 def getHtml(url,data): #只輸入URL的主體部分,后面的參數用下面的字典附加上 11 try: 12 r=requests.get(url,params=data) 13 r.raise_for_status() 14 r.encoding=r.apparent_encoding 15 return r.text 16 except: 17 print('爬取失敗') 18 19 def getComment(html):#獲得一頁的評論 20 commentList=[] 21 soup=BeautifulSoup(html,'html.parser') 22 lines=soup.find_all('dl',attrs={'class':'cmt-content'})#獲得一整頁所有的評論總的標簽內容 23 for line in lines:#對每個評論進行解析,line就是每個評論的總標簽內容<di class=cmt_content...> ...</dl> 24 goal=line.find('strong',attrs={'class':'goal'}).string#得到總評分 25 comm_totall=line.find('div', attrs={'class':'eval-star'}).p.string.strip()#總評價 26 catagory=line.find('ul',attrs={'class':'goal-detail'}).find_all('li')#獲得幾個屬性的評價 27 # print(catagory) 28 a1=catagory[0].string 29 a2 = catagory[1].string 30 a3 = catagory[2].string 31 a4 = catagory[3].string 32 a5 = catagory[4].string 33 comm_detail=line.find('p',attrs={'class':"text"})#具體評價,但這部分內容存在標簽與字混合的成分,要把標簽替換掉 34 detail_new=re.sub(r'<.*?>','',str(comm_detail))#因為部分內容存在空格\xa0,要去掉這部分空格的代碼顯示 35 detail=','.join(detail_new.split())#用逗號來將分割的字符串兩節起來,join()函數用來連接字符串數組元素 36 commentList.append([goal,comm_totall,a1,a2,a3,a4,a5,detail]) 37 return commentList 38 # print(commentList) 39 40 def comment(url,num):#獲得多個頁面的評論 41 data={'productId': 1073867, 42 'filterBy': -1, 43 'itemCfgId': -1, 44 'order': 2, 45 'pageNo': 1, 46 'vId': 432764} 47 comment_all=[] 48 for i in range(1,num+1): 49 data['pageNo']=i 50 html=getHtml(url,data) 51 comment=getComment(html) 52 comment_all+=comment 53 print('頁數',i) 54 #print(comment_all) 55 return comment_all 56 57 if __name__=='__main__': 58 url='http://pdcmt.pconline.com.cn/front/2015/mtp-list.jsp?' 59 a=comment(url,17) 60 print(len(a)) 61 name = ['總評分', '總評價','性價比','屏幕','流暢度','電池','相機','細評'] 62 test = pd.DataFrame(columns=name, data=a) 63 test.to_csv('D:/mi6x.csv', index=False) # 去掉默認的行索引index