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
二.獲取標題
右鍵檢視網頁的原始碼,我們看到可以找到這樣一段程式碼:
我們可以看到標題都是在標籤
<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