:知乎回答文本與圖片采集源碼解析)
簡介這份資源面向具備Python基礎、希望入門網絡數據采集的開發(fā)者與數據分析學習者圍繞知乎問答社區(qū)場景講解如何抓取回答中的文本與圖片。內容涉及HTTP請求發(fā)送、HTML解析、文件讀寫與延時策略等環(huán)節(jié)幫助讀者理解從問題ID定位頁面到提取回答正文、圖片鏈接及作者信息的完整思路。壓縮包共3個文件包含2個py腳本與1個txt依賴清單分別承擔數據抓取、結果保存和運行環(huán)境說明的職責整體約4KB結構精簡便于快速閱讀與二次修改。目前已有1144人學習下載適合作為爬蟲練手項目參考。讀者可從中獲得請求構造、解析提取、圖片下載與本地存儲的代碼范例并了解通過time.sleep控制請求頻率、設置計數器限制下載數量等防封禁思路為后續(xù)數據分析和信息挖掘打下實踐基礎。1. 從一份 Python 爬蟲源碼說起知乎回答文本與圖片怎么落地知乎回答頁面的內容結構是很多做數據采集的開發(fā)者繞不開的一道坎。正文里混著富文本、代碼塊、外鏈圖片圖片還分「點開大圖」和「縮略圖」兩套地址直接拿 requests 抓 HTML 往往只能撈到一堆懶加載占位符。這份 Python 爬蟲源碼包針對的就是「把某個問題下所有回答的文本和圖片完整扒下來」這個具體訴求輸出結構化的文本文件和本地圖片目錄。它適合做輿情分析、內容歸檔、數據集構建的從業(yè)者也適合剛學完 requests 和 BeautifulSoup、想找一個真實站點練手的開發(fā)者。源碼里對請求頭、分頁、圖片下載做了封裝但知乎的反爬策略這幾年一直在變直接跑之前得先搞清楚它的邊界在哪。2. 拆解爬取鏈路從請求構造到圖片落盤2.1 為什么不能只靠 requests BeautifulSoup知乎回答列表頁在未登錄狀態(tài)下只返回前幾條回答往下滾動觸發(fā)的是 XHR 接口返回的是 JSON 結構而不是完整 HTML。這意味著純靜態(tài)解析的路子走不通。源碼里采用的是「先拿頁面里的初始數據再走接口翻頁」的混合策略。初始頁面里嵌了一個js-initialData的 script 標簽里面是 JSON 格式的初始狀態(tài)包含前幾個回答的完整內容后續(xù)回答則通過api/v4/questions/{id}/answers這個接口按limit和offset分頁拉取。這個接口返回的 JSON 里data數組每一項的content字段是 HTML 字符串excerpt是純文本摘要。圖片信息藏在content的img標簽里>import requests import json import re import os from urllib.parse import urlparse # 基礎請求頭Cookie 需要替換成自己瀏覽器里抓到的有效值 HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Referer: https://www.zhihu.com/, Cookie: 你的_cookie_字符串, # 關鍵字段缺失會導致分頁受限 } def fetch_answers(question_id, offset0, limit20): 按偏移量拉取回答列表返回 JSON 中的 data 數組 api fhttps://www.zhihu.com/api/v4/questions/{question_id}/answers params { include: data[*].content,excerpt,author,created_time, limit: limit, offset: offset, sort_by: default, } resp requests.get(api, headersHEADERS, paramsparams, timeout15) if resp.status_code ! 200: print(f請求失敗狀態(tài)碼{resp.status_code}) return [] return resp.json().get(data, [])這段代碼里include參數決定了返回字段的豐富程度不傳的話content可能不返回。limit單次最大一般不超過 20設太大容易被截斷。offset按 20 遞增直到返回的data為空或paging.is_end為 true 為止。實際跑的時候建議在每次請求之間加 1 到 2 秒延時源碼里用的是time.sleep(random.uniform(1, 2))這個習慣能省掉很多封禁麻煩。2.3 文本清洗與圖片地址提取拿到content字段后它是一段 HTML。文本提取不能直接上正則去標簽因為代碼塊里的會被誤傷。源碼里用的是 BeautifulSoup 的get_text()配合分隔符把塊級元素之間補上換行。from bs4 import BeautifulSoup def extract_text_and_images(html_content): 從回答 HTML 中提取純文本和原圖地址列表 soup BeautifulSoup(html_content, html.parser) # 把 br 和 p 替換成換行避免文本粘連 for tag in soup.find_all([br, p, div]): tag.append(\n) text soup.get_text(separator\n, stripTrue) image_urls [] for img in soup.find_all(img): # 優(yōu)先取>import hashlib import os def download_images(image_urls, save_dir): 下載圖片到指定目錄返回成功數量 os.makedirs(save_dir, exist_okTrue) success 0 for url in image_urls: try: resp requests.get(url, headersHEADERS, timeout20, streamTrue) if resp.status_code 200: # 用 URL 的 MD5 做文件名避免重名 ext os.path.splitext(urlparse(url).path)[1] or .jpg fname hashlib.md5(url.encode()).hexdigest() ext fpath os.path.join(save_dir, fname) with open(fpath, wb) as f: for chunk in resp.iter_content(1024): f.write(chunk) success 1 except Exception as e: print(f下載失敗 {url}{e}) return successstreamTrue配合iter_content是為了避免大圖一次性讀進內存。超時設 20 秒比文本請求寬松一些因為圖片服務器響應偶爾會慢。如果某張圖反復失敗源碼里不會中斷整個流程只是記錄日志繼續(xù)下一張這個設計在批量任務里很實用。3. 避坑與排查那些跑起來才會遇到的問題3.1 現象接口返回 403 或空數據原因通常是 Cookie 過期或請求頭里缺少Referer。知乎對接口的校驗不只看 Cookie還會檢查來源頁。解決方法是重新從瀏覽器開發(fā)者工具里復制最新 Cookie并確保Referer指向https://www.zhihu.com/。如果換了 IP 或短時間內請求過多也可能觸發(fā)風控這時候需要降低頻率把延時拉到 3 秒以上。3.2 現象圖片下載下來是 1KB 左右的空白圖這是典型的懶加載占位圖。原因在于提取時取了src而不是>import yaml import os def load_config(pathconfig.yaml): with open(path, r, encodingutf-8) as f: cfg yaml.safe_load(f) # 環(huán)境變量優(yōu)先級高于配置文件 cfg[cookie] os.getenv(ZHIHU_COOKIE, cfg.get(cookie, )) return cfg4.2 斷點續(xù)爬與日志記錄批量任務最怕跑到一半中斷重新跑又得從頭來。源碼里用了一個簡單的狀態(tài)文件記錄已完成的 offset 和已下載的圖片 URL 集合。每次啟動先讀狀態(tài)跳過已完成部分。日志用logging模塊輸出到文件格式包含時間戳、級別和消息方便事后排查哪一頁出了問題。參數建議值說明請求間隔1.53 秒太短觸發(fā)風控太長效率低單次 limit20超過 20 容易被截斷圖片超時20 秒大圖下載留足時間重試次數2 次失敗后間隔 3 秒重試狀態(tài)保存頻率每頁一次避免頻繁寫盤4.3 驗證抓取完整性的方法跑完之后怎么確認沒漏可以對比接口返回的paging.totals字段和實際保存的回答數量。如果差距超過 5%說明中間有失敗頁需要檢查日志里的 403 或超時記錄。圖片方面統(tǒng)計每個回答目錄下的文件數和提取階段的 URL 數量做對比差值就是下載失敗的圖片。我一般會在腳本最后打印一份匯總總回答數、成功文本數、圖片總數、下載成功數、失敗列表。這份匯總比任何日志都直觀。從那以后我每次寫采集腳本都強制先跑一個「只抓一頁、只下三張圖」的冒煙測試確認鏈路通了再放開批量。這個習慣幫我省下了不少因為 Cookie 過期或接口變更導致的整夜空跑。希望這份源碼的拆解能幫到你拿到手之后先改配置、再跑冒煙、最后開批量順序別亂。本文還有配套的精品資源點擊獲取