1. 程式人生 > >Python進階(十八)-Python3爬蟲小試牛刀之爬取CSDN部落格個人資訊

Python進階(十八)-Python3爬蟲小試牛刀之爬取CSDN部落格個人資訊

分享一下我的偶像大神的人工智慧教程!http://blog.csdn.net/jiangjunshow

也歡迎轉載我的文章,轉載請註明出處 https://blog.csdn.net/mm2zzyzzp

Python進階(十八)-Python3爬蟲實踐

  這篇文章主要介紹瞭如何使用Python3爬取csdn部落格訪問量的相關資料,在Python2已實現的基礎上實現Python3爬蟲,對比版本之間的差異所在,需要的朋友可以參考下。
  使用python來獲取自己部落格的訪問量,也是後面將要開發專案的一部分,後邊會對部落格的訪問量進行分析,以折線圖和餅圖等視覺化的方式展示自己部落格被訪問的情況,使自己能更加清楚自己的哪些部落格更受關注。其實,在較早之前部落格專家本身就有這個功能,不知什麼原因此功能被取消了。

一.網址分析

這裡寫圖片描述
  進入自己的部落格頁面,網址為:http://blog.csdn.net/sunhuaqiang1。 網址還是比較好分析的:就是csdn的網址+個人csdn登入賬號,我們來看下一頁的網址。
這裡寫圖片描述
  看到第二頁的地址為:http://blog.csdn.net/sunhuaqiang1/article/list/2後邊的數字表示現在正處於第幾頁,再用其他的頁面驗證一下,確實是這樣的,那麼第一頁為什麼不是http://blog.csdn.net/sunhuaqiang1/article/list/1呢,那麼我們在瀏覽器中輸http://blog.csdn.net/sunhuaqiang1/article/list/1

試試,哎,果然是第一頁啊,第一頁原來是被重定向了,http://blog.csdn.net/sunhuaqiang1被重定向到http://blog.csdn.net/sunhuaqiang1/article/list/1,所以兩個網址都能訪問第一頁,那麼現在規律就非常明顯了: http://blog.csdn.net/sunhuaqiang1/article/list/ + 頁號

二.獲取標題

  右鍵檢視網頁的原始碼,我們看到可以找到這樣一段程式碼:
這裡寫圖片描述
這裡寫圖片描述
  我們可以看到標題都是在標籤

<span class="link_title">
<a href="/sunhuaqiang1/article/details/50651235"
> ... </a> </span>
  • 1
  • 2
  • 3
  • 4
  • 5

  中的。所以我們可以使用下面的正則表示式來匹配標題:

<span class="link_title"><a href=".*?">(.*?)</a></span>
  
  • 1

三.獲取訪問量

  拿到了標題之後,就要獲得對應的訪問量了,經過對原始碼的分析,我看到訪問量的結構都是這樣的:

<span class="link_view" title="閱讀次數"><a href="/sunhuaqiang1/article/details/51289580" title="閱讀次數">閱讀</a>(12718)</span>
  
  • 1

  括號中的數字即為訪問量,我們可以用下面的正則表示式來匹配:

<span class="link_view".*?><a href=".*?" title="閱讀次數">閱讀</a>\((.*?)\)</span>
  
  • 1

  其中,’.?’的含義是啟用正則懶惰模式。必須跟在或者+後邊用。
  如:“< img src=”test.jpg” width=”60px” height=”80px”/>”
  如果用正則匹配src中內容非懶惰模式匹配

src=".*"
  
  • 1

  匹配結果是:src=”test.jpg” width=”60px” height=”80px”
  意思是從=”往後匹配,直到最後一個”匹配結束
懶惰模式正則:

src=".*?"
  
  • 1

  結果:src=”test.jpg”
  因為匹配到第一個”就結束了一次匹配。不會繼續向後匹配。因為他懶惰嘛。

  • .表示除\n之外的任意字元
  • *表示匹配0-無窮
  • +表示匹配1-無窮

四.尾頁判斷

  接下來我們要判斷當前頁是否為最後一頁,否則我們就不能判斷什麼時候結束了,我找到了原始碼中‘尾頁’的標籤,發現是下面的結構:

<a href="/sunhuaqiang1/article/list/2">下一頁</a> <a href="/sunhuaqiang1/article/list/7">尾頁</a>
  
  • 1

  所以我們可以用下面的正則表示式來匹配,如果匹配成功就說明當前頁不是最後一頁,否則當前頁就是最後一頁。

<a href=".*?">尾頁</a>
  
  • 1

五.程式設計實現

  下面是摘自的Python2版完整的程式碼實現:

#!usr/bin/python
# -*- coding: utf-8 -*-
'''
Created on 2016年2月13日
@author: ***
使用python爬取csdn個人部落格的訪問量,主要用來練手
'''
import urllib2
import re
#當前的部落格列表頁號
page_num = 1
#不是最後列表的一頁
notLast = 1
account = str(raw_input('輸入csdn的登入賬號:'))
while notLast:
    #首頁地址
    baseUrl = 'http://blog.csdn.net/'+account
    #連線頁號,組成爬取的頁面網址
    myUrl = baseUrl+'/article/list/'+str(page_num)
    #偽裝成瀏覽器訪問,直接訪問的話csdn會拒絕
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    headers = {'User-Agent':user_agent}
    #構造請求
    req = urllib2.Request(myUrl,headers=headers)
    #訪問頁面
    myResponse = urllib2.urlopen(req)
    myPage = myResponse.read()
    #在頁面中查詢是否存在‘尾頁'這一個標籤來判斷是否為最後一頁
    notLast = re.findall('<a href=".*?">尾頁</a>',myPage,re.S)
    print '---------------第%d頁-------------' % (page_num,)
    #利用正則表示式來獲取部落格的標題
    title = re.findall('<span class="link_title"><a href=".*?">(.*?)</a></span>',myPage,re.S)
    titleList=[]
    for items in title:
        titleList.append(str(items).lstrip().rstrip())
    #利用正則表示式獲取部落格的訪問量
    view = re.findall('<span class="link_view".*?><a href=".*?" title="閱讀次數">閱讀</a>\((.*?)\)</span>',myPage,re.S)
    viewList=[]
for items in view:
    viewList.append(str(items).lstrip().rstrip())
#將結果輸出 
for n in range(len(titleList)):
    print '訪問量:%s 標題:%s' % (viewList[n].zfill(4),titleList[n])
#頁號加1
page_num = page_num + 1
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

  由於自己現在的IDE為Python3,且自己在學習Python3。故在此基礎上實現Python2專案的升級改造,並在改造過程中發現版本之間的差異性。以下為Python3版本下的爬蟲程式碼。

#!usr/bin/python
# -*- coding: utf-8 -*-
'''
Created on 2017年3月19日
@author: SUN HuaQiang
目的:使用python爬取csdn個人部落格的訪問量,主要用來練手Python爬蟲
收穫:1.瞭解Python爬蟲的基本過程
      2.在Python2的基礎上實現Python3,通過對比發現版本之間的差異
'''
import urllib.request
import urllib
import re

#當前的部落格列表頁號
page_num = 1
#初始化最後列表的頁碼
notLast = 1
account = str(input('請輸入csdn的登入賬號:'))
while notLast:
    #首頁地址
    baseUrl = 'http://blog.csdn.net/' + account
    #連線頁號,組成爬取的頁面網址
    myUrl = baseUrl+'/article/list/' + str(page_num)
    #偽裝成瀏覽器訪問,直接訪問的話csdn會拒絕
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    headers = {'User-Agent':user_agent}
    #構造請求
    req = urllib.request.Request(myUrl,headers=headers)
    #訪問頁面
    myResponse = urllib.request.urlopen(req)
    #python3中urllib.read返回的是bytes物件,不是string,得把它轉換成string物件,用bytes.decode方法
    myPage = myResponse.read().decode()
    #在頁面中查詢是否存在‘尾頁'這一個標籤來判斷是否為最後一頁
    notLast = re.findall('<a href=".*?">尾頁</a>', myPage, re.S)
    print ('-----------第%d頁--------------' % (page_num,))
    #利用正則表示式來獲取部落格的標題
    title = re.findall('<span class="link_title"><a href=".*?">(.*?)</a></span>',myPage,re.S)
    titleList=[]
    for items in title:
        titleList.append(str(items).lstrip().rstrip())
    #利用正則表示式獲取部落格的訪問量
    view = re.findall('<span class="link_view".*?><a href=".*?" title="閱讀次數">閱讀</a>\((.*?)\)</span>',myPage,re.S)
    viewList=[]
    for items in view:
        viewList.append(str(items).lstrip().rstrip())
    #將結果輸出
    for n in range(len(titleList)):
        print ('訪問量:%s 標題:%s' % (viewList[n].zfill(4),titleList[n]))
    #頁號加1
    page_num = page_num + 1
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

  下面是部分結果:
這裡寫圖片描述
  瑕疵:通過爬蟲結果可以發現,在CSDN中,對於設定為指定的文章,爬取結果存在一定的問題,還包含部分css程式碼。
  改善:通過更改獲取博文標題的正則表示式,即可解決此問題。
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
  想法是好的,但是直接利用正則實現標題獲取時遇到了困難,暫時並未實現理想結果。
  遂改變思路,將利用正則獲取後的字串再進行二次正則,即替換操作,語句如下:

for items in title:
    titleList.append(re.sub('<font color="red">.*?</font>', '', str(items).lstrip().rstrip()))
  
  • 1
  • 2

  更改後的結果如下。並同時為每篇博文進行了編號。
這裡寫圖片描述
  同時,自己還希望獲取到的資訊包括:訪問總量、積分、等級、排名、粉絲、原創、轉載、譯文、評論等資料資訊。
  以上資訊在網頁原始碼中如下所示。

<ul id="blog_rank"> 
    <li>訪問:<span>459285次</span></li> 
    <li>積分:<span>9214</span> </li> 
    <li >等級: <span style="position:relative;display:inline-block;z-index:1" > 
    <img src="http://c.csdnimg.cn/jifen/images/xunzhang/jianzhang/blog6.png" alt="" style="vertical-align: middle;" id="leveImg"> 
    <div id="smallTittle" style=" position: absolute; left: -24px; top: 25px; text-align: center; width: 101px; height: 32px; background-color: #fff; line-height: 32px; border: 2px #DDDDDD solid; box-shadow: 0px 2px 2px rgba (0,0,0,0.1); display: none; z-index: 999;"> 
    <div style="left: 42%; top: -8px; position: absolute; width: 0; height: 0; border-left: 10px solid transparent; border-right: 10px solid transparent; border-bottom: 8px solid #EAEAEA;"></div> 
    積分:9214 </div> 
    </span> </li> 
    <li>排名:<span>第1639名</span></li> 
    </ul> 
    <ul id="blog_statistics"> 
    <li>原創:<span>425篇</span></li> 
    <li>轉載:<span>44篇</span></li> 
    <li>譯文:<span>2篇</span></li> 
    <li>評論:<span>108條</span></li> 
    </ul> 
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

  則獲取訪問資訊的正則表示式為:

#利用正則表示式獲取部落格資訊
sumVisit = re.findall('<li>訪問:<span>(.*?)</span></li>', myPage, re.S)
credit = re.findall('<li>積分:<span>(.*?)</span> </li>', myPage, re.S)
rank = re.findall('<li>排名:<span>(.*?)</span></li>', myPage, re.S)
grade = re.findall('<li >.*?<img src=.*?/blog(.*?).png.*?>.*?</li>', test3, re.S)
original = re.findall('<li>原創:<span>(.*?)</span></li>', myPage, re.S)
reprint = re.findall('<li>轉載:<span>(.*?)</span></li>', myPage, re.S)
trans = re.findall('<li>譯文:<span>(.*?)</span></li>', myPage, re.S)
comment = re.findall('<li>評論:<span>(.*?)</span></li>', myPage, re.S)
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

這裡寫圖片描述
  根據網頁原始碼,可得出其正則表示式為

staData = re.findall('<li><a href=.*?>(.*?)</a><span>(.*?)</span></li>', myPage, re.S)

for i in staData:
    print(i[0] + ':' + i[1].lstrip('(').rstrip(')')+'篇')
  
  • 1
  • 2
  • 3
  • 4

  經過以上操作,得到的使用者Blog資訊如下圖所示:
這裡寫圖片描述
  最終遇到的問題是:有關粉絲數的爬取遇到了問題,因為前面資料資訊的獲取不需要使用者登入,而使用者粉絲數是在使用者已登入情景下獲取的,故需要將使用者登入資訊新增進去。犯愁~
  PS:論文盲審送回來了,自己這段時間要用來修改論文了,後面的部落格後面再說吧~

注意事項

  • urllib2在3.5中為urllib.request;
  • raw_input()在3.5中為input();
  • python3中urllib.read()返回的是bytes物件,不是string,得把它轉換成string物件,用bytes.decode()方法;
  • re.S意在使.匹配包括換行在內的所有字元;
  • python3對urllib和urllib2進行了重構,拆分成了urllib.request, urllib.response,urllib.parse,urllib.error等幾個子模組,這樣的架構從邏輯和結構上說更加合理。urljoin現在對應的函式是urllib.parse.urljoin

  注:Python2部分的爬蟲程式碼為網路獲取,在此向匿名人士表示感謝。

這裡寫圖片描述
這裡寫圖片描述

給我偶像的人工智慧教程打call!http://blog.csdn.net/jiangjunshow