本身寫了一個爬蟲爬取豆瓣小說,後來爲了應對請求不到數據,增長了請求的頭部信息headers,爲了應對豆瓣服務器的反爬蟲機制:防止請求頻率過快而形成「403 forbidden」,乃至封禁本機ip的狀況,而設置了代理ip,詳細請見代碼和註釋。html
爬取豆瓣小說的連接:https://www.douban.com/tag/%E5%B0%8F%E8%AF%B4/book?start=0瀏覽器
獲取免費代理ip的網站:http://www.xicidaili.com/服務器
1 #-*-coding:utf-8-*- 2 import urllib2 3 from bs4 import BeautifulSoup 4 import time 5 import random 6 7 class dbxs: 8 9 def __init__(self): 10 self.pageIndex = 0 11 self.enable = True 12 13 14 #獲取html頁面的內容 15 def getPage(self, pageIndex): 16 try: 17 #設置代理ip 18 enable_proxy = True 19 #Openers使用處理器Handlers,全部的「繁重」工做由Handlers處理,每一個handlers知道如何經過特定協議打開URLs,或者如何處理URL打開時的各個方面 20 #在你使用代理上網或其餘的狀況就須要本身建立一個opener,能夠實例化一個OpenerDirector,而後調用.add_handler(some_handler_instance) 21 #也可以使用build_opener,這是一個更加方便的函數,用來建立opener對象,它只須要一次函數調用 22 proxy_handler = urllib2.ProxyHandler({'Http': '113.118.170.230:808'}) 23 null_proxy_handler = urllib2.ProxyHandler({}) 24 if enable_proxy: 25 #當你獲取一個URL你要使用一個opener,默認狀況下opener是urlopen,但urllib2.urlopen()不支持驗證、cookie或者其餘Http高級功能 26 #要支持這些功能,必須使用build_opener()建立自定義opener對象,build_opener([handler1 [handler2,...]]),參數handler是Handlers的實例,經常使用的有HTTPBasicAuthHandler、HTTPCookieProcessor、ProxyHandler 27 opener = urllib2.build_opener(proxy_handler) 28 else: 29 opener = urllib2.build_opener(null_proxy_handler) 30 urllib2.install_opener(opener) #install_opener用來建立(全局)默認opener,這個表示調用urlopen將使用你安裝的opener 31 #得到頁面響應的內容 32 url = 'https://www.douban.com/tag/%E5%B0%8F%E8%AF%B4/book' + "?start=" + str(pageIndex) 33 #設置請求頭部信息,模擬瀏覽器的行爲 34 my_headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:55.0)'} 35 request = urllib2.Request(url, headers = my_headers) 36 response = urllib2.urlopen(request) 37 return response.read() 38 39 #另一種隨機設置請求頭部信息的方法 40 #my_headers =['Mozilla/5.0 (Windows NT 6.1; WOW64; rv:55.0)', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64)', 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0)'] 41 #header = random.choice(my_headers) #random.choice()能夠從任何序列,好比list列表中,選取一個隨機的元素返回,能夠用於字符串、列表、元組 42 #request = urllib2.Request(url, headers = {'User-Agent': header}) 43 except urllib2.URLError, e: 44 if hasattr(e, "code"): 45 print e.code 46 if hasattr(e, "reason"): 47 print e.reason 48 return None 49 50 #過濾查找這一頁的小說名字,信息和評分 51 def getContent(self, pageIndex): 52 pageCode = self.getPage(pageIndex) 53 soup = BeautifulSoup(pageCode, 'html.parser') 54 #在得到相應的內容中找出全部標籤爲<dd>的內容(裏面包含了咱們須要的小說信息) 55 contents = soup.find_all('dd') 56 #若是contents爲真,可以獲取到包含<dd>標籤的內容,什麼狀況獲取不到?咱們發現豆瓣小說21頁以後的全部頁面裏都不包含<dd>標籤,咱們應該中止打印 57 if contents: 58 #item爲包含小說信息的每一頁的內容 59 for item in contents: 60 title = item.find(class_ = 'title').string 61 info = item.find(class_ = 'desc').string.strip() 62 rate = item.find(class_ = 'rating_nums') 63 #經過試驗,咱們發現某一頁可能存在小說沒有評分,若是咱們不判斷rate,那麼可能就出現報錯 64 if rate: 65 rates = rate.string 66 print u"%s\n%s\n評分:%s\n" %(title, info, rates) 67 #對於小說沒有評分的內容,咱們只打印小說名字,信息 68 else: 69 print u"%s\n%s\n" %(title, info) 70 #若是頁面不包含<dd>標籤,咱們應該中止 71 else: 72 print u"全部頁面已加載完" 73 self.enable = False 74 75 return contents 76 77 78 #建立一個開始方法 79 def start(self): 80 #打印第一頁,此時self.pageIndex = 0,初始化時設置了 81 #設置頁碼x = 1 82 x = 1 83 #咱們觀察發現,第二頁的pageIndex - 第一頁的 = 第一頁的小說的個數 84 #咱們執行self.getContent的同時,獲取了第一頁的小說的個數 85 page_num = len(self.getContent(self.pageIndex)) 86 print u"第%s頁" %x 87 88 #利用self.enable控制下一頁的打印 89 while self.enable == True: 90 #設置下一頁的pageIndex 91 self.pageIndex += page_num 92 #頁碼+1 93 x += 1 94 #time.sleep(1) #能夠利用time模塊來設置sleep時間 95 #再次調用self.getContent的同時,獲取當前頁的小說的個數 96 page_num = len(self.getContent(self.pageIndex)) 97 #在self.getContent中,若是不能獲取到<dd>的內容,self.enable將會改成False,若是咱們不加self.enable判斷,仍會打印不存在小說信息的頁碼
if self.enable == True:
99 print u"第%s頁" %x 100 101 102 DBXS = dbxs() 103 DBXS.start()