【個人】爬蟲實踐,利用xpath方式爬取數據之爬取蝦米音樂排行榜


實驗網站:蝦米音樂排行榜
網站地址: http://www.xiami.com/chart 
難度系數:★☆☆☆☆
依賴庫:request、lxml的etree (安裝lxml:pip install lxml)
IDEA開發工具:PyCharm_2017.3
Python版本:Python3
期望結果:爬取出排行版歌名以及對應歌手

運行效果圖:
音樂排行榜:
 
爬取數據結果圖:

    像這種簡單的爬取就沒必要使用Scrapy框架進行處理,是在有點大材小用,不過如果你剛開始學Scrapy的話,拿這些簡單的練手是必須的,從簡單的開始,慢慢去熟悉、掌握Scrapy框架。用BeautifulSoup也可以,簡單實用,尤其元素選擇器方面和Jquery很類似,上手比較快,但是最近我還是感覺XPath比較好用,所以今天就用XPath方式對數據進行提取吧。不過為了分享更多內容,讓初學者少踩坑,快進步,我打算把這個實驗再用Scrapy實現一遍,對於老鳥來說這實在沒多大意義,但是對於初學者來說卻能更好的理清思路,少走彎路。
    這篇入門教程和未來Scrapy爬取蝦米音樂排行榜的教程我都會以最簡單直白的方式進行說明,基本從第一句代碼開始寫起,期間對遇到的問題進行分析、解決、對代碼逐步完善,同時輔之更清晰明了的截圖,讓各位初學者更直觀的看到代碼逐步完善的過程,更好的理清思路。
 
    首先用瀏覽器(推薦Chrome內核的瀏覽器,例如谷歌Chrome瀏覽器,Cent百分瀏覽器,此處用的Cent瀏覽器,感覺比Chrome更好用)打開網站  http://www.xiami.com/chart  ,基本就是我們看到的這樣:
 
 
    我們此時先試着寫簡單的代碼,我們一步一步處理,遇到問題去解決:
import requests
from lxml import etree

url_ = "http://www.xiami.com/chart"
page_source = requests.get(url=url_)
print("響應結果:\n",page_source.text)
model = etree.HTML(page_source.text)
 
    以上代碼就是最簡單的獲取網頁源碼的方式,我們運行發現好像沒有達到我們的預期結果:
 
    出現了400錯誤,什么問題呢?下面藍色區域畫出來的部分已經很明確的說明了,因為我們瀏覽器發送的請求服務端無法識別,仔細一想瀏覽器打開這個網址正常,而我們通過代碼則不行,很明顯就是Use-Agent(UA)不匹配了,找到問題原因就好辦了,我們可以模擬一個UA,例如:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87,接着我們修改一下代碼:
 
 1 import requests
 2 
 3 from lxml import etree
 4 
 5 
 6 url_ = "http://www.xiami.com/chart"
 7 
 8 headers_ = {
 9 
10     'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87'
11 
12 }
13 
14 page_source = requests.get(url=url_,headers=headers_)
15 
16 print("響應結果:\n",page_source.text)
17 
18 model = etree.HTML(page_source.text)
 
    可以看到此時網站已經正確響應了,我們拿到了我們的“理想數據“,但仔細看了看響應的數據,然后搜索了一下,發現好像沒有看到某首歌曲
的信息,也就是說目前返回的數據並不包含歌曲排行榜數據:
 
    我明明是打開的這個  http://www.xiami.com/chart 網址啊,而且用瀏覽器打開后也加載出音樂排行榜的歌曲了啊,為什么返回的網頁源碼中找不到歌曲信息呢?不知道你發現沒有,當瀏覽器打開這個網址時,頁面中間區域排行榜數據處於一個正在加載中狀態,並不是一下子整個頁面出來的(你網速好可以忽略了...)
    就類似於上圖這樣,一部分頁面出來了而一部分還未加載完成,這時候你是不是就想到了Ajax異步加載了?這就對了,這塊數據是Ajax后期加載出來的,是有一個新請求的,直接通過代碼獲取網頁源碼肯定不會得到期望結果的,我們應該想辦法知道Ajax通過什么方式請求了哪個地址以及得到了什么類型的結果,於是乎瀏覽器的開發者工具就派上用場了:
    我們可以看到當我們打開這個頁面時都進行了右側的請求響應處理,我們響應的Ajax請求肯定就在其中了,我們可以慢慢找,不過我們知道是Ajax請求了,那我們直接過濾“XHR”:
    進過過濾我們發現就這一個請求,然后看了一下Response,最后確認就是它了!!
    歌曲就在其中了,於是我們確定這就是我們最終要請求的URL了,然后我們再看一下該請求的相關信息:
    於是我們知道了URL是: http://www.xiami.com/chart/data?c=103&type=0&page=1&limit=100&_=1517477892257  請求方式是:GET方式 等信息,那我們就接着修改代碼吧:
    (URL的請求參數,比如page、limit等我們就不細究了,一看就知道當前頁碼和每頁返回數據大小)
 
import requests
from lxml import etree

url_ = "http://www.xiami.com/chart/data?c=103&type=0&page=1&limit=100&_=1517477892257"

headers_ = {

    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87'

}
page_source = requests.get(url=url_,headers=headers_)

print("響應結果:\n",page_source.text)

model = etree.HTML(page_source.text)
    運行之后:
    可以看到這就是我們理想數據了,相關音樂排行榜數據都在其中了,剩下的就是提取數據了,這里我們使用XPath語法提取,首先還是在瀏覽器那邊定位一下我們想要的歌曲名、歌手所在元素位置,然后確定XPath路徑寫法。
    我們看到歌曲名在<a>標簽里面,而且這個標簽是在樣式類型為“info”的div標簽里面嵌套的,層次為:
<div class="info">
    <p>
        <strong>
            <a>歌曲名等信息  在第一個p標簽里面</a>
        </strong>
    </p>
    <p>
        ...
        ...
    </p>
</div>
    那我們根據這個層級初步寫出一個XPath路徑:
     //div[@class="info"]/p[1]/strong/a/text()    
    我們使用XPath Helper插件進行驗證一下:
    
 
    我們發現這句XPath選擇是可以把當前頁面所有的歌曲名稱選擇出來的,然后就是再選擇歌曲對應的歌手,我們再看一下歌手標簽所在的DOM結構:
 
    我們看到歌曲名在<a>標簽里面,而且這個標簽是在樣式類型為“info”的div標簽里面嵌套的,層次為:
 
<div class="info">
    <p>
        ...
        ...
    </p>
    <p>
       <a>歌手名稱,在第二個p標簽里面</a>
    </p>
 
    基於以上結構,我們初步下一個XPath路徑:
     //div[@class="info"]/p[2]/a
    我們使用XPath Helper插件進行驗證一下:
    
    此時我們發現這個XPath選擇確實把歌手名稱選中了,但是好像有個問題,明明查詢出來100首歌曲,怎么卻有129位歌手呢?對應不起來啊。別急,那我們就仔細看一下每一首歌曲的歌手吧
    
 
    從中發現,一首歌曲可能有多位演唱者,每一位演唱者占用一個<a>標簽,且用“;”分隔,如下:
    這樣的話我們改進一下XPath選擇,試試選擇<a>標簽所在的p標簽,這樣把多位歌手(即多個a標簽)看成一個list集合,我們在Python代碼處理即可,修改后的XPath選擇如下:
     //div[@class='info']/p[2]
    
    此時我們看到這次選擇的就不是每一位歌手所在a標簽了,二是上一級的整個p標簽,而且選擇出來的歌手一共100位,正好和歌曲個數對應起來了,那么就到此為止,我們用代碼處理:
import requests
from lxml import etree

url_ = "http://www.xiami.com/chart/data?c=103&type=0&page=1&limit=100&_=1517477892257"

headers_ = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87'
}

page_source = requests.get(url=url_, headers=headers_)
print("響應結果:\n", page_source.text)
model = etree.HTML(page_source.text)
songs_list = model.xpath('//div[@class="info"]/p[1]/strong/a/text()')

songer = model.xpath("//div[@class='info']/p[2]")
print("歌曲個數:{}   歌手個數:{}".format(len(songs_list),len(songer)))

 


 
 
 
    運行結果:
    對代碼繼續進行處理完善:
import requests
from lxml import etree
url_ = "http://www.xiami.com/chart/data?c=103&type=0&page=1&limit=100&_=1517477892257"

headers_ = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87'
}
page_source = requests.get(url=url_, headers=headers_)

print("響應結果:\n", page_source.text)

model = etree.HTML(page_source.text)
songs_list = model.xpath('//div[@class="info"]/p[1]/strong/a/text()')
songer = model.xpath("//div[@class='info']/p[2]")
print("歌曲個數:{}   歌手個數:{}".format(len(songs_list), len(songer)))
for index, item in enumerate(songs_list):
    # 繼續處理一首歌曲有多位演唱者的情況,因為每一位演唱者都在一個a標簽里面,我們把多個a標簽看成一個list集合處理
    songer_list = songer[index].xpath(".//a/text()")
    # 每一首歌曲的每一位演唱者組成一個list集合,我們利用join方法對list集合的每一項進行拼接,組成一個字符串結果
    dealed_songer = ",".join(songer_list)
    # 最后按格式輸出結果
    print("{}、{}\t【{}】".format(index + 1, item, dealed_songer))

 


 
 
 
最終結果:
歌曲個數:100   歌手個數:100
1、Bad Boy    【Red Velvet(레드벨벳)】
2、Electric Kiss    【EXO(엑소)】
3、Cosmic Railway    【EXO(엑소)】
4、說散就散    【袁婭維(Tia)】
5、追光者    【岑寧兒】
6、我們不一樣    【大壯】
7、帶你去旅行    【校長(張馳)】
8、剛好遇見你    【李玉剛】
9、123我愛你    【新樂塵符】
10、空空如也    【胡66】
11、成都    【趙雷(雷子)】
12、紅昭願    【音闕詩聽(Interseting)】
13、等你下課    【周傑倫,楊瑞代】
14、9420    【麥小兜】
15、Ei Ei    【偶像練習生】
16、廣東愛情故事    【廣東雨神】
17、小幸運    【田馥甄】
18、九張機    【葉炫清】
19、歲月神偷    【金玟岐】
20、BINGBIAN病變 (女聲版)    【鞠文嫻】
21、你就不要想起我    【田馥甄(Hebe)】
22、最美情侶    【白小白】
23、全部都是你    【Dragon Pig,Cloud Wang】
24、告白氣球    【周傑倫(Jay Chou)】
25、사랑을 했다    【iKON(TEAM B)】
26、過往    【鄒施如】
27、文愛    【CG(CHIGGA GANG黃鬼幫)】
28、差一步    【大壯】
29、在人間    【王建房】
30、Panama    【Matteo】
31、沒有你陪伴真的好孤單    【夢然】
32、童話鎮    【陳一發兒(陳一發)】
33、盡頭    【音闕詩聽(Interseting)】
34、Lovin’ You Mo’    【EXO(엑소)】
35、勉為其難    【王冕】
36、最美的期待    【周筆暢(BiBi Chou)】
37、非酋    【薛明媛,朱賀】
38、平凡之路    【朴樹】
39、多幸運    【韓安旭】
40、再也沒有    【Ryan.B,AY楊佬叄】
41、說散就散    【馮提莫(Ti mo Feng)】
42、空空如也    【任然】
43、Faded    【Alan Walker,Iselin Solheim】
44、你曾是少年    【S.H.E(SHE)】
45、小半    【陳粒(粒粒)】
46、All Right    【Red Velvet(레드벨벳)】
47、春風吹    【阿冷】
48、Shape of You    【Ed Sheeran(艾德·希蘭)】
49、默    【那英】
50、喜歡你    【G.E.M.鄧紫棋(鄧紫棋)】
51、盜心賊    【黑龍】
52、演員 (Live)    【薛之謙】
53、戀人心    【魏新雨】
54、Please Don't Go    【Joel Adams】
55、其實都沒有    【楊宗緯(Aska Yang)】
56、過客    【阿涵(周思涵)】
57、我們    【楊清檸,王樂樂】
58、丑八怪 (Live)    【薛之謙】
59、最久的瞬間    【炎亞綸(Aaron)】
60、大魚    【周深(卡布叻)】
61、Time    【MKJ】
62、回憶總想哭    【南宮嘉駿,姜玉陽】
63、Despacito (Remix)    【Luis Fonsi,Daddy Yankee,Justin Bieber】
64、山丘    【李宗盛(Jonathan Lee)】
65、回憶那么傷    【孫子涵(Niko)】
66、后來的我們    【五月天(Mayday)】
67、一笑傾城    【汪蘇瀧】
68、陪你度過漫長歲月    【陳奕迅(Eason Chan)】
69、林中鳥    【葛林】
70、半壺紗    【劉珂矣】
71、生活不止眼前的苟且    【許巍】
72、給我一個理由忘記    【A-Lin(黃麗玲)】
73、光年之外    【G.E.M.鄧紫棋(鄧紫棋)】
74、Dream It Possible    【Delacey】
75、Sugar    【Maroon 5(魔力紅)】
76、Havana    【Camila Cabello,Young Thug】
77、如果我們不曾相遇    【五月天(Mayday)】
78、全世界誰傾聽你    【林宥嘉(Yoga Lin)】
79、短發    【LAMPHO(lampho猴子)】
80、退    【蔣蔣(蔣家駒)】
81、小公主    【蔣蔣,楊清檸】
82、奇妙能力歌    【陳粒(粒粒)】
83、雨后人去樓也空    【王樂樂】
84、歌在飛    【蘇勒亞其其格(格格)】
85、我要你    【任素汐】
86、后會無期    【G.E.M.鄧紫棋(鄧紫棋)】
87、Зая    【Бамбинтон】
88、微微一笑很傾城    【楊洋】
89、Psycho (Pt. 2)    【Russ】
90、閃光 (Shinin’)    【鍾鉉(종현)】
91、四年半    【楊清檸】
92、情話微甜    【王聖鋒,李朝】
93、願得一人心    【李行亮】
94、病變remix    【前男友】
95、愛的就是你    【十二星宿風之少年,劉佳】
96、Grandpa    【阿克江LilAkin,Bohan Phoenix,Lofimaker】
97、好好 (想把你寫成一首歌)    【五月天(Mayday)】
98、無問西東    【王菲(Faye Wong)】
99、理想三旬    【陳鴻宇】
100、走在冷風中    【劉思涵(Koala)】
 

    至此,本教程結束,通過本教程,你清晰的看到了這個簡單數據爬取是怎么一步一步完成的,見證了從需求明確、問題原因分析、問題解決、代碼完善、最終完成的整個生命周期,那么此時你也就對爬蟲編寫基本思路有了一個簡單的認識,爬取數據的代碼都不會太復雜,復雜就復雜在發現問題、解決問題方式的尋找中,好的爬蟲在於數據價值、涵蓋范圍以及相關算法確定中。當然了,本教程爬取的數據沒多大價值,僅僅是拋磚引玉而已,希望各位靈活運用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM