爬取豆瓣TOP250圖書榜的出版社分布(一)-urllib2

爬取豆瓣TOP250圖書榜的出版社分布(一)-urllib2


0. 需求

現(xiàn)在準(zhǔn)備爬取豆瓣上的圖書TOP250然后看哪個(gè)出版社的圖書上榜最多。將使用兩種辦法分別實(shí)現(xiàn),urllib2與scrapy框架盏缤。爬取的內(nèi)容包括書的名字砰蠢,書的出版社,書的評(píng)分唉铜,書的鏈接台舱。

1. 使用urllib2實(shí)現(xiàn)

1.1 分析網(wǎng)站鏈接

http://book.douban.com/top250?start=0這個(gè)是豆瓣網(wǎng)站上圖書TOP250首頁的鏈接,很容易就會(huì)發(fā)現(xiàn)規(guī)律潭流,就是?start=0竞惋,表示的是這一個(gè)頁面的開始是從第0本書開始的,那么第二頁就是從start=25開始的灰嫉,了解了這一點(diǎn)拆宛,首先就可以把要爬取網(wǎng)站的url搞定了。

def __init__(self):
    self.addr = 'http://book.douban.com/top250'#?start=0
    self.colums=1
1.2 獲取網(wǎng)頁源代碼

為了防止豆瓣網(wǎng)檢測(cè)出是機(jī)器爬蟲訪問網(wǎng)站讼撒,從而封掉自己的ip浑厚,因此在發(fā)送request請(qǐng)求的時(shí)候,附帶上模擬瀏覽器訪問的headers根盒。

headers通過瀏覽器訪問豆瓣網(wǎng)钳幅,然后右鍵點(diǎn)擊審查元素,就可以查詢出用瀏覽器訪問的時(shí)候產(chǎn)生的headers和cookie炎滞。

下面的代碼中cookie有點(diǎn)長(zhǎng)敢艰。

獲取相應(yīng)的網(wǎng)站的源代碼步驟是:

  • 構(gòu)建url
  • 構(gòu)建request(本次要加上headers)
  • 發(fā)送請(qǐng)求
  • 讀取返回的源代碼數(shù)據(jù)

獲取網(wǎng)頁源代碼數(shù)據(jù)的代碼如下:

def getPage(self,page):
    '''獲取每個(gè)頁面的源代碼,豆瓣網(wǎng)站編碼是utf-8'''
    start=(page-1)*25
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language': 'zh-CN,zh;q=0.8',
        'Connection': 'keep-alive',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36',
        'Host':'book.douban.com',
        'Referer':'http://book.douban.com/top250?start=0',
        'Cookie':'bid="uJg2YuOLKDc"; ll="118371"; gr_user_id=f349a8b5-04e7-4132-b6c3-659f79f124fa; _pk_ref.100001.3ac3=%5B%22%22%2C%22%22%2C1454551498%2C%22http%3A%2F%2Fwww.douban.com%2F%22%5D; viewed="1770782_21323941_19952400_10432347_10436668_3155710_4830438_1152111_1015813"; _pk_id.100001.3ac3=c7eb454cb471541c.1439423804.9.1454552955.1448876420.; __utma=30149280.2012237960.1437482698.1451533495.1454551966.15; __utmc=30149280; __utmz=30149280.1451533495.14.11.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; __utma=81379588.2012449174.1439423804.1448876271.1454551966.9; __utmc=81379588; __utmz=81379588.1448876271.8.6.utmcsr=baidu|utmccn=(organic)|utmcmd=organic'
            }
    url=self.addr+'?start='+str(start)
    try:
        request=urllib2.Request(url,headers=headers)
        response=urllib2.urlopen(request)
        result=response.read()
    except urllib2.URLError,e:
        print '無法連接,原因:',e.reason
    else:
        return result

在這里有一個(gè)需要注意的tip就是册赛,最好不要直接return response.read()這樣有可能導(dǎo)致返回不了完整的數(shù)據(jù)钠导。

1.3 利用正則表達(dá)式匹配需要的信息

首先分析豆瓣網(wǎng)頁源代碼,找到圖書信息在HTML代碼中相應(yīng)的位置森瘪,建立合理的正則表達(dá)式辈双。

然后利用上一小節(jié)getPage()方法返回的網(wǎng)頁源代碼信息進(jìn)行匹配。

利用re模塊里面的findall()函數(shù)進(jìn)行匹配柜砾,將獲取到整個(gè)頁面的25本圖書的信息results湃望,并且返回的是一個(gè)列表,其中每一本書在這個(gè)列表中也是以列表存在的,因此迭代返回的列表证芭,獲取對(duì)應(yīng)的信息瞳浦。

[日] 東野圭吾 / 劉子倩 / 南海出版公司 / 2008-9 / 28.00

其中出版社這一條,可以通過觀察發(fā)現(xiàn)废士,出版社都在網(wǎng)站相應(yīng)字段的倒數(shù)第三個(gè),因此解析出版社數(shù)據(jù)的時(shí)候利用resultlt=result[2].split('/')將字符串分裂開叫潦,然后使用resultlt[-3]即可提取出出版社的信息。

整個(gè)處理方法代碼如下:

def getContent(self,page):
    '''通過獲得的源代碼將所需要的圖書信息匹配出來'''
    response=self.getPage(page)
    #建立正則表達(dá)式
    pattern=re.compile('<div class="pl2".*?<a href="(.*?)".*?title="(.*?)".*?<p class="pl">(.*?)</p>.*?<span class="rating_nums">(.*?)</span>',re.S)
    results=re.findall(pattern,response)
    contents=[]
    #1是鏈接2是名字3是作者與出版社信息4是得分
    for result in results:
        resultlt=result[2].split('/')
        contents.append([result[1],result[0],resultlt[-3].strip(),result[3]])
    return contents
    #只是直接打印列表的話才不會(huì)顯示正常字符官硝,如果直接打印就會(huì)打印出中文字符
1.4 將數(shù)據(jù)寫入文件

將獲取到的數(shù)據(jù)按照對(duì)應(yīng)字段寫入txt文本文檔還是相當(dāng)容易的矗蕊,主要的問題是字符串的編碼問題,豆瓣網(wǎng)采用了utf-8編碼氢架,因此在讀取網(wǎng)頁源代碼以及寫入文件的時(shí)候并不需要考慮編碼問題傻咖。

直接將要寫入文件的字符串格式建立好就可以直接寫入了。

寫入函數(shù)如下所示:

def writeFile(self,contents):
    '''將數(shù)據(jù)寫入到文本文件中'''
    file=open('douban.txt','a')
    for content in contents:
        line='\n'+str(self.colums)
        info='\nname:'+content[0]+'\naddress:'+content[1]+'\npress:'+content[2]+'\nrate:'+content[3]+'\n'
        file.write(line)
        file.write(info)
        self.colums+=1
    file.close()

寫入后的文本效果如下圖:

寫入的文本
1.5 開始程序

在這里將控制程序打開豆瓣圖書TOP250的10個(gè)頁面岖研,然后分別進(jìn)行數(shù)據(jù)提取卿操。代碼如下:

def start(self):
    '''開始程序,首先讀取content然后將數(shù)據(jù)保存到shelve模塊中'''
    i=1
    while i<=10:
        print '正在讀取并存儲(chǔ)第',str(i),'頁內(nèi)容'
        contents=self.getContent(i)
        self.writeData(contents)
        self.writeFile(contents)
        i+=1
        time.sleep(10)

這里需要注意的是在打開頁面之間最好留有間隔孙援,time.sleep(10),間隔10秒害淤,否則豆瓣網(wǎng)站會(huì)禁止訪問。

1.6 數(shù)據(jù)分析

#######1.6.1 從文本文件提取出版社信息

下面進(jìn)行的內(nèi)容就是將存入文件的TOP250的圖書信息提取出來拓售,然后將每本書的出版社匯總分析窥摄,看每個(gè)出版社出現(xiàn)了多少次,然后做成直觀的統(tǒng)計(jì)圖表進(jìn)行顯示础淤。

做到這一切的核心思想是:將文本文件的文本提取出來(使用readlines())溪王,然后使用正則表達(dá)式提取press的信息,創(chuàng)建一個(gè)字典值骇,出版社名為鍵莹菱,出版社出現(xiàn)的次數(shù)作為值。

使用字典的has_key方法判斷是否有該出版社鍵值吱瘩,沒有則將該出版社作為鍵加入字典道伟,設(shè)置默認(rèn)值1。如果有的話使碾,將該出版社對(duì)應(yīng)的值加一蜜徽。最后獲得整個(gè)的出版社次數(shù)的字典。

另外程序還使用了shelve作為對(duì)出版社數(shù)據(jù)的簡(jiǎn)單的存儲(chǔ)票摇,shelve的使用非常方便拘鞋,只需要將其當(dāng)成普通的字典,這一點(diǎn)剛好符合我們的提取信息的方案矢门,將其存入shelve后盆色,在下一步的數(shù)據(jù)可視化中就可以方便的將數(shù)據(jù)提取出來灰蛙。

代碼如下:

#coding=utf-8

'''這個(gè)程序是將存入文件的豆瓣圖書書單的出版社提取出來,存入字典
使用setdefault()方法隔躲,如果有相應(yīng)的鍵則返回鍵對(duì)應(yīng)的值
否則返回默認(rèn)值1'''
import re
import shelve

class ExtractPress():
'''首先定義一個(gè)存放出版社和數(shù)量的字典摩梧,然后是輸入,以及匹配的內(nèi)容'''

    def __init__(self):
        self.pressDic={}
        self.pattern=re.compile('press:(.*?).rate',re.S)
        self.database=shelve.open('press.dat')


    def getAllValue(self):
        text=open('douban.txt').readlines()
        strText=''.join(text)
        results=re.findall(self.pattern,strText)
        for result in results:
            if self.pressDic.has_key(result):
                number=int(self.pressDic[result])
                number+=1
                self.pressDic[result]=number
            else:
                self.pressDic.setdefault(result,1)

    def printDic(self):
        for press in self.pressDic:
            print press+':'+str(self.pressDic[press])
            self.database[press]=self.pressDic[press]
        self.database.close()

if __name__=='__main__':
example=ExtractPress()
example.getAllValue()
example.printDic()

#######1.6.2 對(duì)提取的信息進(jìn)行可視化處理

在這里我將使用matplotlib進(jìn)行數(shù)據(jù)分析宣旱,有關(guān)matplotlib的環(huán)境配置仅父,請(qǐng)移步利用matplotlib進(jìn)行數(shù)據(jù)分析(一)一文,其中包含了matplotlib以及相關(guān)依賴的安裝配置方法浑吟。

這里直接上代碼笙纤,然后對(duì)代碼進(jìn)行分析,關(guān)于數(shù)據(jù)可視化編程的知識(shí)组力,參考Python數(shù)據(jù)可視化編程實(shí)戰(zhàn) [愛爾蘭]Igon Milovanovic一書省容。

#coding=utf-8

import shelve
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties

class dataAnalyseGraph():
    '''這個(gè)類將上面的出版社的數(shù)據(jù)信息提取出來,做出一個(gè)可視化的圖表'''

    def __init__(self):
        self.database=shelve.open('press.dat')
        self.keys=[]
        self.data=[]
        self.font=FontProperties(fname=r'C:\WINDOWS\Fonts\STSONG.TTF',size=10)

    def getData(self):
        for key in self.database.iterkeys():
            if self.database[key]<=1:
                continue
            self.keys.append(key.decode('utf-8'))
            self.data.append(self.database[key])
        print self.data
        for n in self.keys:
            print n

    def makeGraph(self):
        y_pos=range(len(self.keys))
        # colors=np.random.rand(len(self.keys))
        #水平柱狀圖
        plt.barh(y_pos,self.data,align='center',alpha=0.4)
        #刻度
        plt.yticks(y_pos,self.keys,fontproperties=self.font)
        #繪圖
        for datas,y_pos in zip(self.data,y_pos):
            plt.text(datas,y_pos,datas,horizontalalignment='center',
                 verticalalignment='center',weight='bold')
        #set y limit
        plt.ylim(+32,-1.0)
        plt.title(u'豆瓣圖書TOP250出版社統(tǒng)計(jì)',fontproperties=self.font)
        plt.ylabel(u'出版社',fontproperties=self.font)
        plt.subplots_adjust(bottom=0.15)
        plt.xlabel(u'出版社出現(xiàn)次數(shù)',fontproperties=self.font)
        plt.show()
        plt.savefig("douban_book_press.png")

if __name__=='__main__':
    graph=dataAnalyseGraph()
    graph.getData()
    graph.makeGraph()

建立了一個(gè)專門作為數(shù)據(jù)可視化的類忿项,在該類的構(gòu)造方法中蓉冈,打開了shelve文件(上一小節(jié)中存儲(chǔ)的出版社數(shù)據(jù)),初始化了兩個(gè)列表城舞,同時(shí)打開了一個(gè)宋體的文字文件作為圖表顯示文字轩触。

getData方法中將文件的數(shù)據(jù)提取出來,這里由于出版社過多家夺,因此只提取了出現(xiàn)1次以上的出版社脱柱,將出版社和出現(xiàn)次數(shù)按順序存放至建立好的keys和data列表中。

makeGraph是數(shù)據(jù)可視化的核心部分拉馋。barh是繪制水平柱狀圖的函數(shù)榨为,接收y_pos為豎直坐標(biāo),而self.data作為柱狀圖的值煌茴,align指定了矩形條的居中設(shè)置随闺,alpha指定了透明度。yticks是豎直方向的刻度設(shè)置蔓腐,y_pos指定了刻度矩乐,而self.keys指定了刻度的顯示,這兩個(gè)是一一對(duì)應(yīng)的回论。然后將每一組data與y_pos的柱指定它的文本散罕,坐標(biāo)就是datas(出版社出現(xiàn)次數(shù),橫坐標(biāo)的值),y_pos是y坐標(biāo)傀蓉,datas是顯示的數(shù)字欧漱。然后ylim設(shè)置y的上下限。設(shè)置標(biāo)題葬燎,設(shè)置y軸的標(biāo)簽误甚,x的標(biāo)簽缚甩,然后show顯示該圖像。

最后的可視化效果如圖所示:

豆瓣圖書TOP250出版社分布
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末靶草,一起剝皮案震驚了整個(gè)濱河市蹄胰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌奕翔,老刑警劉巖裕寨,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異派继,居然都是意外死亡宾袜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門驾窟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來庆猫,“玉大人,你說我怎么就攤上這事绅络≡屡啵” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵恩急,是天一觀的道長(zhǎng)杉畜。 經(jīng)常有香客問我,道長(zhǎng)衷恭,這世上最難降的妖魔是什么此叠? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮随珠,結(jié)果婚禮上灭袁,老公的妹妹穿的比我還像新娘。我一直安慰自己窗看,他們只是感情好茸歧,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著显沈,像睡著了一般软瞎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上构罗,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天铜涉,我揣著相機(jī)與錄音,去河邊找鬼遂唧。 笑死芙代,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盖彭。 我是一名探鬼主播纹烹,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼页滚,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了铺呵?” 一聲冷哼從身側(cè)響起裹驰,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎片挂,沒想到半個(gè)月后幻林,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡音念,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年沪饺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闷愤。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡整葡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出讥脐,到底是詐尸還是另有隱情遭居,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布旬渠,位于F島的核電站俱萍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏坟漱。R本人自食惡果不足惜鼠次,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一更哄、第九天 我趴在偏房一處隱蔽的房頂上張望芋齿。 院中可真熱鬧,春花似錦成翩、人聲如沸觅捆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽栅炒。三九已至,卻和暖如春术羔,著一層夾襖步出監(jiān)牢的瞬間赢赊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工级历, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留释移,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓寥殖,卻偏偏與公主長(zhǎng)得像玩讳,于是被迫代替她去往敵國(guó)和親涩蜘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,867評(píng)論 25 707
  • 今天開始這學(xué)期就算正式開始了熏纯,心情還是沒有收拾好同诫,有些累。 不會(huì)說話辦事的樟澜,唉误窖,慢慢熬吧~ 對(duì)自己的堅(jiān)持也有所懷疑...
    salen小倫閱讀 144評(píng)論 0 0
  • 前兩天一個(gè)人正在發(fā)呆,朋友發(fā)了一條消息:你考完試直接到我們學(xué)校找我吧秩贰,不要聯(lián)系他了贩猎。 心里咯噠一下。 分了萍膛?我問她...
    盛夏安年閱讀 160評(píng)論 0 0
  • 上一章 吃飽喝足后吭服,林思凡心滿意足地坐到了一邊,至于洗碗刷鍋的事自然由另外兩個(gè)男生分擔(dān)蝗罗,自己暫時(shí)可以歇歇了艇棕。整理好...
    狐貍九閱讀 372評(píng)論 0 4
  • 明凈的車窗外 藍(lán)天白云綠水青山紅磚灰瓦 原來天上的空和云是分開的 白云就像剛出爐的棉花糖 扯一片含在口中 一絲甜蜜...
    叫我梅芳就好閱讀 937評(píng)論 1 0