公衆號:愛寫bug(ID:iCodeBugs)css
週末了,圍觀幾個知乎福利話題:git
女生身材好是什麼體驗?:https://www.zhihu.com/question/328457531github
擁有一雙大長腿是怎樣的體驗?:https://www.zhihu.com/question/297715922mongodb
有個身材火辣的女友是怎樣一種體驗?:https://www.zhihu.com/question/313825759數據庫
這是真福利吖,點開一個問題看一下答主的回答,,,全都是高質量圖片:json
圖片都是一些我的精品照,質量很高。api
但是這每一個話題下都有上千條回答,這得看到啥時候,不停的刷新也得好久。。。因而就寫了這段代碼把這些圖片都下載了,考慮到一些數據可能用到,就順道一塊兒存到數據庫了。包括圖片地址、答主主頁地址、答主暱稱、答主、個性簽名、答主粉絲、相關問題地址、贊同數等等等。當作果圖:app
我懷疑你在開車,可是我沒有證據
函數
尊重答主的分享,因此 以每一位答主暱稱來命名其圖片的父目錄文件夾。可是最後瀏覽圖片一個一個文件夾太麻煩了,因此我統一整理了一下一共 三個話題下2325張圖片放在一個文件夾裏,想直接觀摩一下的同窗公衆號後臺回覆:知乎,壓縮包合集發給你(一個月內有效),下面是講獲取的方法,只對圖片感興趣的不用看了,去回覆吧。工具
點開一個話題,進入開發者工具,刷新頁面,在xhr欄目下,會發現不少請求,左上角過濾一下,只有以 answers?
開頭的纔是回答內容,分析一下請求頭:
知乎的請求結構出奇的簡單,很意外。關鍵信息已在圖片標明。基礎URL是:https://www.zhihu.com/api/v4/questions/313825759/answers?include=
後面全都是根據 Query String Parameters
構造出來的。
而後咱們看一下答主的回答內容:
這裏回答內容有多是引用其餘話題 擁有一雙大長腿是怎樣的體驗?
的圖片,也就是說,咱們只要再把這個引用的話題地址獲取下來,再根據新獲取的地址構造請求URL, 獲得該話題的請求地址,這樣就能夠順着一條回答把全部引用的類似問題其餘答主的圖片所有下載下來。。。
點擊引用的其餘話題,切換知乎話題 擁有一雙大長腿是怎樣的體驗?
,咱們再看一下回答內容:
一樣看一下該話題的 Query String Parameters
只有 limit 、offset兩個屬性會變,而limit 爲限制當頁顯示的回答數量,offset 爲偏移量,就是本頁從第幾條回答開始顯示,其餘屬性全是相同的(知乎頁面限制顯示回答數最大20)。這意味着無論知乎哪一個問題均可由該問題的地址以相同的方法構造請求URL:
param = { 'include': '',#太長了,不展現了 'limit': '20', # 限制當頁顯示的回答數,知乎最大20 'offset': offset, # 偏移量 'platform': 'desktop', 'sort_by': 'default', } base_URL = 'https://www.zhihu.com/api/v4/questions/297715922/answers?include=' # 基礎 url 用來構造請求url url = base_URL + urllib.parse.urlencode(param) # 構造請求地址
再點擊 preview 看返回的 json 格式的信息:
有個totals,是該話題下總回答數,能夠根據這個計算多少次能夠遍歷所有回答,考慮到後面回答內容質量就跟不上了,咱們只獲取前800條回答。
展開一條回答:
全部的信息包括答主信息和回答的信息都在了,content內容就是回答內容,複製下來,格式化發現這是css渲染的內容,也能理解,知乎回答必需要用富文本方式編輯,返回的內容必然是這種格式。看一下回答內容:
這個層次很明瞭,a 節點的 href 屬性就是引用的相關問題的地址。figure 節點 下 noscript 節點下 img節點的 src 屬性就是圖片地址。用 pyquery 解析:
for answer in json['data']: answer_info = {} # 獲取做者信息 author_info = answer['author'] author = {} author['follower_count'] = author_info['follower_count'] # 做者被關注數量 author['headline'] = author_info['headline'] # 個性簽名 author['name'] = author_info['name'] # 暱稱 author['index_url'] = author_info['url'] # 主頁地址 # 獲取回答信息 voteup_count = answer['voteup_count'] # 贊同數 comment_count = answer['comment_count'] # 評論數 # 解析回答內容 content = pq(answer['content']) # content 內容爲 xml 格式的網頁,用pyquery解析 imgs_url = [] imgs = content('figure noscript img').items() for img_url in imgs: imgs_url.append(img_url.attr('src')) # 獲取每一個圖片地址 # 獲取回答內容引用的其餘類似問題 question_info = content('a').items() ......太多不所有展現了,有興趣能夠看一下文末完整源代碼
飲水思源保存文件以答主暱稱命名,以示尊敬:
def save_to_img(imgs_url, author_name, base_path): path = base_path + author_name if not os.path.exists(path): # 判斷路徑文件夾是否已存在 os.mkdir(path) for url in imgs_url: try: response = requests.get(url) if response.status_code == 200: img_path = '{0}/{1}.{2}'.format(path, md5(response.content).hexdigest(), 'jpg') # 以圖片的md5字符串命名防止重複圖片 if not os.path.exists(img_path): with open(img_path, 'wb') as jpg: jpg.write(response.content) else: print('圖片已存在,跳過該圖片') except requests.ConnectionError: print('圖片連接失效,下載失敗,跳過該圖片') print('已保存答主:' + author_name + ' 回答內容的全部圖片')
以圖片內容的 md5 編碼命名能夠防止重複圖片,若是圖片被其餘人下載以後加水印再上傳,圖片內容是不一樣的,因此可能有重複照片。
若是有須要能夠把這些數據存到數據庫,這裏我以mongoDB爲例:
#存儲在mongoDB client = MongoClient(host='localhost') print(client) db = client['zhihu'] collection = db['zhihu'] def save_to_mongodb(answer_info): if collection.insert(answer_info): print('已存儲一條回答到MongoDB')
圖中存儲了答主引用的其餘話題標題及地址,能夠把這個地址傳回去循環獲取,直到全部相似話題圖片所有下載。
算了,太多了,養分跟不上。這裏就打包開頭那三個話題前800條回答的圖片共2325張。公衆號回覆 知乎 得到壓縮包。
後面我大概看了一下里面的圖片,裏面仍是有一點點重複的,並且還有一些什麼表情圖在裏面,這都沒什麼,忍不了的是裏面還有一點男士 秀本身的照片。。。跟預期不同吖。
你們可根據狀況加些判斷函數,例如圖片中間大概位置的像素點是否相同,來真正的把重複圖片去掉。加些人體身材特徵值對比,去掉男士的圖片和表情圖。這個太慢了,有時間的朋友自行發揮,我是要出去玩嘍,週末開心。
源碼地址:https://github.com/zhangzhe532/icodebugs/tree/master/DataAnalysis/zhihu_get_pic
公衆號:愛寫bug