大家好,前面入門已經說了那么多基礎知識了,下面我們做幾個實戰項目來挑戰一下吧。那么這次為大家帶來,Python爬取糗事百科的小段子的例子。
首先,糗事百科大家都聽說過吧?糗友們發的搞笑的段子一抓一大把,這次我們嘗試一下用爬蟲把他們抓取下來。
## 本篇目標
> 1.抓取糗事百科熱門段子
>
> 2.過濾帶有圖片的段子
>
> 3.實現每按一次回車顯示一個段子的發布時間,發布人,段子內容,點贊數。
糗事百科是不需要登錄的,所以也沒必要用到Cookie,另外糗事百科有的段子是附圖的,我們把圖抓下來圖片不便于顯示,那么我們就嘗試過濾掉有圖的段子吧。
好,現在我們嘗試抓取一下糗事百科的熱門段子吧,每按下一次回車我們顯示一個段子。
## 1.確定URL并抓取頁面代碼
首先我們確定好頁面的URL是 http://www.qiushibaike.com/hot/page/1,其中最后一個數字1代表頁數,我們可以傳入不同的值來獲得某一頁的段子內容。
我們初步構建如下的代碼來打印頁面代碼內容試試看,先構造最基本的頁面抓取方式,看看會不會成功
~~~
# -*- coding:utf-8 -*-
import urllib
import urllib2
page = 1
url = 'http://www.qiushibaike.com/hot/page/' + str(page)
try:
????request = urllib2.Request(url)
????response = urllib2.urlopen(request)
????print response.read()
except urllib2.URLError, e:
????if hasattr(e,"code"):
????????print e.code
????if hasattr(e,"reason"):
????????print e.reason
~~~
運行程序,哦不,它竟然報錯了,真是時運不濟,命途多舛啊
~~~
line 373, in _read_status
raise BadStatusLine(line)
httplib.BadStatusLine: ''
~~~
好吧,應該是headers驗證的問題,我們加上一個headers驗證試試看吧,將代碼修改如下
~~~
# -*- coding:utf-8 -*-
import urllib
import urllib2
page = 1
url = 'http://www.qiushibaike.com/hot/page/' + str(page)
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
headers = { 'User-Agent' : user_agent }
try:
????request = urllib2.Request(url,headers = headers)
????response = urllib2.urlopen(request)
????print response.read()
except urllib2.URLError, e:
????if hasattr(e,"code"):
????????print e.code
????if hasattr(e,"reason"):
????????print e.reason
~~~
嘿嘿,這次運行終于正常了,打印出了第一頁的HTML代碼,大家可以運行下代碼試試看。在這里運行結果太長就不貼了。
## 2.提取某一頁的所有段子
好,獲取了HTML代碼之后,我們開始分析怎樣獲取某一頁的所有段子。
首先我們審查元素看一下,按瀏覽器的F12,截圖如下
[]
我們可以看到,每一個段子都是…包裹的內容。
現在我們想獲取發布人,發布日期,段子內容,以及點贊的個數。不過另外注意的是,段子有些是帶圖片的,如果我們想在控制臺顯示圖片是不現實的,所以我們直接把帶有圖片的段子給它剔除掉,只保存僅含文本的段子。
所以我們加入如下正則表達式來匹配一下,用到的方法是 re.findall 是找尋所有匹配的內容。方法的用法詳情可以看前面說的正則表達式的介紹。
好,我們的正則表達式匹配語句書寫如下,在原來的基礎上追加如下代碼
~~~
content = response.read().decode('utf-8')
pattern = re.compile('.*?.*?(.*?).*?+
???????????????????? '="content".*?title="(.*?)">(.*?)(.*?)(.*?)',re.S)
items = re.findall(pattern,content)
for item in items:
????print item[0],item[1],item[2],item[3],item[4]
~~~
現在正則表達式在這里稍作說明
1).*? 是一個固定的搭配,.和*代表可以匹配任意無限多個字符,加上?表示使用非貪婪模式進行匹配,也就是我們會盡可能短地做匹配,以后我們還會大量用到 .*? 的搭配。
2)(.*?)代表一個分組,在這個正則表達式中我們匹配了五個分組,在后面的遍歷item中,item[0]就代表第一個(.*?)所指代的內容,item[1]就代表第二個(.*?)所指代的內容,以此類推。
3)re.S 標志代表在匹配時為點任意匹配模式,點 . 也可以代表換行符。
現在我們可以看一下部分運行結果
> 儒雅男神 2015-02-17 14:34:42
>
> 小時候一個一個拆著放的舉個爪…
>
>
>
>
>
>
>
>
>
> 7093
> 奇怪的名字啊 2015-02-17 14:49:16
>
> 回家的路,你追我趕,回家的心情和窗外的陽光一樣燦爛。一路向前,離親人越來越近了。哪里有爸媽哪里才是家,希望所有糗友的爸爸媽媽都身體健康…….
>
> 4803
這是其中的兩個段子,分別打印了發布人,發布時間,發布內容,附加圖片以及點贊數。
其中,附加圖片的內容我把圖片代碼整體摳了出來,這個對應item[3],所以我們只需要進一步判斷item[3]里面是否含有img這個字樣就可以進行過濾了。
好,我們再把上述代碼中的for循環改為下面的樣子
~~~
for item in items:
????????haveImg = re.search("img",item[3])
????????if not haveImg:
????????????print item[0],item[1],item[2],item[4]
~~~
現在,整體的代碼如下
~~~
# -*- coding:utf-8 -*-
import urllib
import urllib2
import re
page = 1
url = 'http://www.qiushibaike.com/hot/page/' + str(page)
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
headers = { 'User-Agent' : user_agent }
try:
????request = urllib2.Request(url,headers = headers)
????response = urllib2.urlopen(request)
????content = response.read().decode('utf-8')
????pattern = re.compile('.*?.*?(.*?).*?+
???????????????????????? '="content".*?title="(.*?)">(.*?)(.*?)(.*?)',re.S)
????items = re.findall(pattern,content)
????for item in items:
????????haveImg = re.search("img",item[3])
????????if not haveImg:
????????????print item[0],item[1],item[2],item[4]
except urllib2.URLError, e:
????if hasattr(e,"code"):
????????print e.code
????if hasattr(e,"reason"):
????????print e.reason
~~~
運行一下看下效果

恩,帶有圖片的段子已經被剔除啦。是不是很開森?
## 3.完善交互,設計面向對象模式
好啦,現在最核心的部分我們已經完成啦,剩下的就是修一下邊邊角角的東西,我們想達到的目的是:
按下回車,讀取一個段子,顯示出段子的發布人,發布日期,內容以及點贊個數。
另外我們需要[設計]面向對象模式,引入類和方法,將代碼做一下優化和封裝,最后,我們的代碼如下所示
~~~
__author__ = 'CQC'
# -*- coding:utf-8 -*-
import urllib
import urllib2
import re
import thread
import time
#糗事百科爬蟲類
class QSBK:
????#初始化方法,定義一些變量
????def __init__(self):
????????self.pageIndex = 1
????????self.user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
????????#初始化headers
????????self.headers = { 'User-Agent' : self.user_agent }
????????#存放段子的變量,每一個元素是每一頁的段子們
????????self.stories = []
????????#存放程序是否繼續運行的變量
????????self.enable = False
????#傳入某一頁的索引獲得頁面代碼
????def getPage(self,pageIndex):
????????try:
????????????url = 'http://www.qiushibaike.com/hot/page/' + str(pageIndex)
????????????#構建請求的request
????????????request = urllib2.Request(url,headers = self.headers)
????????????#利用urlopen獲取頁面代碼
????????????response = urllib2.urlopen(request)
????????????#將頁面轉化為UTF-8編碼
????????????pageCode = response.read().decode('utf-8')
????????????return pageCode
????????except urllib2.URLError, e:
????????????if hasattr(e,"reason"):
????????????????print u"連接糗事百科失敗,錯誤原因",e.reason
????????????????return None
????#傳入某一頁代碼,返回本頁不帶圖片的段子列表
????def getPageItems(self,pageIndex):
????????pageCode = self.getPage(pageIndex)
????????if not pageCode:
????????????print "頁面加載失敗...."
????????????return None
????????pattern = re.compile('.*?.*?(.*?).*?+
???????????????????????? '="content".*?title="(.*?)">(.*?)(.*?)(.*?)',re.S)
????????items = re.findall(pattern,pageCode)
????????#用來存儲每頁的段子們
????????pageStories = []
????????#遍歷正則表達式匹配的信息
????????for item in items:
????????????#是否含有圖片
????????????haveImg = re.search("img",item[3])
????????????#如果不含有圖片,把它加入list中
????????????if not haveImg:
????????????????#item[0]是一個段子的發布者,item[1]是發布時間,item[2]是內容,item[4]是點贊數
????????????????pageStories.append([item[0].strip(),item[1].strip(),item[2].strip(),item[4].strip()])
????????return pageStories
????#加載并提取頁面的內容,加入到列表中
????def loadPage(self):
????????#如果當前未看的頁數少于2頁,則加載新一頁
????????if self.enable == True:
????????????if len(self.stories) 2:
????????????????#獲取新一頁
????????????????pageStories = self.getPageItems(self.pageIndex)
????????????????#將該頁的段子存放到全局list中
????????????????if pageStories:
????????????????????self.stories.append(pageStories)
????????????????????#獲取完之后頁碼索引加一,表示下次讀取下一頁
????????????????????self.pageIndex += 1
????#調用該方法,每次敲回車打印輸出一個段子
????def getOneStory(self,pageStories,page):
????????#遍歷一頁的段子
????????for story in pageStories:
????????????#等待用戶輸入
????????????input = raw_input()
????????????#每當輸入回車一次,判斷一下是否要加載新頁面
????????????self.loadPage()
????????????#如果輸入Q則程序結束
????????????if input == "Q":
????????????????self.enable = False
????????????????return
????????????print u"第%d頁\t發布人:%s\t發布時間:%s\n%s\n贊:%s\n" %(page,story[0],story[1],story[2],story[3])
????#開始方法
????def start(self):
????????print u"正在讀取糗事百科,按回車查看新段子,Q退出"
????????#使變量為True,程序可以正常運行
????????self.enable = True
????????#先加載一頁內容
????????self.loadPage()
????????#局部變量,控制當前讀到了第幾頁
????????nowPage = 0
????????while self.enable:
????????????if len(self.stories)>0:
????????????????#從全局list中獲取一頁的段子
????????????????pageStories = self.stories[0]
????????????????#當前讀到的頁數加一
????????????????nowPage += 1
????????????????#將全局list中第一個元素刪除,因為已經取出
????????????????del self.stories[0]
????????????????#輸出該頁的段子
????????????????self.getOneStory(pageStories,nowPage)
spider = QSBK()
spider.start()
~~~
好啦,大家來測試一下吧,點一下回車會輸出一個段子,包括發布人,發布時間,段子內容以及點贊數,是不是感覺爽爆了!
我們第一個爬蟲實戰項目介紹到這里,歡迎大家繼續關注,小伙伴們加油!
- Python爬蟲入門
- (1):綜述
- (2):爬蟲基礎了解
- (3):Urllib庫的基本使用
- (4):Urllib庫的高級用法
- (5):URLError異常處理
- (6):Cookie的使用
- (7):正則表達式
- (8):Beautiful Soup的用法
- Python爬蟲進階
- Python爬蟲進階一之爬蟲框架概述
- Python爬蟲進階二之PySpider框架安裝配置
- Python爬蟲進階三之Scrapy框架安裝配置
- Python爬蟲進階四之PySpider的用法
- Python爬蟲實戰
- Python爬蟲實戰(1):爬取糗事百科段子
- Python爬蟲實戰(2):百度貼吧帖子
- Python爬蟲實戰(3):計算大學本學期績點
- Python爬蟲實戰(4):模擬登錄淘寶并獲取所有訂單
- Python爬蟲實戰(5):抓取淘寶MM照片
- Python爬蟲實戰(6):抓取愛問知識人問題并保存至數據庫
- Python爬蟲利器
- Python爬蟲文章
- Python爬蟲(一)--豆瓣電影抓站小結(成功抓取Top100電影)
- Python爬蟲(二)--Coursera抓站小結
- Python爬蟲(三)-Socket網絡編程
- Python爬蟲(四)--多線程
- Python爬蟲(五)--多線程續(Queue)
- Python爬蟲(六)--Scrapy框架學習
- Python爬蟲(七)--Scrapy模擬登錄
- Python筆記
- python 知乎爬蟲
- Python 爬蟲之——模擬登陸
- python的urllib2 模塊解析
- 蜘蛛項目要用的數據庫操作
- gzip 壓縮格式的網站處理方法
- 通過瀏覽器的調試得出 headers轉換成字典
- Python登錄到weibo.com
- weibo v1.4.5 支持 RSA協議(模擬微博登錄)
- 搭建Scrapy爬蟲的開發環境
- 知乎精華回答的非專業大數據統計
- 基于PySpider的weibo.cn爬蟲
- Python-實現批量抓取妹子圖片
- Python庫
- python數據庫-mysql
- 圖片處理庫PIL
- Mac OS X安裝 Scrapy、PIL、BeautifulSoup
- 正則表達式 re模塊
- 郵件正則
- 正則匹配,但過濾某些字符串
- dict使用方法和快捷查找
- httplib2 庫的使用