Python爬蟲之利用BeautifulSoup爬取豆瓣小說(一)——設置代理IP

本身寫了一個爬蟲爬取豆瓣小說,後來爲了應對請求不到數據,增長了請求的頭部信息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()
相關文章
相關標籤/搜索