#老司機教你看妹子——你的第一個知乎爬蟲(2)

老司機教你看妹子——你的第一個知乎爬蟲(2)

“老師快教我怎么才能獲取完整圖片秒梳?”

別急,還記得上回說的,設(shè)置UA的事情么

“嗯字柠, 要把自己偽裝成一個瀏覽器

我們先看看瀏覽器做了什么。

瀏覽器做了什么

你已經(jīng)知道了,知乎的網(wǎng)頁是通過 Ajax 進行 異步加載西潘, 證據(jù)就是那個大大的“更多”按鈕。

點一下,就加載更多食茎。

那么點了按鈕之后究竟發(fā)生了什么呢?瀏覽器可以告訴我們究竟發(fā)生了什么哎媚。

使用Chrome瀏覽器,在頁面上單擊鼠標右鍵->審查元素(檢查)捻悯,就可以喚起開發(fā)者工具。

切換到Network一欄里,然后點擊“更多”何荚,就可以看到點擊了“更多”后面發(fā)生了什么網(wǎng)絡(luò)請求。

你看到了什么?

“一堆圖片請求,然后上面的那個看圖標應(yīng)該是文件之類的狂票,而且有29k,加載了630ms。而且国瓮,從時間順序上看,先執(zhí)行獲取到了這個數(shù)據(jù)播歼,然后再加載的圖片叭莫∈彻眩”

Ok善榛,那我們點開看一下悼院。

fetch-preview.png
fetch-preview2.png

啊哈颖医!

“這里是具體的回答數(shù)據(jù)熔萧!那我只需要調(diào)用這個接口辙谜,就可以拿到所有的答案了装哆!“

Copy as cURL

你迫不及待的寫下了爹殊,r = requests.get(url,headers=ua_header) 這樣的代碼,卻發(fā)現(xiàn)了我在旁邊笑而不語辛块。

“有什么問題么润绵?”

不要急著動手寫,先分析下這個請求都帶了那些參數(shù)卿捎。

“是指的url里的參數(shù)么?”

不是。選中那個請求籽懦,然后右鍵->Copy->Copy as cURL

cURL是一個利用URL語法在命令行下工作的文件傳輸工具呆盖,絕大多數(shù)的linux 和unix都會內(nèi)置的一個軟件.
但是宙项,注意windows下命令行里調(diào)用的curl并不是這里提到的那個curl尤筐,具體的討論可以看這篇:PowerShell 為什么 alias 了 curl 就引起了如此大的爭議旬蟋?

“那我現(xiàn)在要去裝curl?”

別急啊,我們先看看我們復制出來了什么。

curl 'https://www.zhihu.com/api/v4/questions/22212644/answers?sort_by=default&include=data%5B%2A%5D.is_normal%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%2Cmark_infos%2Ccreated_time%2Cupdated_time%2Creview_info%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%2Cupvoted_followees%3Bdata%5B%2A%5D.author.follower_count%2Cbadge%5B%3F%28type%3Dbest_answerer%29%5D.topics&limit=721&offset=0' -H 'Cookie: aliyungf_tc=AQAAADvok2VGQgEAiE1NfJc49LzrUk7p; q_c1=ef155c9cc9124e1f951447b3b6fd875f|1500990779000|1500990779000; _zap=84936da1-3813-4842-a846-56214e791bd0; q_c1=70bd5b2623c14a3d9079630a483b0aa3|1500990778000|1500990778000; l_n_c=1; l_cap_id="NDczNThhZjExZWU1NDIzYWJhMDllNjBkZTJiNDUwZGI=|1500990807|075d561c18784c75946ae101e6f7135b5b271cf3"; r_cap_id="Y2MwNzdlMjMxMjc0NDViMGE0NWJhOTI3NGQzNjQwNGY=|1500990807|769b04b121d8b52602f6d7f3e86ca62bf5f80d33"; cap_id="ZTFkYmRiMjZiZTgyNDdjY2I3YTk3ZDExNDZjZDUyYmY=|1500990807|2f85fb4342ee06cfe26e5ba006d699c778a7787c"; n_c=1; _xsrf=b967f17b-4577-428e-906d-1c306c67decd' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.6,en;q=0.4' -H 'authorization: oauth c3cef7c66a1843f8b3a9e6a1e3160e20' -H 'accept: application/json, text/plain, */*' -H 'Referer: https://www.zhihu.com/question/22212644' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36' -H 'Connection: keep-alive' --compressed

嗯迎捺,這么長一行確實挺惡心的,我們來換個行范舀。

curl
'https://www.zhihu.com/api/v4/questions/22212644/answers
?sort_by=default
&include=data%5B%2A%5D.is_normal%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%2Cmark_infos%2Ccreated_time%2Cupdated_time%2Creview_info%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%2Cupvoted_followees%3Bdata%5B%2A%5D.author.follower_count%2Cbadge%5B%3F%28type%3Dbest_answerer%29%5D.topics
&limit=20
&offset=3'
-H 
'Cookie: 
    aliyungf_tc=AQAAADvok2VGQgEAiE1NfJc49LzrUk7p;   q_c1=ef155c9cc9124e1f951447b3b6fd875f|1500990779000|1500990779000; _zap=84936da1-3813-4842-a846-56214e791bd0;
    l_n_c=1;
    l_cap_id="NDczNThhZjExZWU1NDIzYWJhMDllNjBkZTJiNDUwZGI=|1500990807|075d561c18784c75946ae101e6f7135b5b271cf3";
    r_cap_id="Y2MwNzdlMjMxMjc0NDViMGE0NWJhOTI3NGQzNjQwNGY=|1500990807|769b04b121d8b52602f6d7f3e86ca62bf5f80d33";    cap_id="ZTFkYmRiMjZiZTgyNDdjY2I3YTk3ZDExNDZjZDUyYmY=|1500990807|2f85fb4342ee06cfe26e5ba006d699c778a7787c";
    n_c=1;
    _xsrf=b967f17b-4577-428e-906d-1c306c67decd'
-H 'Accept-Encoding: gzip, deflate, br'
-H 'Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.6,en;q=0.4'
-H 'authorization: oauth c3cef7c66a1843f8b3a9e6a1e3160e20'
-H 'accept: application/json, text/plain, */*'
-H 'Referer: https://www.zhihu.com/question/22212644'
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'
-H 'Connection: keep-alive'


curl的第一參數(shù)就是要請求的url辅辩, -H表示一個Header,所以,這個請求總共有8個Header,其中一個是cookie节沦。

“老師,cookie是啥”

(如果你知道cookie是啥,可以跳過下面的小節(jié))

cookie與session

我們從一個故事開始。

你去柜臺買東西,付錢拿貨走人。第二天你又去柜臺,說說好的贈品還沒給呢聋袋。店員說,你誰啊啥容,要啥贈品啊击吱,買東西那邊排隊去覆醇。卒永脓。后來為了避免這種情況,柜臺會給個你一個收據(jù)排宰,同時也會記錄那些東西賣出去了详炬,還欠著贈品。你下次來的時候,帶著收據(jù),柜臺根據(jù)收據(jù)割坠,一查賬,誒發(fā)現(xiàn)確實欠你個贈品剪菱,然后給你贈品。大家都美滋滋蚪拦。

“店員就這么蠢驰贷,一點都不記事么”

對次兆,最開始的http協(xié)議就是這樣恃慧,一次請求結(jié)束后痢士,連接就斷開了。后來有了cookie的誕生,發(fā)送一些額外的信息,用來標記用戶。

“那cookie就是收據(jù)为肮,session就是店家的記錄?”

對,cookie和session分別表示存在瀏覽器和服務(wù)器的某些數(shù)據(jù)重斑,這些數(shù)據(jù)被用來標識用戶和記錄狀態(tài)。而且cookie是通常都是服務(wù)器設(shè)置的漾脂。

Request with cookie

“那我就把這些cookie直接寫近代碼里就可以了么姜钳?”

cookie會過期哥桥,所以昔期,最好還是要知道這些cookie從何而來佛玄。

我們從頭開始般贼,看看服務(wù)器給我們設(shè)置了那些cookie

在做這個之前,你要先進入Chrome的隱身模式,隱身模式會清除你以前瀏覽器留下的cookie叠洗,其實之前我們所有的請求都是在隱身模式下發(fā)起的。

點開第一條請求荤牍,我們看到了_xsrf和aliyungf_tc這兩個cookie

_xsrf這樣的字段通常是用來防止XSRF(跨站請求偽造)的愧杯,而且aliyungf_tc力九,從名稱上來看,應(yīng)該是阿里云高防塞的抵乓。

“那q_c1, l_n_c, l_cap_id,r_cap_id,cap_id, n_c這些呢颅眶?”

一點小經(jīng)驗:這種充斥著大量連字符、意義不明的cookie商叹,都可以忽略,這些通常是在某些中間步驟被設(shè)置進去的。

我們分析了這么多酪夷,終于可以開始寫了。

我們上次用到的requests庫,提供了一個requests.Session()對象,可以用來很方面的模擬一次會話字管,它會設(shè)置根據(jù)服務(wù)器的返回自動cookie。

def init(url):
    ua = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'}
    s = requests.Session()
    s.headers.update(ua)
    ret=s.get(url)
    return s

“老師,這個get的這個url是干啥用的汁胆,為啥返回值直接不要了”

會想一下我們剛剛分析的整個流程沦泌,首先打開了某個網(wǎng)頁萝衩,然后JS調(diào)用了"https://www.zhihu.com/api/v4/questions/22212644/answers"這樣一個接口千劈。所以墙牌,我們要模擬打開網(wǎng)頁的那一步撤防,讓服務(wù)器給我們設(shè)置cookie辜膝。

“然后接下來模擬js調(diào)用?”

然也

def fetch_answer(s,qid,limit,offset):
    params={
        'sort_by':'default',
        'include':'data[*].is_normal,is_collapsed,annotation_action,annotation_detail,collapse_reason,is_sticky,collapsed_by,suggest_edit,comment_count,can_comment,content,editable_content,voteup_count,reshipment_settings,comment_permission,mark_infos,created_time,updated_time,review_info,relationship.is_authorized,is_author,voting,is_thanked,is_nothelp,upvoted_followees;data[*].author.follower_count,badge[?(type=best_answerer)].topics',
        'limit':limit,
        'offset':offset
    }
    url ="https://www.zhihu.com/api/v4/questions/"+qid+"/answers"
    return s.get(url,params=params)

qid,就是url后面的那一串數(shù)字保檐,question_id,limit表示一次拉去多少個回答、offset表示從第幾個開始扔亥。

接下來你就可以運行一下了踢关。

url = "https://www.zhihu.com/question/29814297"
session = init(url)
q_id = url.split('/')[-1]
offset = 0
limit=20
ret=fetch_answer(session,q_id,limit,offset)

如果不出意外的話,你可能會看到這樣一個結(jié)果:

“呃芙贫,老師這個\u8bf7這一串是什么”

最簡單的方式磺平,把這一串copy出來,貼到交互式窗口里:

請求頭錯誤,我們可以通過ret.request.headers查看我們個發(fā)出的請求,究竟包含了那些header

對比之后,發(fā)現(xiàn)捶牢,少了authorization: oauth c3cef7c66a1843f8b3a9e6a1e3160e20

我們在init函數(shù)里把它加上

def init(url):
    ua = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'}
    s = requests.Session()
    s.headers.update(ua)
    ret=s.get(url)
    s.headers.update({"authorization":"oauth c3cef7c66a1843f8b3a9e6a1e3160e20"})
    return s

在執(zhí)行一次炬太,我們終于成功了

獲取所有答案

“等一下可缚,老師帘靡,剛剛那個fetch_answer戈次,limit我們可以直接設(shè)置到99999啊朝扼,然后不久可以一口氣拿回來所有的么,或者我們找下總共有多少個回答驮俗,然后設(shè)置成那個數(shù)字不就好了嘛∷髋耄”

你一天吃三頓飯况木,但是你會一口氣吃光三頓飯么火惊!這么做當然可以,但是這樣的行為十分反常,而且很可能觸發(fā)某些反爬蟲機制俗他,因為這個特征太明顯了。牢記一點,你是一個瀏覽器雷袋。

(實際上知乎會把大于20的limit當做20去處理)

這里我們因為不關(guān)心總數(shù),所以就利用fetch_answer返回的paging里的is_end字段,來判斷是否獲取完畢刃泡。

def fetch_all_answers(url):
    session = init(url)
    q_id = url.split('/')[-1]
    offset = 0
    limit=20
    answers=[]
    is_end=False
    while not is_end:
        ret=fetch_answer(session,q_id,limit,offset)
        #total = ret.json()['paging']['totals']
        answers+=ret.json()['data']
        is_end= ret.json()['paging']['is_end']
        print("Offset: ",offset)
        print("is_end: ",is_end)
        offset+=limit
    return answers

最后烘贴,我們拿到了一個answer的數(shù)組庙楚,從每個answer里的'content'字段里找出url,下載就好了趴樱。

url = "https://www.zhihu.com/question/29814297"
answers=fetch_all_answers(url)
folder = '29814297'
for ans in answers:
    imgs = grep_image_urls(ans['content'])
    for url in imgs:
        download(folder,url)

完整的代碼在這里

“老師圖呢馒闷?”

最后爬取了“日常穿JK制服是怎樣一種體驗?”這樣一個問題叁征,拿到了970張圖


“老師纳账,我們下節(jié)課干啥”

關(guān)注我,下節(jié)課你就知道了疏虫。

我的知乎,或者我的簡書

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子呢袱,更是在濱河造成了極大的恐慌,老刑警劉巖翅敌,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件羞福,死亡現(xiàn)場離奇詭異,居然都是意外死亡蚯涮,警方通過查閱死者的電腦和手機治专,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遭顶,“玉大人张峰,你說我怎么就攤上這事“羝欤” “怎么了喘批?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長铣揉。 經(jīng)常有香客問我饶深,道長,這世上最難降的妖魔是什么老速? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任粥喜,我火速辦了婚禮,結(jié)果婚禮上橘券,老公的妹妹穿的比我還像新娘额湘。我一直安慰自己,他們只是感情好旁舰,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布锋华。 她就那樣靜靜地躺著,像睡著了一般箭窜。 火紅的嫁衣襯著肌膚如雪毯焕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天磺樱,我揣著相機與錄音纳猫,去河邊找鬼。 笑死竹捉,一個胖子當著我的面吹牛芜辕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播块差,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼侵续,長吁一口氣:“原來是場噩夢啊……” “哼倔丈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起状蜗,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤需五,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后轧坎,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宏邮,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年眶根,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜀铲。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片边琉。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡属百,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出变姨,到底是詐尸還是另有隱情族扰,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布定欧,位于F島的核電站渔呵,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏砍鸠。R本人自食惡果不足惜扩氢,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望爷辱。 院中可真熱鬧录豺,春花似錦、人聲如沸饭弓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弟断。三九已至咏花,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間阀趴,已是汗流浹背昏翰。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留刘急,地道東北人棚菊。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像排霉,于是被迫代替她去往敵國和親窍株。 傳聞我的和親對象是個殘疾皇子民轴,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容