-前言
之前一直用scrapy與urllib姿勢爬取數據,最近使用requests感覺還不錯,這次希望通過對知乎數據的爬取為 各位爬蟲愛好者和初學者更好的了解爬蟲制作的准備過程以及requests請求方式的操作和相關問題。當然這是一個簡單的爬蟲項目,我會用重點介紹爬蟲從開始制作的准備過程,目的是為了讓和我一樣自學的爬蟲愛好者和初學者更多的了解爬蟲工作。
一、觀察目標網頁模板和策略
很多人都忽略這一步,其實這一步最為重要,因為它決定了你將采取什么策略來獲取數據,也可以評估出你能夠做到什么程度
(1)打開瀏覽器的開發工具F12
這里我用的是Google瀏覽器,打開瀏覽器按F12,你將看到你加載網頁情況,以及網絡請求的方式和交互的參數情況。如果你沒有看到,你應該百度自己的瀏覽器開發者工具,如何打開。我們在打開知乎門戶網頁后,F12看到開發者工具的Network一欄沒有出現任何東西。如圖1.1所示:
開發者工具 圖 1.1
然后我們在知乎搜索框內輸入需要搜索的內容,你將會看到網頁后台與前台數據交互的變化,加載的數據以及數據請求的方式和參數。如圖1.2:
服務端與瀏覽器交互的信息 圖1.2
這里你可以看到有很多js文件和png格式文件,這些文件都是通過你的搜索這個動作,對方服務器返回的文件,根據這些你可以更加了解網頁服務端與瀏覽器的交互過程。這里如果你很有經驗的話,可以根據它的size和name字段快速找出你想要的交互文件。
因為我們之前的搜索操作,所以很容易可以看出來第一個帶有search字段的是搜索操作時和網站服務器交互的文件。點擊我們可以看到 如圖1.3:
與服務器通信請求參數 圖1.3
這里有返回給我們與服務器通信后的過程以及相關數據,右上方可以看到Headers、Previes、Response、cookie等選項 。
-
headers可以看到請求的參數,我們很多時候寫爬蟲訪問服務器被拒絕就是因為這里有很多參數驗證沒有通過,所以學會運用這里的參數是很有必要的。Requests Headers 是你請求時所用的請求頭,重要的是cookie與User-Agent,cookie可以讓你免登陸,雖然有時效性,但是有時候會幫助你節省時間,同時它有時候也是網站監測你是否是爬蟲的手段,userAgent基本都會被服務端檢測,所以每次請求都需要帶上。Query String Parameters是你請求時所帶的參數,因為這里是get方式請求,所以這里的參數在你的請求鏈接是可以看到的。post請求時,這里的參數會很重要,每次請求都必需帶上這些參數,比如賬號登錄,你就可以在這里看到賬號和密碼。
-
Previes 這個文件內容就是網站將會呈現給你的東西,也就是預覽
-
Response 可以看到返回的數據文本,有時候這里可以直接看到json數據,解決動態頁面時,如果你能夠直接找到想要的數據,你可以很輕松的避開js文件,直接訪問這個文件獲取數據。
在知乎首頁搜索后,你會發現沒有換頁,通過不停的下拉,會有新的數據產生。這里我們通過下拉時可以看到它產生了新的文件 如圖 1.4:下拉后變化 圖1.4
多了一個search的請求文件,我們點開和第一個對比發現,offset字段從0變成了10。我們復制一下這里的url在新開的標簽頁粘貼后,發現如圖1.5:
復制鏈接的頁面 圖1.5
看到返回的一個json類型的數據,這里中文都是unicode編碼格式,所以我們需要自己寫點代碼,復制這些字符串,decode解碼出中文。解碼后你會發現,這些都是下拉時網頁顯示的數據。我們就可以通過正則表達式從這里將自己需要的數據提取出來,這里只是網頁的第一層,為了進入第二層(點擊一個鏈接,跳轉的下一個頁面),我們將提取這里所有的鏈接。
回顧我之前文章requests介紹用法,很容易寫出:
#假設每個搜索項有500頁,如果沒有想要的內容,可以breakfor i in range(500): # key是要搜索的關鍵詞 url = 'https://www.zhihu.com/r/search?q='+key+'&correction=1&type=content&offset='+str(i*10) try: #try用在這里,后面會解釋原因 response = requests.get(url,headers=headers) except: continue response.encoding='unicode-escape' page = lxml.html.fromstring(response.text) rule = re.compile('<a target="_blank" href="(.*?)"') hrefs = re.findall(rule,response.text)
好了第一層我們差不多做好了,進入網站第二層,隨意點擊一個我們搜索產生的內容標題,跳轉至一個新的頁面,我們用同樣的方法,觀察第二層我們與服務端交互的信息 如圖 1.6:
第二層服務端交互信息 圖1.6
這里有很多網絡加載好的文件,我們需要找到具有關鍵信息的文件,如果各位有嘗試在程序里直接請求你打開的url鏈接,會發現你得到的東西不是你在網上看到的,這是因為很多文件是通過瀏覽器渲染了js而得到的數據,而我們寫的代碼並沒有這一步,所以我們很多時候用程序訪問動態頁面時,看不到數據。
當然你也可以添加這里面的js文件在代碼中觸發,但是這會變得很復雜,因為js文件作用很多,你要找到你想要的js文件並不容易。我們需要找到更快速有效的方法,這也是為什么“觀察”是爬蟲最重要的一環。
這里我們開始一個一個文件的去看,先看Response,你可以看到他返回的數據和內容。還有就是看它的文件名,這里的answers很容易可以猜到是評論和回答,我們點擊進去Response看到數據,發現確實如我們所想
如圖1.7:
回答請求參數頁面 圖1.7
有上次經驗,可以准確知道offset是用來翻頁的,limit是回答條數,我們同樣復制這條鏈接,和第一層同樣打開一個新的標簽頁,就能看到返回的json數據。我們要做的只需要通過解析工作,提取相關數據就行了。
二、爬蟲的制作
通過觀察所得到的結論,可以找到服務器的請求入口,從第一層找到翻頁的鏈接,然后第二層獲取數據。知乎第二層其實有幾種版式,一種就是我們上文那種問答的形式,還有文章的形式,/question/ 和zhuanlan ,還有視頻,這幾種都要分開討論,分別解析。我這里只介紹問答和文章的解析方式,方法都大同小異。
(1) 搜索關鍵詞進入相關頁面
import requestsimport reimport lxml.html keys = ['.....'] #key 自己定義一個list for key in keys: #假設有500頁 for i in range(500): url = 'https://www.zhihu.com/r/search?q='+key+'&correction=1&type=content&offset='+str(i*10) try: response = requests.get(url,headers=headers) except: continue response.encoding='unicode-escape' page = lxml.html.fromstring(response.text) rule = re.compile('<a target="_blank" href="(.*?)"') hrefs = re.findall(rule,response.text) rule2 = re.compile('<em>(.*?)<') keyword = re.findall(rule2,response.text) response.close() hrefs = [i.replace('\\','') for i in hrefs] if key in keyword: for href in hrefs: if 'question' in href: num = href.replace('/question/','') GetQuestionMsg(key,num) elif 'zhuanlan' in href: GetPageMsg(key,href) else: break
(2) 文章樣式提取數據
def GetPageMsg(key,url): headers = { 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36' } try: response = requests.get(url,headers=headers) except: return #print(response.status_code) print(key) #這里我用xpath方式來解析網頁文本 page = lxml.html.fromstring(response.text) title = page.xpath('//title/text()') title = title[0] content = page.xpath('//div[@class="RichText Post-RichText"]//p/text()')
(3)問答模板提取數據
def GetQuestionMsg(key,num): #這里假設它有500頁 for i in range(500): url = 'https://www.zhihu.com/api/v4/questions/'+num+'/answers?include=data%5B*%5D.is_normal%2Cadmin_closed_comment%2Creward_info%2Cis_collapsed%2Cannotation_action%2Cannotation_detail%2Ccollapse_reason%2Cis_sticky%2Ccollapsed_by%2Csuggest_edit%2Ccomment_count%2Ccan_comment%2Ccontent%2Ceditable_content%2Cvoteup_count%2Creshipment_settings%2Ccomment_permission%2Ccreated_time%2Cupdated_time%2Creview_info%2Crelevant_info%2Cquestion%2Cexcerpt%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%2Cupvoted_followees%3Bdata%5B*%5D.mark_infos%5B*%5D.url%3Bdata%5B*%5D.author.follower_count%2Cbadge%5B%3F(type%3Dbest_answerer)%5D.topics&offset='+str(i*20)+'&limit=20&sort_by=created' headers = { 'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36' } #自行添加自己的cookie值,按第一步所說步驟,復制添加訪問此處網頁的Requests Headers中的cookie cookies={ '_zap':'', ' q_c1':'', ' d_c0':'', ' z_c0':'', ' __DAYU_PP':'', ' q_c1':'', ' aliyungf_tc':'', ' _xsrf':'', ' __utmc':'', ' __utmv':'', ' __utmz':'', ' __utma':'', ' s-q':'', ' sid':'', ' s-i':'', } try: response = requests.get(url,headers=headers,cookies=cookies) except: return response.encoding='unicode-escape' print(key) rule = re.compile('"excerpt": "(.*?)"') content = re.findall(rule,response.text) rule2 = re.compile('"title": "(.*?)"') title = re.findall(rule2,response.text) content =','.join(content) response.close() try: print(title[1]) title = title[1] print(content) except: return
問答時候,添加了cookies,因為直接訪問得不到數據,所以我們需要模擬我們觀察得到的請求頭信息,添加了cookies,發現訪問成功。
三、測試與問題
用requests爬知乎的過程中,經常會遇到一個異常
requests.exceptions.ConnectionError: HTTPSConnectionPool: Max retries exceeded with url:
百度出來的解釋說requests連接請求次數超過了限制次數,需要關閉連接或設置更大的默認連接數,但我都嘗試了,還是會有這種問題。我想應該是其它原因導致的這個錯誤,所以我在每次的response= response.get()時都要加try,拋出異常來保證程序持續運行。如果你們有更好的解決方案和對這個問題的理解,請您回復我或者私信我,不甚感激。
結語 電動堆高車
知乎爬蟲項目到這里就告一段落了,前期工作講的比較細,因為我覺得作為爬蟲工程師對前期工作應該要重視,我之前沒有重視,所以填了很多坑,走了很多彎路,所以借這個項目來講下爬蟲工程師前期工作,當然我講的只是一小塊,實際工作有的會更加復雜,有時候找很久都找不到獲取數據入口,有時候找到了獲取途徑又需要參數驗證,甚至好不容易獲取到了數據,才發現網站能提供的數據量遠遠不夠,這都是前期工作需要做好的內容。這一章獻給和我一樣自學的爬蟲愛好者與初學者。