標籤:爬蟲 python爬蟲 csdn部落格 Regex urllib2
Python爬蟲Csdn系列II
By 白熊花田(http://blog.csdn.net/whiterbear) 轉載需註明出處,謝謝。
說明:
在上一篇文章中,我們已經知道了只要將程式偽裝成瀏覽器就能訪問csdn網頁。在這篇文章中,我們將設法擷取某個csdn使用者的所有文章的連結。
分析:
開啟一個某一個的csdn使用者的的專欄,可以選擇目錄檢視(如:http://blog.csdn.net/whiterbear?viewmode=contents)和摘要視圖(比如:http://blog.csdn.net/whiterbear?viewmode=list)。兩個視圖都可以顯示使用者的文章列表。
注意:這裡我們選擇摘要視圖,不要選擇目錄檢視,文章最後會解釋為什麼。
開啟摘要視圖查看網頁原始碼,我們發現,在id為’article_list’的div中,每一個子div都代表著一篇文章,
每一個子div中都包含一篇文章的標題,連結,閱讀次數,是否為原創,評論數等資訊,我們只需要取出標題和連結就夠了。如何取出不難,學過Regex應該都會。我們再使用個數組將介面中所有的文章名及其連結儲存即可。
這裡需要注意的是,如果部落格有分頁怎麼辦,我們還需要擷取分頁的下一頁中的文章的連結?
我嘗試了兩種方法,第一種方法是設定一個article_list字典,字典成員為‘下一頁連結和是否已經被訪問標識鍵值對’,初始放入首頁連結,每處理一個介面時將該連結的值設為訪問,之後尋找下一頁的連結,如果其不在字典裡,就將其加入並設訪問標識為0。
比如初始字典為article_list={‘/pongba/article/list/1’:False},在處理/pongba/article/list/1這個介面時設值為True,此時又發現了/pongba/article/list/2和/pongba/article/list/3。此時,我們判斷字典(has_key())中是沒有這兩個鍵的,就加入,並設其值為False。之後遍曆(keys())字典,如果有值為0的連結,則訪問該連結,重複。
第二種方法:在分頁的html代碼中給出了分頁的頁數,我們提取出頁數pagenum,結合/pongba/article/list/num,num為頁數,值為[1,pagenum]。通過這個連結即可取出該作者的所有文章了。
我代碼中採用了第二種方法,第一種方法試了,也可以。
代碼介紹:
CsdnArticle類(article.py),封裝成一篇文章必須的東西,便於儲存和訪問一個文章的屬性。
我重寫了__str__()方法,便於輸入。
#-*- coding:utf-8 -*-class CsdnArticle(object):def __init__(self):#作者self.author = ''#部落格文章名self.title = ''#部落格連結self.href = ''#部落格內容self.body = ''#字串化def __str__(self):return self.author + '\t' + self.title + '\t' + self.href + '\t' + self.body
CsdnCrawler類。封裝了爬取csdn部落格所有連結的操作。
#-*- coding:utf-8 -*-import sysimport urllibimport urllib2import refrom bs4 import BeautifulSoupfrom article import CsdnArticlereload(sys)sys.setdefaultencoding('utf-8')class CsdnCrawler(object):#預設訪問我的部落格def __init__(self, author = 'whiterbear'):self.author = authorself.domain = 'http://blog.csdn.net/'self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36'}#儲存文章對象數組self.articles = []#給定url,得到所有的文章listsdef getArticleLists(self, url= None):req = urllib2.Request(url, headers=self.headers)response = urllib2.urlopen(req)soup = BeautifulSoup(''.join(response.read()))listitem = soup.find(id='article_list').find_all(attrs={'class':r'list_item article_item'})#連結的Regex,可以匹配連結href_regex = r'href="(.*?)"'for i,item in enumerate(listitem):enitem = item.find(attrs={'class':'link_title'}).contents[0].contents[0]href = re.search(href_regex,str(item.find(attrs={'class':'link_title'}).contents[0])).group(1)#我們將擷取的一篇文章資訊封裝成一個對象,然後存入數組中art = CsdnArticle()art.author = self.authorart.title = enitem.lstrip()art.href = (self.domain + href[1:]).lstrip()self.articles.append(art)def getPageLists(self, url= None):url = 'http://blog.csdn.net/%s?viewmode=list'%self.authorreq = urllib2.Request(url, headers=self.headers)response = urllib2.urlopen(req)soup = BeautifulSoup(''.join(response.read()))num_regex = '[1-9]\d*'pagelist = soup.find(id='papelist')self.getArticleLists(url)#如果該作者部落格多,有分頁的話if pagelist:pagenum = int(re.findall(num_regex, pagelist.contents[1].contents[0])[1])for i in range(2, pagenum + 1):self.getArticleLists(self.domain + self.author + '/article/list/%s'%i)def mytest(self):for i,url in enumerate(self.articles):print i,urldef main():#可以將pongba換成你的部落格名,也可以不填,為空白,這樣預設是訪問我的部落格csdn = CsdnCrawler(author='pongba')#'pongba'csdn.getPageLists()csdn.mytest()if __name__ == '__main__':main()<span style="font-family:Verdana;font-size:18px;"></span>
結果:
輸出了126條資料。
選擇摘要視圖的解釋:當某使用者文章多有分頁時,訪問目錄檢視介面中的下一頁連結時會跳轉到摘要視圖的下一頁連結中。我這麼說你可能不太明白,舉個例子吧。
我使用劉未鵬學長(我崇拜的)的部落格為例子吧,地址:http://blog.csdn.net/pongba。他的文章很多,有分頁。選擇他介面中的目錄檢視後,翻到分頁連結出。如:
其中的分頁連結值為:
可以看出下一頁的連結為:http://blog.csdn.net +/pongba/article/list/2.
當我們在瀏覽器輸入這個網址斷行符號後是出現這個結果的:
可以看到第一篇文章為“斯托克代爾悖論與底線思考法”
然而,當我們使用程式開啟的結果卻是:
而這個結果卻和摘要視圖的第二頁結果一樣:
所以,如果你試圖用程式使用http://blog.csdn.net/pongba/article/list/2這個連結訪問,得到的結果卻並不是目錄檢視的結果。我沒能理解為什麼,糾結了好久程式為什麼出錯了,後來換成摘要視圖了。
未完待續。
Python爬蟲Csdn系列II