selenium +phantomjs 爬取網(wǎng)易云音樂(lè)的評(píng)論信息

1.前言

網(wǎng)易云音樂(lè)的網(wǎng)頁(yè)端與服務(wù)端通訊做了加密艰毒,本人才疏學(xué)淺破解不了,于是考慮用
selenium +phantomjs的方式爬取大年,selenium 用pip install selenium 安裝
phantomjs 官網(wǎng)下載安裝包即可介陶,Python版本為3.6,用了mysql數(shù)據(jù)庫(kù)商模,環(huán)境為win7 不過(guò)理論上linux mac也可以跑

2.爬取思路

點(diǎn)開(kāi)一首歌的頁(yè)面,這首歌的評(píng)論也會(huì)出現(xiàn)在頁(yè)面下方蜘澜,當(dāng)然通常情況下一頁(yè)是加載不完的施流,所以得通過(guò)模擬點(diǎn)擊下一頁(yè)的方式一頁(yè)一頁(yè)的撈評(píng)論,因?yàn)橹皇桥廊?shù)據(jù)順便學(xué)習(xí)下鄙信,只爬取了用戶id瞪醋,用戶昵稱,建立了一個(gè) userid nickname music 構(gòu)成的mysql表装诡,同時(shí)將爬取并且通過(guò)selenium 解析出來(lái)的頁(yè)面信息緩存到本地银受,以后也許會(huì)有用的上的地方

3.幾個(gè)關(guān)鍵點(diǎn)

在爬取過(guò)程中有幾個(gè)點(diǎn)需要注意

  • 1.selenium +phantomjs 解析頁(yè)面時(shí),如果頁(yè)面上用到了iframe鸦采,需要switch_to.frame()的方式切換到對(duì)應(yīng)的iframe宾巍,否則可能會(huì)導(dǎo)致查找不到需要的 element
  • 2.頁(yè)面上有異步的ajax請(qǐng)求時(shí),最好在做操作后等待一會(huì)再查找element渔伯,否則有可能找不到數(shù)據(jù)
  • 3.有的操作是讓頁(yè)面重新走了下ajax請(qǐng)求如點(diǎn)擊下一頁(yè)顶霞,這個(gè)時(shí)候頁(yè)面不需要重新加載url地址,有些則需要锣吼,比如這首歌的評(píng)論我爬完了选浑,爬取下一首
4.結(jié)合代碼講解下

代碼一個(gè)是操作數(shù)據(jù)的sqlinstance.py 一個(gè)是主程序 spider_main.py
sqlinstance 用了sqlalchemy框架蓝厌,目前只有一張表用于記錄用戶和歌曲的評(píng)論關(guān)系,
代碼如下

from sqlalchemy import create_engine, text, Column, Integer, String, Sequence, \
    Date, UniqueConstraint, BigInteger
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()


class MusicCmt(Base):
    __tablename__ = "t_musiccmts"
    id=Column(Integer,primary_key=True,autoincrement=True)
    userid = Column(BigInteger)
    nickname=Column(String(20),nullable=False)
    musicid = Column(BigInteger, nullable=False)
    __table_args__ = (UniqueConstraint('nickname', 'musicid'),
                      )

# 建立連接
engine = create_engine('mysql+pymysql://pig:123456@localhost:3306/cloudmusic?charset=utf8'
                       ,encoding='utf-8',echo=False,pool_size=50, pool_recycle=3600)
DBSession = sessionmaker(bind=engine)
# 通過(guò)代碼創(chuàng)建數(shù)據(jù)庫(kù)
try:
    MusicCmt.__table__.create(engine)
except Exception as e :
    print(e)
    pass


class SqlInstance:
    def addmark(self,**kwargs):

        session = DBSession()
        try:
            # 插入一條數(shù)據(jù)
            session.add(
                MusicCmt(userid=kwargs['userid'], musicid=kwargs['musicid'],nickname=kwargs["nickname"]))
            session.commit()
        except Exception as e:
            print(e)
            pass
        session.close()
sqlInstance=SqlInstance()

代碼看完 基本的sqlalchemy 建立mysql數(shù)據(jù)表并插入數(shù)據(jù)的操作就可以做了古徒,其他復(fù)雜操作可以查官網(wǎng)拓提,這里我也不多說(shuō)了

接下來(lái)是主程序了,因?yàn)樵囟ㄎ皇怯脕?lái)很多xpath的語(yǔ)法隧膘,不熟悉的同學(xué)最好先看下語(yǔ)法代态,然后自己打開(kāi)一個(gè)網(wǎng)易云音樂(lè)的頁(yè)面,用Chrome的檢查元素舀寓,再通過(guò)xpath查詢的方式定位element ,可以驗(yàn)證下代碼和xpath語(yǔ)法

主程序代碼如下

import os
import re
import time
from selenium import webdriver
from selenium.webdriver import DesiredCapabilities
import configparser

import sqlinstance
# 將目標(biāo)musicid存到了一個(gè)文件里面肌蜻,這個(gè)如果要做大的話可以動(dòng)態(tài)獲得
config = configparser.ConfigParser()
config.read('myselectMusic.ini')
musiclist= config['nemusic']['id'].split(",")
# //PHANTOMJS自定義userAgent互墓,避免被反爬
dcap = dict(DesiredCapabilities.PHANTOMJS)
dcap["phantomjs.page.settings.userAgent"] = (
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"
)

driver = webdriver.PhantomJS(desired_capabilities=dcap)
# 設(shè)置一個(gè)很長(zhǎng)的網(wǎng)頁(yè)加載數(shù)據(jù),省的有些情況還得滾動(dòng)頁(yè)面
driver.set_window_size(1920,5000)

for musicid in musiclist:
    # 加載歌曲第一頁(yè)
    driver.get("http://music.163.com/#/song?id=%s" % (musicid))
    # 等待網(wǎng)頁(yè)ajax 請(qǐng)求完成
    time.sleep(1)
    ele = driver.find_element_by_class_name("g-iframe")
    # print(ele)
    # 頁(yè)面里面有iframe嵌套蒋搜,如果要定位的元素iframe里面
    # 必須切換篡撵,否則會(huì)查找不到
    driver.switch_to.frame(ele)

    pagenum=1
    # 查看下已經(jīng)爬取了多少頁(yè),
    # 避免重復(fù)操作
    savedfiles = os.listdir("saves")
    thissaved = [a for a in
                 savedfiles if
                 a.startswith(musicid) and a.count("final")>0]
    if(len(thissaved)>0):
        continue
    maxpage=0
    try:
        thissaved = [int(a.replace(musicid + "_", "").replace(r".txt", "")) for a in savedfiles if
                     a.startswith(musicid)]
    except:
        maxpage == "final"
        pass
    if maxpage and maxpage == "final":
        continue
    if len(thissaved)>0:
        maxpage = sorted(thissaved, reverse=True)[0]
    else:
        maxpage=0

    maxpage=int(maxpage)
    if maxpage>0:
        current_is_end=False
        while True:
            # 這個(gè)xpath是查找頁(yè)面底部的 1.2,3 豆挽。育谬。。這些的翻頁(yè)element
            # 點(diǎn)擊就是跳的目標(biāo)頁(yè)了
            # 網(wǎng)易云音樂(lè)的布局是 最后一個(gè)是跳轉(zhuǎn)下一頁(yè)帮哈,倒數(shù)第二個(gè)是跳轉(zhuǎn)最后一頁(yè)
            # 膛檀,倒數(shù)第二個(gè)是翻一個(gè)大頁(yè)面,如1-10 點(diǎn)了下就變成3-13 這種
            pagejumps = driver.find_elements_by_xpath(
                "http://div[contains(@class,'u-page')]/a")
            target=[ a for a in pagejumps if a.text==str(int(maxpage)+1)]
            if target:
                pagenum = maxpage+1
                target[0].click()
                time.sleep(1)
                break
            else:
                pagejumps[-3].click()
                time.sleep(1)
    while True:
        # 這個(gè)xpath就是找到當(dāng)前頁(yè)面的所有評(píng)論的用戶昵稱
        cmts=driver.find_elements_by_xpath("http://div[@class='cnt f-brk']/a[@class='s-fc7']")
# print(len(kk))
        if len(cmts)>0:
            for aelemnt in cmts:
                urluid=aelemnt.get_attribute("href")
                print("nikename:%s url%s" %(aelemnt.text,aelemnt.get_attribute("href")))
                try:
                    # 從點(diǎn)擊昵稱的跳轉(zhuǎn)鏈接正則解析出用戶uid
                    saveuid=re.findall(r"id=(\d+)",urluid)[0]
                except:
                    saveuid=None
                    pass
                # 數(shù)據(jù)存入數(shù)據(jù)庫(kù)
                sqlinstance.sqlInstance.addmark(userid=saveuid, musicid=musicid,nickname=aelemnt.text)
        # 找到頁(yè)面上的下一頁(yè)按鈕
        nextpagebtn=driver.find_element_by_xpath("http://div[contains(@class,'u-page')]/a[text()='下一頁(yè)']")
        str = driver.find_element_by_xpath("http://html").get_attribute("innerHTML")
        # 判斷當(dāng)前頁(yè)是否為最后一頁(yè)
        if "js-disable" in nextpagebtn.get_attribute("class"):
            print("最后一頁(yè)")
            # 緩存下爬取的數(shù)據(jù)
            with open("saves/%s_%s.txt" % (musicid, "final"), "w",encoding='utf-8') as f:
                f.write(str)
            break
        else:
            nextpagebtn.click()
            with open("saves/%s_%s.txt" % (musicid, pagenum), "w",encoding='utf-8') as f:
                f.write(str)
            pagenum += 1
            time.sleep(2)

# 退出瀏覽器別忘了
driver.quit()

然后直接Python 跑下就好了,效果如圖所示


效果如圖
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末娘侍,一起剝皮案震驚了整個(gè)濱河市咖刃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌憾筏,老刑警劉巖嚎杨,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異氧腰,居然都是意外死亡枫浙,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)古拴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)箩帚,“玉大人,你說(shuō)我怎么就攤上這事黄痪「喑保” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵满力,是天一觀的道長(zhǎng)焕参。 經(jīng)常有香客問(wèn)我轻纪,道長(zhǎng),這世上最難降的妖魔是什么叠纷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任刻帚,我火速辦了婚禮,結(jié)果婚禮上涩嚣,老公的妹妹穿的比我還像新娘崇众。我一直安慰自己,他們只是感情好航厚,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布顷歌。 她就那樣靜靜地躺著,像睡著了一般幔睬。 火紅的嫁衣襯著肌膚如雪眯漩。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天麻顶,我揣著相機(jī)與錄音赦抖,去河邊找鬼。 笑死辅肾,一個(gè)胖子當(dāng)著我的面吹牛队萤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播矫钓,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼要尔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了新娜?” 一聲冷哼從身側(cè)響起盈电,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎杯活,沒(méi)想到半個(gè)月后匆帚,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旁钧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年吸重,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歪今。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嚎幸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出寄猩,到底是詐尸還是另有隱情嫉晶,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站替废,受9級(jí)特大地震影響箍铭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜椎镣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一诈火、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧状答,春花似錦冷守、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至馆截,卻和暖如春充活,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背孙咪。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工堪唐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留巡语,地道東北人翎蹈。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像男公,于是被迫代替她去往敵國(guó)和親荤堪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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