第一個(gè)參數(shù):min_behot_time
以下為今日第一個(gè)參數(shù)的頭條代碼
"refresh" === t ? (i = this.list.length > 0 ? this.list[0].behot_time : 0,
this.url += "min_behot_time=" + i) : (i = this.list.length > 0 ? this.list[this.list.length - 1].behot_time : 0,
this.url += "max_behot_time=" + i);
代碼整理后邏輯如下
// t = 'refresh'; // 刷新頁(yè)面時(shí)載第一頁(yè) t的值
// t = 'loadmore'; // 下拉加載下一頁(yè) t 的值
// this.list = [] // 刷新頁(yè)面時(shí)載第一頁(yè) this.list 的值
// this.list = [{...},{...},...] // 下拉加載下一頁(yè) this.list 的值,里面有16 個(gè)元素
var i = 0;
if (t == 'refresh') {
// this.list = [];
if (this.list.length > 0) {
i = this.list[0].behot_time
} else {
i = 0,this.url += "min_behot_time=" + i
// this.url = /api/pc/feed/?min_behot_time=0
}
}
if (t == 'loadmore') {
if (this.list.length > 0) {
// this.list.length = 16
i = this.list[this.list.length - 1].behot_time;
// /api/pc/feed/?max_behot_time=1548149528
} else {
i = 0,this.url += "max_behot_time=" + i;
}
}
邏輯看起來(lái)是取返回的數(shù)據(jù)中,behot_time 字段的值。 this.list 為所有的新聞數(shù)據(jù)數(shù)組,每加載一頁(yè)就會(huì)往這個(gè)數(shù)組中push.
所以,加載第一頁(yè),min_behot_time=0 ; 加載下一頁(yè),max_behot_time = this.list[this.list.length - 1].behot_time; 返回?cái)?shù)據(jù)中的最后一條,behot_time 的值。
先前猜測(cè)這個(gè)值是直接取的時(shí)間戳,調(diào)試驗(yàn)證后才知道真相,實(shí)踐出真理。
第二個(gè)參數(shù):category: all
看這個(gè)單詞很好猜測(cè),分類(lèi)的意思,加載下一頁(yè)時(shí)沒(méi)有變動(dòng),所以不用修改,可直接使用。
第三個(gè)參數(shù):utm_source: toutiao
看起來(lái)像來(lái)源,toutiao(頭條)? 加載下一頁(yè)時(shí)沒(méi)有變動(dòng),所以不用修改,可直接使用。
第四個(gè)參數(shù):widen: 1
加載下一頁(yè)時(shí)沒(méi)有變動(dòng),所以不用修改,可直接使用。
第五個(gè)參數(shù):tadrequire: false
在調(diào)試期間,有時(shí)候?yàn)閒alse, 有時(shí)候?yàn)閠rue. 影響不是很大,先不做處理,直接用true 或者false.
第六、七個(gè)參數(shù) as、cp
這個(gè)比較特殊
as: A1057CA4A68E6CC
cp: 5C469E465C4CAE1
可以將js直接提取出來(lái),然后運(yùn)行就能獲取到。
第八個(gè)參數(shù):_signature:
這個(gè)參數(shù)看起來(lái)有點(diǎn)故事。調(diào)試看看。
var n = (0, g.sign)(i + "");
(0, a.default)(this.params, {
as: e.as,
cp: e.cp,
_signature: n
})
由上代碼可以看出_signature: n; 而 n 是 使用 i 處理后生成的。g.sign 做了什么生出了 n ???
_signature:
經(jīng)過(guò)調(diào)試到這..... _signature的值就來(lái)自這些字符串,沒(méi)有思路了,打算采用其他方式爬蟲(chóng)。并考慮到這些字符串可能來(lái)自后端生成,然后在進(jìn)行加密的,如果今日頭條不斷的進(jìn)行更新,就會(huì)導(dǎo)致今天也許爬蟲(chóng)成功了,過(guò)一段時(shí)間就不行了。搜索了下,發(fā)現(xiàn)有很多這種情況。
Function(function(t) {
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","?new x[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<b;t?)s[n="$"+t]=r[n];for(t=0,b=s?=a?;t<b;t?)s[t]=a[t];?c(e,0,s)}?c(t,b,k){?u(e){v[x?]=e}?f?{?g=?,t?ing(b?g)}?l?{try{y=c(t,b,k)}catch(e){h=e,y=l}}for(?h,y,d,g,v=[],x=0;;)switch(g=?){case 1:u(!?)?4:?f??5:u(?(e){?a=0,r=e?;???{?c=a<r;?c&&u(e[a?]),c}}(???6:y=?,u(?(y??8:if(g=?,l??g,g=?,y===c)b+=g;else if(y!==l)?y?9:?c?10:u(s(???11:y=?,u(?+y)?12:for(y=f?,d=[],g=0;g<y?;g?)d[g]=y.charCodeAt(g)^g+y?;u(String.fromCharCode.apply(null,d??13:y=?,h=delete ?[y]?14:???59:u((g=?)?(y=x,v.slice(x-=g,y?:[])?61:u(?[?])?62:g=?,k[0]=65599*k[0]+k[1].charCodeAt(g)>>>0?65:h=?,y=?,?[y]=h?66:u(e(t[b?],?,???67:y=?,d=?,u((g=?).x===c?r(g.y,y,k):g.apply(d,y??68:u(e((g=t[b?])<"<"?(b--,f?):g+g,?,???70:u(!1)?71:?n?72:?+f??73:u(parseInt(f?,36??75:if(?){b??case 74:g=?<<16>>16?g?76:u(k[?])?77:y=?,u(?[y])?78:g=?,u(a(v,x-=g+1,g??79:g=?,u(k["$"+g])?81:h=?,?[f?]=h?82:u(?[f?])?83:h=?,k[?]=h?84:?!0?85:?void 0?86:u(v[x-1])?88:h=?,y=?,?h,?y?89:u(??{?e?{?r(e.y,arguments,k)}?e.y=f?,e.x=c,e}?)?90:?null?91:?h?93:h=??0:??;default:u((g<<16>>16)-16)}}?n=this,t=n.Function,s=Object.keys||?(e){?a={},r=0;for(?c in e)a[r?]=c;?a?=r,a},b={},k={};?r'.replace(/[?-?]/g, function(e) {
return t[15 & e.charCodeAt(0)]
})
}("v[x++]=?v[--x]?t.charCodeAt(b++)-32?function ?return ?))?++?.substr?var ?.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<k7l l!r&lengthb%^l$1+s$j?l s#i$1ek1s$gr#tack4)zgr#tac$! +0o![#cj?o ]!l$b%s"o ]!l"l$b*b^0d#>>>s!0s%yA0s"l"l!r&lengthb<k+l"^l"1+s"j?l s&l&z0l!$ +["cs\'(0l#i\'1ps9wxb&s() &{s)/s(gr&Stringr,fromCharCodes)0s*yWl ._b&s o!])l l Jb<k$.aj;l .Tb<k$.gj/l .^b<k&i"-4j!?+& s+yPo!]+s!l!l Hd>&l!l Bd>&+l!l <d>&+l!l 6d>&+l!l &+ s,y=o!o!]/q"13o!l q"10o!],l 2d>& s.{s-yMo!o!]0q"13o!]*Ld<l 4d#>>>b|s!o!l q"10o!],l!& s/yIo!o!].q"13o!],o!]*Jd<l 6d#>>>b|&o!]+l &+ s0l-l!&l-l!i\'1z141z4b/@d<l"b|&+l-l(l!b^&+l-l&zl\'g,)gk}ejo{?cm,)|yn~Lij~em["cl$b%@d<l&zl\'l $ +["cl$b%b|&+l-l%8d<@b|l!b^&+ q$sign ', [Object.defineProperty(e, "__esModule", {
value: !0
})])
最終解決方案
使用 puppeteer
進(jìn)行爬蟲(chóng),高級(jí)解決方案,可爬取任何網(wǎng)站,不管這個(gè)網(wǎng)站如何加密,只要能訪問(wèn)這個(gè)網(wǎng)站,就能爬取。
直接上代碼: 爬取今日頭條首頁(yè)新聞,滾動(dòng)加載5 頁(yè)數(shù)據(jù),并將數(shù)據(jù)轉(zhuǎn)為json,寫(xiě)入到j(luò)son文件。
const puppeteer = require('puppeteer');
const fs = require('fs');
let news = [];
(async() => {
var pageN = 1;
var sleep = function(time) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, time);
})
};
const browser = await puppeteer.launch();
// const browser = await browser1.createIncognitoBrowserContext();
const page = await browser.newPage();
page.on('response', res => {
let mathStr = res._url.indexOf('www.toutiao.com/api/pc/feed/');
if (mathStr > -1) {
console.log(res._url);
res.json().then(json => {
let data = json.data;
data.forEach(v => {
news.push(v);
})
})
}
})
await page.goto('https://www.toutiao.com/');
console.log('document loaded success');
await sleep(3000);
await page.evaluate(_ => {
window.scrollBy(0, document.body.scrollHeight);
});
console.log('1 one page loaded success' + new Date());
await sleep(3000);
await page.evaluate(_ => {
window.scrollBy(0, document.body.scrollHeight);
});
console.log('2 one page loaded success' + new Date());
await sleep(3000);
await page.evaluate(_ => {
window.scrollBy(0, document.body.scrollHeight);
});
console.log('3 one page loaded success' + new Date());
await sleep(3000);
await page.evaluate(_ => {
window.scrollBy(0, document.body.scrollHeight);
});
console.log('4 one page loaded success' + new Date());
await sleep(3000);
await page.evaluate(_ => {
window.scrollBy(0, document.body.scrollHeight);
});
console.log('5 one page loaded success' + new Date());
await sleep(3000);
let fileDate = new Date();
let fileName = 'news'+fileDate.getFullYear()+fileDate.getDate();
objToJsonFile(news, fileName);
await browser.close();
console.log(' browser close success');
})();
function objToJsonFile(obj, fileName) {
fs.open(__dirname + '/' + fileName + '.json', 'w', (err, fd) => {
if (err) {
throw err;
}
let jsonStr = JSON.stringify(obj);
fs.write(fd, jsonStr, (err, written) => {
if (err) {
throw err;
}
})
fs.close(fd);
});
}
總結(jié)
閑話(huà):這次的爬蟲(chóng),陸陸續(xù)續(xù)的調(diào)試了很多次,也花了很多時(shí)間,都是在業(yè)余時(shí)間進(jìn)行開(kāi)發(fā)和調(diào)試,時(shí)間斷斷續(xù)續(xù)就會(huì)導(dǎo)致思路也是斷斷續(xù)續(xù)的,有時(shí)候來(lái)剛來(lái)了點(diǎn)靈感,但又需要去做其他事。但不斷的嘗試,嘗試,還是算給出了解決方案,雖然不是很完美,但只要堅(jiān)持下去,總會(huì)有結(jié)果,嗯嗯。
1 這次的爬蟲(chóng)中,有嘗試使用 crawler
和 puppeteer
。
crawler 優(yōu)點(diǎn):輕量級(jí),速度快。
crawler 缺點(diǎn):一次只對(duì)單個(gè)鏈接進(jìn)行爬取,無(wú)法模擬瀏覽器操作。
puppeteer 優(yōu)點(diǎn):可模擬瀏覽器操作,可以爬取單頁(yè)應(yīng)用,可直接運(yùn)行瀏覽器中js代碼,只要瀏覽器可以的操作,使用puppeteer 都可以進(jìn)行模擬。
puppeteer 缺點(diǎn):太笨重,每一次運(yùn)行都需要加載一次chrome 內(nèi)核,速度慢,內(nèi)存占用高。
crawler官方網(wǎng)站
puppeteer官方網(wǎng)站
2 這次爬蟲(chóng)的目的是想實(shí)現(xiàn)一個(gè)私人定制的今日頭條,而不是今日頭條按照個(gè)人興趣進(jìn)行AI推薦的內(nèi)容。(有段時(shí)間有類(lèi)似上癮的感覺(jué),每次今日頭條都很能抓住我的興趣,導(dǎo)致每天都會(huì)花很多時(shí)間去刷今日頭條,但這樣真的好嗎,這樣是否會(huì)導(dǎo)致每個(gè)人的興趣都固定在同一個(gè)圈內(nèi),而我要的是各個(gè)行業(yè)的新聞,興趣應(yīng)該是廣泛的,我想看的是大家的想法、也許我就是烏合之眾吧!!!個(gè)人的想法)
這次有嘗試爬取當(dāng)天的新聞,也成功爬取了一天中的新聞,并進(jìn)行了分析,按照之前的想法去構(gòu)建一個(gè)私人定制的今日頭條。但按照思路進(jìn)行了處理,處理后發(fā)現(xiàn)結(jié)果并不是想象中結(jié)果。
爬取了14頁(yè)左右的今日頭條,并按照個(gè)人想法進(jìn)行過(guò)濾(按照評(píng)論數(shù)進(jìn)行排序,按照關(guān)鍵詞標(biāo)簽排除了娛樂(lè)新聞、美食、汽車(chē)、視頻、家居、美文、育兒、健康,這些都不是我想關(guān)注。)。
爬取2019/01/31今日頭條內(nèi)容展示地址:http://www.apago.top/example/spiderjrty/test.html
3 處理后發(fā)現(xiàn)結(jié)果并不是想象中結(jié)果,原因大概是,點(diǎn)擊爬取中各條新聞就會(huì)發(fā)現(xiàn),今日頭條首頁(yè)中的新聞并不都是按照最新的時(shí)間進(jìn)行排序的,有些還是好幾天前的新聞。也就是說(shuō)首頁(yè)中展示的新聞,都是由小編
推薦的新聞, 而我想看的只是今天或者昨天的新聞,目的是每天都只關(guān)注最近的新聞,并達(dá)到如果每天都看新聞的話(huà),你會(huì)不漏掉所有的新聞,所有的熱點(diǎn),且不會(huì)看到重復(fù)的新聞。
4 考慮解決方案,這樣爬蟲(chóng)下來(lái),并不能達(dá)到我想要的目標(biāo)和結(jié)果。
如果考慮只想關(guān)注特定的新聞,例如國(guó)內(nèi)政治新聞,最好還是去爬取人民網(wǎng)什么的,還沒(méi)去了解,搜索下政治新聞排行網(wǎng)站什么就能得到排行。按照這個(gè)思路去爬蟲(chóng),數(shù)據(jù)會(huì)更接近想要的結(jié)果,更純粹。