目標(biāo):爬取今日頭條頭條號王者榮耀資訊和視頻。
爬蟲關(guān)鍵點(diǎ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)容,但實(shí)際上獲取文章列表真正鏈接的請求是:
“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ù)。
第二步就是文章列表中,每一個(gè)關(guān)鍵的json數(shù)據(jù)樣式,現(xiàn)在我們通過鏈接可以看到我們獲取到的數(shù)據(jù)央視是這樣的:
看起來很繁雜,仔細(xì)分析之后,可以看到,實(shí)際上是有規(guī)律可以遵循的,重點(diǎn)關(guān)注的是json格式數(shù)據(jù)里面的data的value值,里面是真正的文章信息列表。現(xiàn)在分析清楚之后,可以放下,再進(jìn)行單頁面的分析請求。
經(jīng)過分析可以得到,今日頭條單頁面url鏈接是:
?????? “https://www.toutiao.com/a6645464825897943555/“
很明顯,最后的那一串?dāng)?shù)字是關(guān)鍵,那么,這一串?dāng)?shù)字是從哪里獲取的呢,現(xiàn)在就要回頭看前面的請求列表了,我們拿著“6645464825897943555“這串?dāng)?shù)字,在前面的
文章列表進(jìn)行搜索,輕易的發(fā)現(xiàn),展示這串?dāng)?shù)字的key值就是data里面的“group_id”雖然有點(diǎn)驚訝,但是最終還是拿到了。
現(xiàn)在我們通過搜索獲取文章列表,跳轉(zhuǎn),和翻頁我們都找到了接口。下面的事情就簡單了,獲取單頁面數(shù)據(jù)。當(dāng)我點(diǎn)開網(wǎng)頁源代碼的時(shí)候,發(fā)現(xiàn)里面就有我想要的內(nèi)容。
最后通過xpath或者是正則就可以獲取一個(gè)單頁面文章所需要的內(nèi)容。
? ? ?這個(gè)頁碼有很多亂碼,經(jīng)過百度之后,發(fā)現(xiàn)其實(shí)這些亂碼其實(shí)就是前端頁面標(biāo)簽。經(jīng)過簡單的頁面轉(zhuǎn)義,就能保存為正常的前端頁面。
????????????? 然后是視頻信息,現(xiàn)在我能夠獲取視頻的video,但是怎么獲取視頻播放的原始url,是一個(gè)很頭疼的問題。這里的分析后面再說。
?????? 剩下的就是可以寫代碼了,寫好之后爬取,結(jié)果爬了一會(huì)就沒了,總共就爬了245條。因此,就需要轉(zhuǎn)方向,爬取頭條號資料。
(2)ip被封,反爬。
????????????? 可能是之前嘗試次數(shù)太多了,頭條將我的ip封掉。最后通過買了阿布云代理,配置好之后,又能夠順利爬取。
(3)爬取頭條號里面的文章和視頻內(nèi)容
進(jìn)入一個(gè)頭條號頁面:
?????? https://www.toutiao.com/c/user/60018788872/#mid=1566905732637697
這個(gè)url可以固定,重點(diǎn)是爬取里面的文章列表和詳情頁。
?????? 現(xiàn)在我們能獲取每一個(gè)單頁面文章或視頻的單頁面內(nèi)容,所以爬頭條號資訊的時(shí)候,只需要解決怎么拉取文章列表和翻頁就可以了。
?????? 首先是看源代碼,里面沒有任何我需要的文章內(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=“
這些信息每一個(gè)都是必須的,user_id和max_behot_time 都是可以通過前面的文章列表獲取。最關(guān)鍵的點(diǎn)是as,cp,_signature這三個(gè)值是怎么獲取的,暫時(shí)沒有找到出處。
一開始,因?yàn)椴欢岸舜a,沒想過js會(huì)對這里產(chǎn)生影響,經(jīng)過搜索之后,決定采用模擬瀏覽器的方式進(jìn)行操作,即使用selenium庫進(jìn)行操作。通過模擬瀏覽器發(fā)送請求的方式,網(wǎng)頁源代碼經(jīng)過模擬瀏覽器渲染,可以獲取到標(biāo)準(zhǔn)的前端展示代碼頁面,也就可以直接獲取到,同時(shí)通過模擬瀏覽器下拉菜單操作方式,獲取更多的資訊。但是通過這個(gè)方式操作之后,發(fā)現(xiàn)有幾個(gè)弊端:
[if !supportLists](1)?????[endif]下拉請求時(shí)經(jīng)常無法更新頁面,并不是每次請求必有回應(yīng)。
[if !supportLists](2)?????[endif]需要獲取數(shù)據(jù)的時(shí)候,每次都是從第一頁開始拉取,翻頁就是下拉菜單,但是在這過程中我并不能保存頁面,所以無法做到實(shí)時(shí)存儲(chǔ)。
[if !supportLists](3)?????[endif]爬取速度實(shí)在慢的可憐,其他我都忍了,20分鐘才獲取100多條數(shù)據(jù),這種速度實(shí)在不能忍。
最后決定放棄這種方式,重新回到找url規(guī)律的問題上來。關(guān)鍵點(diǎn)就是as,cp,signature 這三個(gè)值怎么獲取。通過百度之后,可以知道as,cp這些值,我可以在js中找到對應(yīng)的函數(shù)。
即上圖這,可以清楚的看到,里面有一個(gè)固定的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),這個(gè)函數(shù)值跟as,cp沒有半毛錢關(guān)系,跟user_id,和max_hot_time 有關(guān)系。但是怎么運(yùn)行成了問題。
????????????? 在這個(gè)地方卡了一天半之后,求助領(lǐng)導(dǎo),領(lǐng)導(dǎo)在發(fā)現(xiàn)完全一樣請求之后,依然解決不了問題。最后決定,將這部分代碼拷貝下來,然后通過node.js在本地調(diào)用運(yùn)行。最后獲得正確的signture值。
????????????? 至此,今日頭條最難處理的部分就解決了。
????????????? 在測試中還發(fā)現(xiàn),在翻頁的時(shí)候(翻頁是使用json數(shù)據(jù)中,max_hot_time值進(jìn)行翻頁),失敗率非常高,一個(gè)翻頁需要請求多次。最后成功拿到文章列表。
?????? 最后一個(gè)要解決的問題就是,怎么通過video_id獲取視頻原始鏈接。經(jīng)過百度,最終找到一個(gè)有效的解密方案(如果沒有這個(gè),我這輩子就解不開。)。即:
1.打開http://toutiao.com/a6309254755004875010/,查看網(wǎng)頁源代碼獲取videoid = 0425d8f0c2bb425d9361c0eb2eeb4f16
2.拼接成如下字符串/video/urls/v/1/toutiao/mp4/{videoid}?r={randint}。其中
3. 將第二步拼接的字符串進(jìn)行crc32校驗(yàn)(php有crc32函數(shù)),獲取值為十六進(jìn)制需轉(zhuǎn)化成十進(jì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,這是最常見的,最后買個(gè)代理,省事省心。
[if !supportLists]2.?????[endif]網(wǎng)頁文章鏈接(關(guān)鍵內(nèi)容),通過另外的url請求獲取,同時(shí)進(jìn)行加密處理(as,cp,signture)
[if !supportLists]3.?????[endif]對網(wǎng)頁js函數(shù)進(jìn)行了加密處理,鬼才看得懂
[if !supportLists]4.?????[endif]視頻通過videoid獲取網(wǎng)頁播放鏈接,經(jīng)過三次加密處理才能獲取最終url
[if !supportLists]5.?????[endif]翻頁請求高失敗率,顯著降低了爬蟲獲取信息的速度。
總結(jié)爬蟲策略:
[if !supportLists]1.?????[endif]首先找信息列表和下拉方式的url規(guī)律,分析獲取單頁面信息的規(guī)律,有了三個(gè)點(diǎn),所有爬蟲都可以爬了
[if !supportLists]2.?????[endif]如果是大網(wǎng)站,多百度多github,網(wǎng)友可以提供非常多的好的思路。
[if !supportLists]3.?????[endif]讀懂前端代碼很重要。