node 爬蟲(chóng)今日頭條

第一個(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)行就能獲取到。

今日頭條as,cp 獲取測(cè)試代碼

第八個(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)中,有嘗試使用 crawlerpuppeteer
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é)果,更純粹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,055評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,365評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,561評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,346評(píng)論 6 404
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,889評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評(píng)論 3 439
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,118評(píng)論 0 286
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,637評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,558評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,739評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,980評(píng)論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,362評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,619評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,347評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,702評(píng)論 2 370

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