從高可用IP代理池到千萬級(jí)網(wǎng)易云音樂數(shù)據(jù)爬取的實(shí)現(xiàn)

博客引流

首先 祝?大家 1024 快樂

之前寫了第一版 網(wǎng)易云爬蟲

邏輯比較簡單

總結(jié)一下耗绿,就是:

  1. 抓取各分類下歌單id
  2. 根據(jù)歌單id, 獲得這個(gè)歌單id下的歌曲詳情
  3. 把拿到的數(shù)據(jù)存到落到本地文件留攒,最后利用shell腳本進(jìn)行數(shù)據(jù)統(tǒng)計(jì)
  4. 為了提高效率采用多線程
  • 這版線程數(shù)開的有點(diǎn)多稍途,建議在docker環(huán)境中啟樊破,否則你的電腦就不屬于你了

先 放代碼 傳送門

整體架構(gòu)圖

image

Trouble

第一版 爬蟲 看起來沒什么毛病

但 還是會(huì)有一些問題

  1. 你可能會(huì)有疑問 這么大的一個(gè)公司 怎么沒有反爬策略
  • 怎么可以讓我這么肆無忌憚的爬
  • 這可是線上服務(wù) 一個(gè)個(gè)請求都是壓力
  1. 落磁盤落在文件里,雖然處理數(shù)據(jù)也很方便,但數(shù)據(jù)的關(guān)系不夠明顯
  • 這個(gè)看起來很簡單 就是落數(shù)據(jù)庫

Netease Anti-Spider

第一個(gè)問題 其實(shí) 你在分析數(shù)據(jù)的時(shí)候就會(huì)發(fā)現(xiàn)一些端疑

為啥一個(gè)那么火的歌單只有一首歌?

實(shí)際上這是網(wǎng)易云音樂的一個(gè)防爬機(jī)制

在短時(shí)間請求比較大的時(shí)候會(huì)觸發(fā)

在我嘗試過程中 基本上在請求 8k-1w次的時(shí)候會(huì)發(fā)現(xiàn)

按每次請求200ms計(jì)算,開18個(gè)線程 一秒請求100次

QPS就達(dá)到6k

如果我多開幾個(gè)爬蟲 那么就會(huì)網(wǎng)易云的監(jiān)控就會(huì)很可怕

要知道PDD一般服務(wù)的QPS也就幾十萬

所以 為了防我們這種新手

網(wǎng)易云造了一些200的Response油猫,基本數(shù)據(jù)也是一致的

只是數(shù)據(jù)量 會(huì)少一點(diǎn)

比如說一個(gè)歌單只返回一首歌的信息(劃重點(diǎn) 這是我們接下來 驗(yàn)證IP是否可用的一個(gè)有效判據(jù))

問題找到了,那么改如何解決:

一種辦法 就是 換物理IP

用人話說 就是 你在大興 爬爬 然后 跑到本部去爬

嗯 LZ 在最開始也干過這種事情

導(dǎo)致很多物理IP 現(xiàn)在可能也不能用 hhh

當(dāng)然根本的解決策略就是建立代理IP池

Proxy 代理池

  • 首先 什么是代理柠偶?

代理就是 有一個(gè)服務(wù)器代替你做 你想做的事情

代理IP做的事情 就是 把你原本自己發(fā)出去的請求 借助代理服務(wù)器的?發(fā)出去

保密做的好的 就叫高匿

一般用的ShadowSockets 就是一種Socket5代理

我們這里要用的則是Http情妖,Https代理

尤其更需要Http的代理

Xici

xici代理 是我爬的第一個(gè)Free Proxy 網(wǎng)站

當(dāng)時(shí)爬了20頁只找到 7個(gè)能用的

然后隨機(jī)選取一個(gè)作為代理

想的挺好的 這次應(yīng)該不會(huì)被封了吧

結(jié)果 快到3w歌單的時(shí)候 pia 機(jī) 沒了

所以 痛定思痛 覺得建立一個(gè)Proxy 代理池 而且要是高可用的

以上就是V1.5版

雖然沒有多少代理IP 但借助著精湛的 轉(zhuǎn)移技術(shù)
還是爬取了總計(jì)10.2w歌單12780274首,去重后1099542

怕大家數(shù)不清楚 以上 = 1.2kw/ 110w

但拿到數(shù)據(jù)只是第一步 基于這些數(shù)據(jù)可以做很多事情

我們看 得到的數(shù)據(jù)大概4M*73 = 296M

如果數(shù)據(jù)量達(dá)到GB級(jí)別 shell就不太適用 就可以用MapReduce進(jìn)行處理诱担,此處參考寫的另外一篇blog

Goubanjia

在爬代理網(wǎng)站 建立代理池的過程中毡证,發(fā)現(xiàn)一些很好玩的事情

比如說這個(gè)代理網(wǎng)站 Goubanjia

做最基本的html解析,可以得到下面的內(nèi)容

In [9]: html = a.get_html('http://www.goubanjia.com', {}, 'www.goubanjia.com')

In [10]: trs = html.find_all('tr', class_=['warning', 'success'])

In [11]: tds = trs[0].find_all('td')

In [12]: tds[0].find_all(['div', 'span', 'p'])
Out[12]:
[<p style="display: none;">4</p>,
 <span>4</span>,
 <div style="display:inline-block;">7.</div>,
 <span style="display: inline-block;"></span>,
 <div style="display:inline-block;">9</div>,
 <p style="display: none;">3</p>,
 <span>3</span>,
 <div style="display: inline-block;"></div>,
 <p style="display: none;">.2</p>,
 <span>.2</span>,
 <span style="display:inline-block;">5</span>,
 <p style="display: none;">1.</p>,
 <span>1.</span>,
 <span style="display:inline-block;">9</span>,
 <p style="display:none;"></p>,
 <span></span>,
 <div style="display: inline-block;">4</div>,
 <span class="port GEA">8174</span>]

好像沒什么異常 就是把Ip分開來了 拼接一下不就行了

447.933.251.1.94:8174

好像 這不太像一個(gè)IP地址

實(shí)際上懂一點(diǎn) Html知識(shí)的可能會(huì)發(fā)現(xiàn)style="display:none;"

這個(gè)一個(gè)隱藏的style實(shí)際上是不顯示的意思

發(fā)現(xiàn)這點(diǎn)之后 好像就很簡單了

tds[0].find_all(['div', 'span', not 'p'], class_=not 'port')

但 這只是這個(gè)網(wǎng)站兩年前做的版本 好戲還在后頭

我把得到的ip進(jìn)行測試 然后一驚

woc 費(fèi)那么大勁 一個(gè)都不能用 一個(gè)都不能用 干嘛還這么用力來防

總覺得有蔫仙、不太對(duì)

然后突然發(fā)現(xiàn) 拿到的Port 和網(wǎng)站上看到的 好像不太一樣

image

這個(gè)時(shí)候想到 上課講的wolf字體欺騙

檢查字體發(fā)現(xiàn)再正常不過了

再回頭來看這個(gè)代碼<span class="port GEA">8174</span>

一開始懷疑對(duì)象 也是CSS 這個(gè)class會(huì)不會(huì)有什么特殊的地方

想了半天 也排查了所以css js

發(fā)現(xiàn)如果把http://www.goubanjia.com/theme/goubanjia/javascript/pde.js?v=1.0禁掉 就會(huì)顯示Html的內(nèi)容

有同學(xué)說看js代碼 實(shí)際上 看不出來什么東西

再看引了JQuery的包 猜想應(yīng)該是JQuery動(dòng)態(tài)修改Html

但知道 這個(gè)并沒有用 并不能幫助我們解密

這就是一個(gè)encode decode的過程

image

好像 port后面的字母和端口號(hào)有一一映射關(guān)系

那么 我們 進(jìn)入到最原始的方式:通過枚舉 找規(guī)律

image

然后我們就會(huì) 變得很機(jī)智 發(fā)現(xiàn)這個(gè)密碼就是把字母轉(zhuǎn)化成數(shù)字 然后/8

嗯 這應(yīng)該是 第一個(gè)解密goubanjie騷操作的blog

然后 我們發(fā)現(xiàn)這個(gè)網(wǎng)站更新很頻繁 但一次只能拿到20條

于是 寫個(gè)定時(shí)任務(wù) 就是一個(gè)很合理的需求

gatherproxy

其實(shí)國內(nèi)代理 都太勢利了 能用的本來就不多 還收費(fèi)

國外的代理 就很慷慨

比如說gatherproxy 這也是我們的主力代理Ip

和別的不一樣 這個(gè)網(wǎng)站吧所有ip都開放給你下載 不提倡寫爬蟲

那么問題就變?yōu)?如何在較短時(shí)間內(nèi)把1w+ 對(duì)應(yīng)的http/https 代理是否可用檢驗(yàn)出來 然后寫到DB中

想要快 只能 開多線程

但寫庫不能在多線程中

我們知道Innodb因?yàn)橘Y瓷事務(wù) 有嚴(yán)格的寫鎖機(jī)制

短時(shí)間 競爭寫操作 會(huì)造成 寫失敗操作

于是第一套方案 就是等所有 判斷結(jié)束之后 再寫

測試發(fā)現(xiàn) 寫效率 挺高的 1s內(nèi)完成1k條Insert語句

但實(shí)際上頻繁的寫操作不太友好

所以改成聚類 通過一次sql操作 完成1k條數(shù)據(jù)的插入

這樣就解決了慢SQL的問題

TestDb()

當(dāng)然 代理具有極強(qiáng)的時(shí)效性

如何在短時(shí)間內(nèi)判斷數(shù)據(jù)庫中大量的代理數(shù)據(jù)是否可用(目前為止已經(jīng)有2.2w代理ip數(shù)據(jù)) 也是一個(gè)問題

解決方案 同樣是 多線程

但同時(shí)為了保證代理Ip的質(zhì)量 采用3次驗(yàn)證機(jī)制

通過is_failured字段 進(jìn)行判斷 每失效一次+1 直到is_failured到5則不在檢測

如果可用一次is_failured置為0

不可靠

實(shí)際上就算之前的三層檢驗(yàn) 拿到的可用的代理

在實(shí)際運(yùn)用當(dāng)中 還是會(huì)出現(xiàn)請求失敗的現(xiàn)象

所以 對(duì)于真實(shí)爬取場景 為保證每一個(gè)數(shù)據(jù)的都能被爬取到

對(duì)每個(gè)任務(wù)增加Retry機(jī)制 并記錄爬取進(jìn)度 To DB

然后 其實(shí)Proxy特別依賴network

比如說 有一次連上了 隔壁寢室的WiFi別問我怎么連上的 密碼真的簡單

然后經(jīng)過testdb之后可用的 Ip數(shù)就掉零

然后 實(shí)驗(yàn)證明 Https的代理 比較不穩(wěn)定 十分需要retry機(jī)制

對(duì)于本次爬蟲而言 實(shí)際上Https的接口沒有加 反爬機(jī)制 不用代理也行

DB

DB 采用MySQL

一個(gè)是 因?yàn)槭煜?/p>

另外一個(gè)可用方便顯示數(shù)據(jù)的關(guān)系

但實(shí)際上大數(shù)據(jù)下MySQL的性能優(yōu)化 有很多功課可以做

慢SQL

前面說的 讀寫IP池 是一種慢SQL

實(shí)際上 寫 playlist_queue表也是

我們一次拿到1k+個(gè)歌單Id 需要在短時(shí)間 進(jìn)行判斷寫入/更新進(jìn)DB

我們可以用Replace Into 代替Update進(jìn)行更新

所有操作做聚類 一條SQL 代替數(shù)k條SQL

但在playlist_detail這張表中

首先 單條數(shù)據(jù)Size大

其次 需要一次插入七八萬條數(shù)據(jù) 這已經(jīng)是聚類過的 單classify進(jìn)行統(tǒng)計(jì)處理

這 Insert 也不管用

測試中 6w數(shù)據(jù)

分成5k一組 一條也寫不進(jìn)去
3k一組 能寫三條
1k一組 能寫10條
500一組 中間休息0.2s 能寫20組

仔細(xì)看一下 發(fā)現(xiàn)block大小 和 能寫入的量 直接 并沒有直接關(guān)系

該寫不進(jìn)去的 照樣寫不進(jìn)去

最后 采用先寫到本地文件中

再通過Load data 導(dǎo)入MySQL

那 我們 為啥 還要寫庫 二進(jìn)制文件不是挺好的嗎 shell腳本多少好用

image

Finish

于是第二版 主要解決了以上技術(shù)難題

剩下還有一些零零散散的小問題 主要是多線程 一些寫料睛、更新比較繁瑣的地方

總的來說 實(shí)現(xiàn)

  1. 高可用代理IP庫建立
  2. 資瓷記錄爬蟲進(jìn)度的自動(dòng)化網(wǎng)易云音樂歌單數(shù)據(jù)爬蟲
  3. 完成6百w(5801119)數(shù)據(jù)爬取,寫庫操作
image
image

Next

  1. 通過Kafka消費(fèi)消息隊(duì)列 來解決 寫庫量大的問題
  2. 數(shù)據(jù)分析 挖頻繁模式
  3. 只爬了playlist的數(shù)據(jù) 其實(shí)網(wǎng)易云還有很多可以做的 比如說用戶畫像 評(píng)論之類很有意思的方向

Result

附上出現(xiàn)頻次排名前55的歌曲

至于為什么是前55 e

-- 數(shù)據(jù)采樣于2018.10.23 --

前1k名單見GitHub

time song_name
----|-----
6784 Something Just Like This
5814 Shape of You
5720 Time
5585 Alone
5151 Intro
4916 Hello
4833 You
4787 Closer
4312 Nevada
4217 Stay
4142 Faded
4089 說散就散
4070 Animals
3894 往后余生
3650 Home
3645 Without You
3535 Counting Stars
3515 That Girl
3410 HandClap
3300 Higher
3265 Despacito (Remix)
3229 Unity
3198 Havana
3181 起風(fēng)了(Cover 高橋優(yōu))
3148 Forever
3141 Victory
3108 Please Don't Go
3101 Sugar
3080 Beautiful Now
3077 See You Again
3022 Fade
2969 Summer
2940 Seve
2938 The truth that you leave
2861 Life
2853 可能否
2825 We Don't Talk Anymore
2799 Superstar
2795 #Lov3 #Ng?u H?ng
2793 Try
2759 アイロニ
2730 Hope
2714 Hero
2705 追光者
2679 遇見
2678 いつも何度でも
2654 Let Me Love You
2646 There For You
2643 Trip
2634 BOOM
2626 Fire
2606 Wolves
2600 Friendships (Original Mix)
2597 Freaks (Radio Edit)
2577 全部都是你
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市恤煞,隨后出現(xiàn)的幾起案子屎勘,更是在濱河造成了極大的恐慌,老刑警劉巖居扒,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件概漱,死亡現(xiàn)場離奇詭異,居然都是意外死亡喜喂,警方通過查閱死者的電腦和手機(jī)瓤摧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來玉吁,“玉大人照弥,你說我怎么就攤上這事〗保” “怎么了这揣?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長敢会。 經(jīng)常有香客問我曾沈,道長这嚣,這世上最難降的妖魔是什么鸥昏? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮姐帚,結(jié)果婚禮上吏垮,老公的妹妹穿的比我還像新娘。我一直安慰自己罐旗,他們只是感情好膳汪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著九秀,像睡著了一般遗嗽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鼓蜒,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天痹换,我揣著相機(jī)與錄音,去河邊找鬼都弹。 笑死娇豫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的畅厢。 我是一名探鬼主播冯痢,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了浦楣?” 一聲冷哼從身側(cè)響起袖肥,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎椒振,沒想到半個(gè)月后昭伸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡澎迎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年庐杨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夹供。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡灵份,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哮洽,到底是詐尸還是另有隱情填渠,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布鸟辅,位于F島的核電站氛什,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏匪凉。R本人自食惡果不足惜枪眉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望再层。 院中可真熱鬧贸铜,春花似錦、人聲如沸聂受。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛋济。三九已至棍鳖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碗旅,已是汗流浹背渡处。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扛芽,地道東北人骂蓖。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像川尖,于是被迫代替她去往敵國和親登下。 傳聞我的和親對(duì)象是個(gè)殘疾皇子茫孔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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

  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 31,928評(píng)論 2 89
  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料被芳? 從這篇文章中你...
    hw1212閱讀 12,712評(píng)論 2 59
  • 有時(shí)候缰贝,我在想,人活在世上畔濒,是為了什么? 那人又是如何誕生的呢剩晴? 如果按照中國神話故事里,盤古開天辟地之后侵状,女媧為...
    UpSst閱讀 781評(píng)論 0 0
  • 公眾號(hào)開篇(前言)/老Wu波秀場 六一隨想:《童心》 我每每慶幸赞弥,我有一顆童心, 這其實(shí)是一直以來我的一個(gè)決心趣兄; ...
    老Wu波閱讀 292評(píng)論 2 2
  • 去年夏天還沒過完 外婆就去世了 有時(shí)候在路邊看見佝僂的老人 總會(huì)想起她 可讓我自己都害怕的是 我竟然有時(shí)候會(huì)想不起...
    阿李阿佳閱讀 256評(píng)論 0 0