目標:爬取今日頭條頭條號王者榮耀資訊和視頻狞贱。
爬蟲關(guān)鍵點:1.分析單頁面獲取所需要的內(nèi)容刻获,2.找到文章列表頁翻頁規(guī)律蜀涨,3.解析加密信息瞎嬉,獲取所需要的內(nèi)容
?????? (1)通過搜索接口獲取今日頭條王者榮耀資訊
最初策略是通過今日頭條首頁搜索框搜索關(guān)鍵字“今日頭條”,獲取搜索列表厚柳。經(jīng)過分析fillder 抓包可以得到今日頭條搜索接口是https://www.toutiao.com/search/?keyword= 最后接上關(guān)鍵字既可以搜索得到想要的內(nèi)容氧枣,但實際上獲取文章列表真正鏈接的請求是:
“https://www.toutiao.com/search_content/?offset=0&format=json&keyword=王者榮耀&autoload=true&count=20&cur_tab=1&from=search_tab&pd=synthesis“
去掉其他信息之后,最終獲取的有效的url是:
https://www.toutiao.com/search_content/?offset=0&format=json&keyword=王者榮耀&count=20
現(xiàn)在就很簡單了别垮,可以看到offset是翻頁便监,format=json則表示是通過json格式生成傳遞數(shù)據(jù),keyword則表示搜索的關(guān)鍵字碳想,count 則表示一次傳輸獲取到的數(shù)據(jù)烧董。
第二步就是文章列表中,每一個關(guān)鍵的json數(shù)據(jù)樣式胧奔,現(xiàn)在我們通過鏈接可以看到我們獲取到的數(shù)據(jù)央視是這樣的:
看起來很繁雜逊移,仔細分析之后,可以看到龙填,實際上是有規(guī)律可以遵循的胳泉,重點關(guān)注的是json格式數(shù)據(jù)里面的data的value值,里面是真正的文章信息列表⊙乙牛現(xiàn)在分析清楚之后扇商,可以放下,再進行單頁面的分析請求宿礁。
經(jīng)過分析可以得到案铺,今日頭條單頁面url鏈接是:
?????? “https://www.toutiao.com/a6645464825897943555/“
很明顯,最后的那一串?dāng)?shù)字是關(guān)鍵梆靖,那么红且,這一串?dāng)?shù)字是從哪里獲取的呢坝茎,現(xiàn)在就要回頭看前面的請求列表了,我們拿著“6645464825897943555“這串?dāng)?shù)字,在前面的
文章列表進行搜索暇番,輕易的發(fā)現(xiàn)嗤放,展示這串?dāng)?shù)字的key值就是data里面的“group_id”雖然有點驚訝,但是最終還是拿到了壁酬。
現(xiàn)在我們通過搜索獲取文章列表次酌,跳轉(zhuǎn),和翻頁我們都找到了接口舆乔。下面的事情就簡單了岳服,獲取單頁面數(shù)據(jù)。當(dāng)我點開網(wǎng)頁源代碼的時候希俩,發(fā)現(xiàn)里面就有我想要的內(nèi)容吊宋。
最后通過xpath或者是正則就可以獲取一個單頁面文章所需要的內(nèi)容。
? ? ?這個頁碼有很多亂碼颜武,經(jīng)過百度之后璃搜,發(fā)現(xiàn)其實這些亂碼其實就是前端頁面標簽。經(jīng)過簡單的頁面轉(zhuǎn)義,就能保存為正常的前端頁面鳞上。
????????????? 然后是視頻信息这吻,現(xiàn)在我能夠獲取視頻的video,但是怎么獲取視頻播放的原始url篙议,是一個很頭疼的問題唾糯。這里的分析后面再說。
?????? 剩下的就是可以寫代碼了鬼贱,寫好之后爬取移怯,結(jié)果爬了一會就沒了,總共就爬了245條这难。因此舟误,就需要轉(zhuǎn)方向,爬取頭條號資料雁佳。
(2)ip被封脐帝,反爬。
????????????? 可能是之前嘗試次數(shù)太多了,頭條將我的ip封掉糖权。最后通過買了阿布云代理搁拙,配置好之后和簸,又能夠順利爬取亡电。
(3)爬取頭條號里面的文章和視頻內(nèi)容
進入一個頭條號頁面:
?????? https://www.toutiao.com/c/user/60018788872/#mid=1566905732637697
這個url可以固定髓迎,重點是爬取里面的文章列表和詳情頁。
?????? 現(xiàn)在我們能獲取每一個單頁面文章或視頻的單頁面內(nèi)容,所以爬頭條號資訊的時候腿堤,只需要解決怎么拉取文章列表和翻頁就可以了阀坏。
?????? 首先是看源代碼,里面沒有任何我需要的文章內(nèi)容的信息笆檀,所以可以判斷是通過其他請求獲取到數(shù)據(jù)的忌堂。
經(jīng)過分析可以得知,獲取文章列表鏈接是:
?????? “https://www.toutiao.com/c/user/article/?page_type=1&user_id=%d&max_behot_time=%d&count=20&as=A185BCF242D2906&cp=5C22825930C6AE1&_signature=“
這些信息每一個都是必須的酗洒,user_id和max_behot_time 都是可以通過前面的文章列表獲取士修。最關(guān)鍵的點是as,cp,_signature這三個值是怎么獲取的,暫時沒有找到出處樱衷。
一開始棋嘲,因為不懂前端代碼,沒想過js會對這里產(chǎn)生影響矩桂,經(jīng)過搜索之后沸移,決定采用模擬瀏覽器的方式進行操作,即使用selenium庫進行操作侄榴。通過模擬瀏覽器發(fā)送請求的方式雹锣,網(wǎng)頁源代碼經(jīng)過模擬瀏覽器渲染,可以獲取到標準的前端展示代碼頁面牲蜀,也就可以直接獲取到笆制,同時通過模擬瀏覽器下拉菜單操作方式绅这,獲取更多的資訊涣达。但是通過這個方式操作之后,發(fā)現(xiàn)有幾個弊端:
[if !supportLists](1)?????[endif]下拉請求時經(jīng)常無法更新頁面证薇,并不是每次請求必有回應(yīng)度苔。
[if !supportLists](2)?????[endif]需要獲取數(shù)據(jù)的時候,每次都是從第一頁開始拉取浑度,翻頁就是下拉菜單寇窑,但是在這過程中我并不能保存頁面,所以無法做到實時存儲箩张。
[if !supportLists](3)?????[endif]爬取速度實在慢的可憐甩骏,其他我都忍了,20分鐘才獲取100多條數(shù)據(jù)先慷,這種速度實在不能忍饮笛。
最后決定放棄這種方式,重新回到找url規(guī)律的問題上來论熙。關(guān)鍵點就是as福青,cp,signature 這三個值怎么獲取。通過百度之后无午,可以知道as媒役,cp這些值,我可以在js中找到對應(yīng)的函數(shù)宪迟。
即上圖這酣衷,可以清楚的看到,里面有一個固定的as次泽,cp函數(shù)鸥诽,最開始,我天然的以為as,cp和signature是有某種函數(shù)關(guān)系存在的箕憾,然后又經(jīng)過百度牡借,可以找到那段函數(shù)。經(jīng)過百度搜索和查詢袭异,最后找到簽名函數(shù)是js中的:
Function(function(e) {
??? return'e(e,a,r){(b[e]||(b[e]=t("x,y","x "+e+"y")(r,a)}a(e,a,r){(k[r]||(k[r]=t("x,y","newx[y]("+Array(r+1).join(",x[y]")(1)+")")(e,a)}r(e,a,r){n,t,s={},b=s.d=r?r.d+1:0;for(s["$"+b]=s,t=0;t>>065:h=,y=,[y]=h66:u(e(t[b],,67:y=,d=,u((g=).x===c?r(g.y,y,k):g.apply(d,y68:u(e((g=t[b])<"<"?(b--,f):g+g,,70:u(!1)71:n72:+f73:u(parseInt(f,3675:if(){bcase74:g=<<16>>16g76:u(k[])77:y=,u([y])78:g=,u(a(v,x-=g+1,g79:g=,u(k["$"+g])81:h=,[f]=h82:u([f])83:h=,k[]=h84:!085:void086:u(v[x-1])88:h=,y=,h,y89:u({e{r(e.y,arguments,k)}e.y=f,e.x=c,e})90:null91:h93:h=0:;default:u((g<<16>>16)-16)}}n=this,t=n.Function,s=Object.keys||(e){a={},r=0;for(cin e)a[r]=c;a=r,a},b={},k={};r'.replace(/[--]/g, function(i) {
??????? return e[15 &i.charCodeAt(0)]
??? })
}("v[x++]=v[--x]t.charCodeAt(b++)-32function return
))++.substrvar .length(),b+=;break;case
;break}".split("")))()('gr$Daten Иb/s!l y?y?g,(lfi~ah`{mv,-n|jqewVxp{rvmmx,&eff?kx[!cs"l".Pq%widthl"@q&heightl"vr*getContextx$"2d[!cs#l#,*;?|u.|uc{uq$fontl#vr(fillTextx$$龘???2<[#c}l#2q*shadowBlurl#1q-shadowOffsetXl#$$limeq+shadowColorl#vr#arcx88802[%c}l#vr&strokex[c}l"v,)}eOmyoZB]mx[ cs!0s$l$Pb>>s!0s%yA0s"l"l!r&lengthb&l!l Bd>&+l!l &+l!l 6d>&+l!l&+ s,y=o!o!]/q"13o!l q"10o!],l 2d>&s.{s-yMo!o!]0q"13o!]*Ld>>b|s!o!l q"10o!],l!&s/yIo!o!].q"13o!],o!]*Jd>>b|&o!]+l &+s0l-l!&l-l!i\'1z141z4b/@d
上面這一坨钠龙,到這里,我就絕望了御铃,這鬼才看得懂碴里。
詢問領(lǐng)導(dǎo)之后,測試才發(fā)現(xiàn)上真,這個函數(shù)值跟as咬腋,cp沒有半毛錢關(guān)系,跟user_id,和max_hot_time 有關(guān)系睡互。但是怎么運行成了問題根竿。
????????????? 在這個地方卡了一天半之后,求助領(lǐng)導(dǎo)就珠,領(lǐng)導(dǎo)在發(fā)現(xiàn)完全一樣請求之后寇壳,依然解決不了問題。最后決定妻怎,將這部分代碼拷貝下來壳炎,然后通過node.js在本地調(diào)用運行。最后獲得正確的signture值逼侦。
????????????? 至此匿辩,今日頭條最難處理的部分就解決了。
????????????? 在測試中還發(fā)現(xiàn)榛丢,在翻頁的時候(翻頁是使用json數(shù)據(jù)中铲球,max_hot_time值進行翻頁),失敗率非常高,一個翻頁需要請求多次涕滋。最后成功拿到文章列表睬辐。
?????? 最后一個要解決的問題就是,怎么通過video_id獲取視頻原始鏈接。經(jīng)過百度溯饵,最終找到一個有效的解密方案(如果沒有這個侵俗,我這輩子就解不開。)丰刊。即:
1.打開http://toutiao.com/a6309254755004875010/隘谣,查看網(wǎng)頁源代碼獲取videoid = 0425d8f0c2bb425d9361c0eb2eeb4f16
2.拼接成如下字符串/video/urls/v/1/toutiao/mp4/{videoid}?r={randint}。其中
3. 將第二步拼接的字符串進行crc32校驗(php有crc32函數(shù)),獲取值為十六進制需轉(zhuǎn)化成十進制crc32("/video/urls/v/1/toutiao/mp4/0425d8f0c2bb425d9361c0eb2eeb4f16?r=7937864853677161")= 4040162423
4.
拼接Urlhttp://i.snssdk.com/video/urls/v/1/toutiao/mp4/{videoid}?r={randint}&s={checksum}
5. 訪問拼接Urlhttp://i.snssdk.com/video/urls/v/1/toutiao/mp4/0425d8f0c2bb425d9361c0eb2eeb4f16?r=2330415823304158&s=4218775840其中main_url為視頻地址(需要base64解碼)啄巧。
至此今日頭條所有內(nèi)容都可以爬取到了寻歧。?????
總結(jié)今日頭條反爬策略:
[if !supportLists]1.?????[endif]封ip,這是最常見的秩仆,最后買個代理码泛,省事省心。
[if !supportLists]2.?????[endif]網(wǎng)頁文章鏈接(關(guān)鍵內(nèi)容)澄耍,通過另外的url請求獲取噪珊,同時進行加密處理(as,cp,signture)
[if !supportLists]3.?????[endif]對網(wǎng)頁js函數(shù)進行了加密處理,鬼才看得懂
[if !supportLists]4.?????[endif]視頻通過videoid獲取網(wǎng)頁播放鏈接齐莲,經(jīng)過三次加密處理才能獲取最終url
[if !supportLists]5.?????[endif]翻頁請求高失敗率痢站,顯著降低了爬蟲獲取信息的速度。
總結(jié)爬蟲策略:
[if !supportLists]1.?????[endif]首先找信息列表和下拉方式的url規(guī)律选酗,分析獲取單頁面信息的規(guī)律阵难,有了三個點,所有爬蟲都可以爬了
[if !supportLists]2.?????[endif]如果是大網(wǎng)站芒填,多百度多github呜叫,網(wǎng)友可以提供非常多的好的思路。
[if !supportLists]3.?????[endif]讀懂前端代碼很重要氢烘。